@gamaze/hicortex 0.3.7 → 0.3.8

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/dist/init.js CHANGED
@@ -228,6 +228,58 @@ Tell them: "Get a license key at https://hicortex.gamaze.com/ — after purchase
228
228
  (0, node_fs_1.writeFileSync)((0, node_path_1.join)(CC_COMMANDS_DIR, "hicortex-activate.md"), activateContent);
229
229
  console.log(` ✓ Installed /learn and /hicortex-activate commands in ${CC_COMMANDS_DIR}`);
230
230
  }
231
+ /**
232
+ * Detect LLM API key from current shell environment and persist to
233
+ * ~/.hicortex/config.json so the daemon can use it (launchd/systemd
234
+ * don't inherit shell env vars).
235
+ */
236
+ function persistLlmConfig() {
237
+ const configPath = (0, node_path_1.join)(HICORTEX_HOME, "config.json");
238
+ // Read existing config (may have licenseKey)
239
+ let config = {};
240
+ try {
241
+ config = JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
242
+ }
243
+ catch { /* new file */ }
244
+ // Don't overwrite if LLM config already persisted
245
+ if (config.llmApiKey && config.llmBaseUrl) {
246
+ console.log(` ✓ LLM config already in ${configPath}`);
247
+ return;
248
+ }
249
+ // Detect from environment (same priority as resolveLlmConfigForCC)
250
+ const hcKey = process.env.HICORTEX_LLM_API_KEY;
251
+ const hcUrl = process.env.HICORTEX_LLM_BASE_URL;
252
+ const hcModel = process.env.HICORTEX_LLM_MODEL;
253
+ if (hcKey && hcUrl) {
254
+ config.llmApiKey = hcKey;
255
+ config.llmBaseUrl = hcUrl;
256
+ if (hcModel)
257
+ config.llmModel = hcModel;
258
+ }
259
+ else if (process.env.ANTHROPIC_API_KEY) {
260
+ config.llmApiKey = process.env.ANTHROPIC_API_KEY;
261
+ config.llmBaseUrl = process.env.ANTHROPIC_BASE_URL ?? "https://api.anthropic.com";
262
+ config.llmProvider = "anthropic";
263
+ }
264
+ else if (process.env.OPENAI_API_KEY) {
265
+ config.llmApiKey = process.env.OPENAI_API_KEY;
266
+ config.llmBaseUrl = process.env.OPENAI_BASE_URL ?? "https://api.openai.com";
267
+ config.llmProvider = "openai";
268
+ }
269
+ else if (process.env.GOOGLE_API_KEY) {
270
+ config.llmApiKey = process.env.GOOGLE_API_KEY;
271
+ config.llmBaseUrl = "https://generativelanguage.googleapis.com/v1beta";
272
+ config.llmProvider = "google";
273
+ }
274
+ else {
275
+ console.log(" ⚠ No LLM API key found in environment. Server will use Ollama fallback.");
276
+ console.log(" Set ANTHROPIC_API_KEY and re-run init, or edit ~/.hicortex/config.json");
277
+ return;
278
+ }
279
+ (0, node_fs_1.mkdirSync)(HICORTEX_HOME, { recursive: true });
280
+ (0, node_fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2));
281
+ console.log(` ✓ LLM config saved to ${configPath}`);
282
+ }
231
283
  /**
232
284
  * Determine the npm package specifier for the daemon.
233
285
  * Uses tag-based resolution so restarts pick up new versions automatically.
@@ -428,6 +480,8 @@ async function runInit() {
428
480
  }
429
481
  console.log();
430
482
  // Phase 3: Execute
483
+ // Persist LLM config from current environment for the daemon
484
+ persistLlmConfig();
431
485
  // Install daemon if needed
432
486
  if (!d.localServer && !d.remoteServer) {
433
487
  installDaemon();
@@ -179,13 +179,18 @@ async function startServer(options = {}) {
179
179
  console.log(`[hicortex] Initializing database at ${dbPath}`);
180
180
  db = (0, db_js_1.initDb)(dbPath);
181
181
  stateDir = dbPath.replace(/\/hicortex\.db$/, "");
182
- // LLM config
183
- const llmConfig = (0, llm_js_1.resolveLlmConfigForCC)();
182
+ // LLM config: read from config.json first (persisted by init), then env vars
183
+ const savedConfig = readConfigFile(stateDir);
184
+ const llmConfig = (0, llm_js_1.resolveLlmConfigForCC)({
185
+ llmBaseUrl: savedConfig?.llmBaseUrl,
186
+ llmApiKey: savedConfig?.llmApiKey,
187
+ llmModel: savedConfig?.llmModel,
188
+ });
184
189
  llm = new llm_js_1.LlmClient(llmConfig);
185
190
  console.log(`[hicortex] LLM: ${llmConfig.provider}/${llmConfig.model} (reflect: ${llmConfig.reflectModel})`);
186
191
  // License: read from options, config file, or env var
187
192
  const licenseKey = options.licenseKey
188
- ?? readConfigLicenseKey(stateDir)
193
+ ?? savedConfig?.licenseKey
189
194
  ?? process.env.HICORTEX_LICENSE_KEY;
190
195
  (0, license_js_1.validateLicense)(licenseKey, stateDir).catch((err) => console.log(`[hicortex] License validation failed: ${err}`));
191
196
  if (licenseKey) {
@@ -196,6 +201,8 @@ async function startServer(options = {}) {
196
201
  cancelConsolidation = (0, consolidate_js_1.scheduleConsolidation)(db, llm, embedder_js_1.embed, consolidateHour);
197
202
  // Seed lesson on first run
198
203
  await (0, seed_lesson_js_1.injectSeedLesson)(db);
204
+ // Self-heal: fix pinned version in daemon config
205
+ fixDaemonVersionPin();
199
206
  // Stats
200
207
  const stats = (0, db_js_1.getStats)(db, dbPath);
201
208
  console.log(`[hicortex] Ready: ${stats.memories} memories, ${stats.links} links, ` +
@@ -281,20 +288,55 @@ async function startServer(options = {}) {
281
288
  // Helpers
282
289
  // ---------------------------------------------------------------------------
283
290
  /**
284
- * Read license key from ~/.hicortex/config.json.
285
- * Written by /hicortex-activate CC command.
291
+ * Read ~/.hicortex/config.json (persisted by init with LLM and license config).
286
292
  */
