get-claudia 1.55.18 → 1.55.19

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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  All notable changes to Claudia will be documented in this file.
4
4
 
5
+ ## 1.55.19 (2026-03-19)
6
+
7
+ ### The Self-Healer
8
+
9
+ Bulletproof installer for non-technical users. Existing installs auto-fix on the next `npx get-claudia`.
10
+
11
+ - **Auto-rebuild Python 3.14 venvs** -- If your existing venv uses Python 3.14+ and a compatible Python (3.13/3.12/3.11) is available, the installer automatically rebuilds the venv. No user action needed.
12
+ - **Auto-install Python 3.12** -- On macOS with Homebrew, if only Python 3.14 exists, the installer runs `brew install python@3.12` automatically before creating the venv.
13
+ - **LaunchAgent verification** -- After registering the macOS LaunchAgent, the installer now verifies the standalone daemon is actually running via `launchctl list`. If not running, force-reloads the agent. On Linux, enables and starts the systemd user service. Fixes the silent failure where backups, consolidation, and decay never ran.
14
+ - **Clear degradation messaging** -- When falling back to Python 3.14+ (no compatible version available), the installer now shows a yellow warning explaining that spaCy is unavailable and entity extraction will use regex only.
15
+
5
16
  ## 1.55.18 (2026-03-19)
6
17
 
7
18
  ### Data Quality & Python Compatibility
package/bin/index.js CHANGED
@@ -914,10 +914,74 @@ async function main() {
914
914
  if (!supportsInPlace) renderer.appendLine('daemon', 'warn', 'Python 3.10+ not found');
915
915
  rootCause = { step: 'daemon', issue: 'python' };
916
916
  } else {
917
- // Phase 2: Create venv if it doesn't exist
917
+ // Phase 2: Create venv (or rebuild if using Python 3.14)
918
+ if (existsSync(venvPython)) {
919
+ // Self-heal: check if existing venv uses Python 3.14+
920
+ const venvVer = await new Promise((resolve) => {
921
+ const proc = spawn(venvPython, ['-c', 'import sys; print(sys.version_info.minor)'], {
922
+ stdio: 'pipe', timeout: 5000
923
+ });
924
+ let out = '';
925
+ proc.stdout.on('data', (d) => { out += d.toString(); });
926
+ proc.on('close', () => resolve(out.trim()));
927
+ proc.on('error', () => resolve(''));
928
+ });
929
+ if (venvVer && parseInt(venvVer) >= 14 && pythonCmd !== venvPython) {
930
+ // Check if pythonCmd is < 3.14
931
+ const sysVer = await new Promise((resolve) => {
932
+ const proc = spawn(pythonCmd, ['-c', 'import sys; print(sys.version_info.minor)'], {
933
+ stdio: 'pipe', timeout: 5000
934
+ });
935
+ let out = '';
936
+ proc.stdout.on('data', (d) => { out += d.toString(); });
937
+ proc.on('close', () => resolve(out.trim()));
938
+ proc.on('error', () => resolve(''));
939
+ });
940
+ if (sysVer && parseInt(sysVer) < 14) {
941
+ renderer.update('daemon', 'active', `rebuilding venv (3.14→3.${sysVer})...`);
942
+ // Rebuild venv with better Python
943
+ await new Promise((resolve) => {
944
+ const proc = spawn(pythonCmd, ['-m', 'venv', '--clear', daemonVenvDir], {
945
+ stdio: 'pipe', timeout: 30000
946
+ });
947
+ proc.on('close', (code) => resolve(code === 0));
948
+ proc.on('error', () => resolve(false));
949
+ });
950
+ }
951
+ }
952
+ }
953
+
918
954
  if (!existsSync(venvPython)) {
919
955
  renderer.update('daemon', 'active', 'creating venv...');
920
956
  mkdirSync(join(homedir(), '.claudia', 'daemon'), { recursive: true });
957
+
958
+ // If pythonCmd is 3.14+ and we're on macOS with Homebrew, auto-install 3.12
959
+ if (process.platform === 'darwin') {
960
+ const cmdVer = await new Promise((resolve) => {
961
+ const proc = spawn(pythonCmd, ['-c', 'import sys; print(sys.version_info.minor)'], {
962
+ stdio: 'pipe', timeout: 5000
963
+ });
964
+ let out = '';
965
+ proc.stdout.on('data', (d) => { out += d.toString(); });
966
+ proc.on('close', () => resolve(out.trim()));
967
+ proc.on('error', () => resolve(''));
968
+ });
969
+ if (cmdVer && parseInt(cmdVer) >= 14) {
970
+ renderer.update('daemon', 'active', 'installing Python 3.12...');
971
+ const installed312 = await new Promise((resolve) => {
972
+ const proc = spawn('brew', ['install', 'python@3.12'], {
973
+ stdio: 'pipe', timeout: 300000
974
+ });
975
+ proc.on('close', (code) => resolve(code === 0));
976
+ proc.on('error', () => resolve(false));
977
+ });
978
+ if (installed312) {
979
+ // Re-detect best Python
980
+ pythonCmd = await isPythonInstalled() || pythonCmd;
981
+ }
982
+ }
983
+ }
984
+
921
985
  const venvCreated = await new Promise((resolve) => {
922
986
  const proc = spawn(pythonCmd, ['-m', 'venv', daemonVenvDir], { stdio: 'pipe' });
923
987
  proc.on('close', (code) => resolve(code === 0));
@@ -1020,9 +1084,54 @@ async function main() {
1020
1084
  }
1021
1085
  }
1022
1086
 
1023
- // Register LaunchAgent for standalone daemon (macOS only)
1087
+ // Register LaunchAgent and verify standalone daemon is running (macOS only)
1024
1088
  if (daemonOk && process.platform === 'darwin') {
1025
1089
  await ensureLaunchAgent(venvPython);
1090
+ // Verify daemon is actually running (self-heal for existing installs)
1091
+ const daemonRunning = await new Promise((resolve) => {
1092
+ const proc = spawn('launchctl', ['list', 'com.claudia.memory'], {
1093
+ stdio: 'pipe', timeout: 5000
1094
+ });
1095
+ let out = '';
1096
+ proc.stdout.on('data', (d) => { out += d.toString(); });
1097
+ proc.on('close', (code) => {
1098
+ // launchctl list returns PID in first column, or "-" if not running
1099
+ const pid = out.trim().split(/\s+/)[0];
1100
+ resolve(code === 0 && pid !== '-' && pid !== '');
1101
+ });
1102
+ proc.on('error', () => resolve(false));
1103
+ });
1104
+ if (!daemonRunning) {
1105
+ // Force reload: unload then load
1106
+ const plistPath = join(homedir(), 'Library', 'LaunchAgents', 'com.claudia.memory.plist');
1107
+ if (existsSync(plistPath)) {
1108
+ await new Promise((resolve) => {
1109
+ const proc = spawn('launchctl', ['unload', plistPath], { stdio: 'pipe', timeout: 5000 });
1110
+ proc.on('close', () => resolve());
1111
+ proc.on('error', () => resolve());
1112
+ });
1113
+ await new Promise((resolve) => {
1114
+ const proc = spawn('launchctl', ['load', plistPath], { stdio: 'pipe', timeout: 5000 });
1115
+ proc.on('close', () => resolve());
1116
+ proc.on('error', () => resolve());
1117
+ });
1118
+ }
1119
+ }
1120
+ }
1121
+
1122
+ // On Linux, verify systemd service is enabled and running
1123
+ if (daemonOk && process.platform === 'linux') {
1124
+ const serviceFile = join(homedir(), '.config', 'systemd', 'user', 'claudia-memory.service');
1125
+ if (existsSync(serviceFile)) {
1126
+ // Enable and start if not running
1127
+ await new Promise((resolve) => {
1128
+ const proc = spawn('systemctl', ['--user', 'enable', '--now', 'claudia-memory'], {
1129
+ stdio: 'pipe', timeout: 10000
1130
+ });
1131
+ proc.on('close', () => resolve());
1132
+ proc.on('error', () => resolve());
1133
+ });
1134
+ }
1026
1135
  }
1027
1136
 
1028
1137
  // MCP Config step: verify .mcp.json is correct and check stdio server count
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "get-claudia",
3
- "version": "1.55.18",
3
+ "version": "1.55.19",
4
4
  "description": "An AI assistant who learns how you work.",
5
5
  "keywords": [
6
6
  "claudia",