287
- function readConfigLicenseKey(stateDir) {
293
+ function readConfigFile(stateDir) {
288
294
  try {
289
295
  const { readFileSync } = require("node:fs");
290
296
  const { join } = require("node:path");
291
297
  const configPath = join(stateDir, "config.json");
292
- const raw = readFileSync(configPath, "utf-8");
293
- const config = JSON.parse(raw);
294
- return config.licenseKey || undefined;
298
+ return JSON.parse(readFileSync(configPath, "utf-8"));
299
+ }
300
+ catch {
301
+ return null;
302
+ }
303
+ }
304
+ /**
305
+ * Self-heal: if the daemon plist/systemd unit has a pinned version
306
+ * (e.g. @gamaze/hicortex@0.3.4), rewrite it to use the bare package
307
+ * name so future restarts pick up the latest version automatically.
308
+ */
309
+ function fixDaemonVersionPin() {
310
+ try {
311
+ const os = require("node:os");
312
+ const fs = require("node:fs");
313
+ const path = require("node:path");
314
+ if (os.platform() === "darwin") {
315
+ const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", "com.gamaze.hicortex.plist");
316
+ if (!fs.existsSync(plistPath))
317
+ return;
318
+ const content = fs.readFileSync(plistPath, "utf-8");
319
+ // Match @gamaze/hicortex@X.Y.Z (pinned to specific version)
320
+ if (/@gamaze\/hicortex@\d+\.\d+\.\d+/.test(content)) {
321
+ const fixed = content.replace(/@gamaze\/hicortex@\d+\.\d+\.\d+/, "@gamaze/hicortex");
322
+ fs.writeFileSync(plistPath, fixed);
323
+ console.log("[hicortex] Fixed daemon config: removed pinned version (will use latest on next restart)");
324
+ }
325
+ }
326
+ else if (os.platform() === "linux") {
327
+ const servicePath = path.join(os.homedir(), ".config", "systemd", "user", "hicortex.service");
328
+ if (!fs.existsSync(servicePath))
329
+ return;
330
+ const content = fs.readFileSync(servicePath, "utf-8");
331
+ if (/@gamaze\/hicortex@\d+\.\d+\.\d+/.test(content)) {
332
+ const fixed = content.replace(/@gamaze\/hicortex@\d+\.\d+\.\d+/, "@gamaze/hicortex");
333
+ fs.writeFileSync(servicePath, fixed);
334
+ console.log("[hicortex] Fixed daemon config: removed pinned version");
335
+ }
336
+ }
295
337
  }
296
338
  catch {
297
- return undefined;
339
+ // Non-fatal
298
340
  }
299
341
  }
300
342
  function formatResults(results) {
@@ -2,7 +2,7 @@
2
2
  "id": "hicortex",
3
3
  "name": "Hicortex — Long-term Memory That Learns",
4
4
  "description": "Your agents remember past decisions, avoid repeated mistakes, and get smarter every day. Nightly reflection generates actionable lessons that automatically update agent behavior.",
5
- "version": "0.3.7",
5
+ "version": "0.3.8",
6
6
  "kind": "lifecycle",
7
7
  "skills": ["./skills/hicortex-memory", "./skills/hicortex-learn", "./skills/hicortex-activate"],
8
8
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gamaze/hicortex",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Human-like memory for self-improving AI agents. Automatic capturing, nightly reflection, and cross-agent learning. Works with Claude Code and OpenClaw.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {