@gamaze/hicortex 0.7.0 → 0.10.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.
Files changed (54) hide show
  1. package/README.md +57 -39
  2. package/dist/claude-md.d.ts +9 -21
  3. package/dist/claude-md.js +9 -241
  4. package/dist/cli.d.ts +3 -2
  5. package/dist/cli.js +29 -11
  6. package/dist/consolidate.js +76 -26
  7. package/dist/db.js +24 -0
  8. package/dist/embedder.d.ts +11 -0
  9. package/dist/embedder.js +27 -0
  10. package/dist/extensions.d.ts +41 -88
  11. package/dist/extensions.js +36 -61
  12. package/dist/features.d.ts +21 -25
  13. package/dist/features.js +47 -83
  14. package/dist/graph.d.ts +1 -1
  15. package/dist/graph.js +13 -7
  16. package/dist/hermes-transcript-reader.d.ts +27 -0
  17. package/dist/hermes-transcript-reader.js +134 -0
  18. package/dist/index.d.ts +16 -4
  19. package/dist/index.js +252 -344
  20. package/dist/init.d.ts +41 -1
  21. package/dist/init.js +545 -190
  22. package/dist/lesson-selection.d.ts +62 -0
  23. package/dist/lesson-selection.js +159 -0
  24. package/dist/lessons-context.d.ts +17 -0
  25. package/dist/lessons-context.js +96 -0
  26. package/dist/llm.d.ts +42 -29
  27. package/dist/llm.js +89 -270
  28. package/dist/mcp-server.d.ts +0 -1
  29. package/dist/mcp-server.js +407 -88
  30. package/dist/nightly.d.ts +9 -6
  31. package/dist/nightly.js +197 -357
  32. package/dist/oc-transcript-reader.d.ts +20 -0
  33. package/dist/oc-transcript-reader.js +61 -0
  34. package/dist/pi-transcript-reader.d.ts +1 -0
  35. package/dist/prompts.d.ts +5 -0
  36. package/dist/prompts.js +29 -0
  37. package/dist/status.js +22 -2
  38. package/dist/storage.d.ts +7 -1
  39. package/dist/storage.js +28 -7
  40. package/dist/transcript-reader.d.ts +19 -0
  41. package/dist/transcript-reader.js +17 -3
  42. package/dist/types.d.ts +16 -0
  43. package/dist/types.js +7 -0
  44. package/dist/uninstall.js +31 -1
  45. package/hermes-plugin/hicortex/README.md +77 -0
  46. package/hermes-plugin/hicortex/__init__.py +17 -0
  47. package/hermes-plugin/hicortex/client.py +162 -0
  48. package/hermes-plugin/hicortex/config.py +105 -0
  49. package/hermes-plugin/hicortex/plugin.yaml +12 -0
  50. package/hermes-plugin/hicortex/provider.py +432 -0
  51. package/openclaw.plugin.json +17 -44
  52. package/package.json +7 -5
  53. package/dist/pro-loader.d.ts +0 -33
  54. package/dist/pro-loader.js +0 -187
@@ -0,0 +1,432 @@
1
+ """Hicortex MemoryProvider for Hermes — recall-only.
2
+
3
+ Recall: prefetch() -> GET /search (relevant memories before each turn)
4
+ queue_prefetch() -> GET /search (background recall for the next turn)
5
+ tools -> hicortex_search / hicortex_recall_recent
6
+ system_prompt_block -> lessons + memory index injected into the prompt
7
+
8
+ Capture is NOT the plugin's job. A nightly reader on the Hicortex server
9
+ distills each agent's own session store (Hermes: ~/.hermes/profiles/<agent>/
10
+ state.db) centrally — see specs/2026-07-01-memory-capture-architecture.md. This
11
+ plugin has no local LLM, no spool, no timer, and no capture path.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import hashlib
17
+ import json
18
+ import logging
19
+ import threading
20
+ from typing import Any, Dict, List, Optional
21
+
22
+ from agent.memory_provider import MemoryProvider
23
+
24
+ from .client import HicortexClient
25
+ from .config import CONFIG_SCHEMA, load_config
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ _INJECT_CONTENT_CAP = 500
30
+
31
+
32
+ class HicortexProvider(MemoryProvider):
33
+ """Hicortex long-term memory backend for Hermes (recall-only)."""
34
+
35
+ def __init__(self):
36
+ self._client: Optional[HicortexClient] = None
37
+ self._project: Optional[str] = None
38
+ self._recall_limit: int = 5
39
+ self._privacy: Optional[str] = "WORK,PERSONAL"
40
+ self._prefetch_cache: Dict[str, str] = {}
41
+ self._bg_threads: List[threading.Thread] = []
42
+
43
+ @property
44
+ def name(self) -> str:
45
+ return "hicortex"
46
+
47
+ # ------------------------------------------------------------------ config
48
+ def _build_client(self) -> Optional[HicortexClient]:
49
+ cfg = load_config()
50
+ url = cfg.get("hicortex_url")
51
+ if not url:
52
+ return None
53
+ token = cfg.get("hicortex_auth_token")
54
+ return HicortexClient(url, auth_token=token or None)
55
+
56
+ def _client_or_none(self) -> Optional[HicortexClient]:
57
+ if self._client is None:
58
+ try:
59
+ self._client = self._build_client()
60
+ except Exception as e:
61
+ logger.warning("hicortex: failed to build client: %s", e)
62
+ return self._client
63
+
64
+ def is_available(self) -> bool:
65
+ """Configured and ready — NO network call (per MemoryProvider contract).
66
+
67
+ ``is_available`` runs at agent init to decide whether to activate this
68
+ provider. Pinging the server here would mean a slow or momentarily-down
69
+ server silently disables memory for the whole session. Per the contract
70
+ ("should not make network calls — just check config and installed deps")
71
+ we only verify a server URL is configured; per-request failures are
72
+ handled at use time.
73
+ """
74
+ return self._build_client() is not None
75
+
76
+ def initialize(self, session_id: str, **kwargs) -> None:
77
+ cfg = load_config()
78
+ self._project = cfg.get("default_project") or None
79
+ try:
80
+ self._recall_limit = int(cfg.get("recall_limit", 5))
81
+ except (TypeError, ValueError):
82
+ self._recall_limit = 5
83
+ self._privacy = cfg.get("privacy_filter", "WORK,PERSONAL")
84
+ try:
85
+ self._client = self._build_client()
86
+ except Exception as e:
87
+ logger.warning("hicortex: init client build failed: %s", e)
88
+
89
+ # ------------------------------------------------------------------- recall
90
+ def _format_hits(self, hits: list[dict]) -> str:
91
+ if not hits:
92
+ return ""
93
+ lines = [
94
+ "Relevant prior context from your long-term memory "
95
+ "(verify before relying on these — each shows date and project):"
96
+ ]
97
+ for h in hits[: self._recall_limit]:
98
+ date = (h.get("created_at") or "")[:10]
99
+ proj = h.get("project") or "global"
100
+ content = (h.get("content") or "").strip().replace("\n", " ")
101
+ if len(content) > _INJECT_CONTENT_CAP:
102
+ content = content[:_INJECT_CONTENT_CAP] + "…"
103
+ lines.append(f"- [{date}, {proj}] {content}")
104
+ return "\n".join(lines)
105
+
106
+ def prefetch(self, query: str, *, session_id: str = "") -> str:
107
+ key = hashlib.sha1(query.encode("utf-8")).hexdigest()
108
+ cached = self._prefetch_cache.pop(key, None)
109
+ if cached is not None:
110
+ return cached
111
+ client = self._client_or_none()
112
+ if client is None:
113
+ return ""
114
+ try:
115
+ hits = client.search(
116
+ query, limit=self._recall_limit, project=self._project, privacy=self._privacy
117
+ )
118
+ return self._format_hits(hits)
119
+ except Exception as e:
120
+ logger.debug("hicortex prefetch failed: %s", e)
121
+ return ""
122
+
123
+ def queue_prefetch(self, query: str, *, session_id: str = "") -> None:
124
+ client = self._client_or_none()
125
+ if client is None:
126
+ return
127
+ key = hashlib.sha1(query.encode("utf-8")).hexdigest()
128
+
129
+ def _bg() -> None:
130
+ try:
131
+ hits = client.search(
132
+ query, limit=self._recall_limit, project=self._project, privacy=self._privacy
133
+ )
134
+ self._prefetch_cache[key] = self._format_hits(hits)
135
+ except Exception as e:
136
+ logger.debug("hicortex queue_prefetch failed: %s", e)
137
+
138
+ self._spawn(_bg)
139
+
140
+ # ------------------------------------------------------ system prompt/tools
141
+ def system_prompt_block(self) -> str:
142
+ client = self._client_or_none()
143
+ if client is None:
144
+ return ""
145
+ try:
146
+ data = client.lessons()
147
+ except Exception as e:
148
+ logger.debug("hicortex lessons fetch failed: %s", e)
149
+ return ""
150
+ lessons = (data.get("lessons") or [])[:8]
151
+ idx = data.get("index") or {}
152
+ lines = [
153
+ "## Hicortex long-term memory",
154
+ "You have shared long-term memory across sessions. Use `hicortex_search` "
155
+ "for specific recall and `hicortex_recall_recent` for recent context.",
156
+ ]
157
+ if lessons:
158
+ lines.append("Lessons:")
159
+ for l in lessons:
160
+ c = (l.get("content") or "").strip().replace("\n", " ")
161
+ lines.append(f"- {c[:200]}")
162
+ if idx.get("total"):
163
+ lines.append(
164
+ f"({idx.get('total')} memories, {idx.get('lessonCount')} lessons "
165
+ f"across {idx.get('sourceCount')} agents)"
166
+ )
167
+ return "\n".join(lines)
168
+
169
+ def get_tool_schemas(self) -> List[Dict[str, Any]]:
170
+ return [
171
+ {
172
+ "name": "hicortex_search",
173
+ "description": (
174
+ "Search long-term memory using semantic similarity. Returns the most "
175
+ "relevant memories from past sessions."
176
+ ),
177
+ "parameters": {
178
+ "type": "object",
179
+ "properties": {
180
+ "query": {"type": "string", "description": "Search query text"},
181
+ "limit": {
182
+ "type": "number",
183
+ "description": "Max results (default 5)",
184
+ },
185
+ "project": {"type": "string", "description": "Filter by project name"},
186
+ },
187
+ "required": ["query"],
188
+ },
189
+ },
190
+ {
191
+ "name": "hicortex_recall_recent",
192
+ "description": "Recall recent context memories, optionally filtered by project.",
193
+ "parameters": {
194
+ "type": "object",
195
+ "properties": {
196
+ "project": {"type": "string"},
197
+ "limit": {
198
+ "type": "number",
199
+ "description": "Max results (default 10)",
200
+ },
201
+ },
202
+ },
203
+ },
204
+ {
205
+ "name": "hicortex_context",
206
+ "description": (
207
+ "Get recent context memories, optionally filtered by project. "
208
+ "Useful to recall what happened recently."
209
+ ),
210
+ "parameters": {
211
+ "type": "object",
212
+ "properties": {
213
+ "project": {"type": "string", "description": "Filter by project name"},
214
+ "limit": {"type": "number", "description": "Max results (default 10)"},
215
+ },
216
+ },
217
+ },
218
+ {
219
+ "name": "hicortex_ingest",
220
+ "description": (
221
+ "Store a new memory in long-term storage. "
222
+ "Use for important facts, decisions, or lessons."
223
+ ),
224
+ "parameters": {
225
+ "type": "object",
226
+ "properties": {
227
+ "content": {"type": "string", "description": "Memory content to store"},
228
+ "project": {"type": "string", "description": "Project this memory belongs to"},
229
+ "memory_type": {
230
+ "type": "string",
231
+ "enum": ["episode", "lesson", "fact", "decision"],
232
+ "description": "Type of memory (default: episode)",
233
+ },
234
+ },
235
+ "required": ["content"],
236
+ },
237
+ },
238
+ {
239
+ "name": "hicortex_lessons",
240
+ "description": (
241
+ "Get actionable lessons learned from past sessions. "
242
+ "Auto-generated insights about mistakes to avoid."
243
+ ),
244
+ "parameters": {
245
+ "type": "object",
246
+ "properties": {
247
+ "project": {"type": "string", "description": "Filter by project name"},
248
+ },
249
+ },
250
+ },
251
+ {
252
+ "name": "hicortex_index",
253
+ "description": (
254
+ "Get the knowledge domain index — shows what topics and projects "
255
+ "are stored in memory, grouped by domain."
256
+ ),
257
+ "parameters": {
258
+ "type": "object",
259
+ "properties": {},
260
+ },
261
+ },
262
+ {
263
+ "name": "hicortex_graph",
264
+ "description": (
265
+ "Query the memory knowledge graph — find connected memories, "
266
+ "hub nodes, or paths between memories."
267
+ ),
268
+ "parameters": {
269
+ "type": "object",
270
+ "properties": {
271
+ "operation": {
272
+ "type": "string",
273
+ "enum": ["neighbors", "hubs", "path"],
274
+ "description": "Graph operation to perform",
275
+ },
276
+ "id": {"type": "string", "description": "Memory ID (required for neighbors and path operations)"},
277
+ "target_id": {"type": "string", "description": "Target memory ID (required for path operation)"},
278
+ "limit": {"type": "number", "description": "Max results (default 10)"},
279
+ "domain": {"type": "string", "description": "Filter hubs by domain"},
280
+ "relationship": {
281
+ "type": "string",
282
+ "description": "Filter neighbors by relationship type (e.g., CONTRADICTS, SUPERSEDES, derives)",
283
+ },
284
+ },
285
+ "required": ["operation"],
286
+ },
287
+ },
288
+ {
289
+ "name": "hicortex_update",
290
+ "description": (
291
+ "Update an existing memory. Use after searching to fix incorrect information. "
292
+ "If content changes, the embedding is re-computed."
293
+ ),
294
+ "parameters": {
295
+ "type": "object",
296
+ "properties": {
297
+ "id": {"type": "string", "description": "Memory ID (from search results, first 8 chars or full UUID)"},
298
+ "content": {"type": "string", "description": "New content text"},
299
+ "project": {"type": "string", "description": "New project name"},
300
+ "memory_type": {
301
+ "type": "string",
302
+ "enum": ["episode", "lesson", "fact", "decision"],
303
+ "description": "New memory type",
304
+ },
305
+ },
306
+ "required": ["id"],
307
+ },
308
+ },
309
+ {
310
+ "name": "hicortex_delete",
311
+ "description": (
312
+ "Permanently delete a memory and its links. "
313
+ "Use when a memory is incorrect and should be removed entirely."
314
+ ),
315
+ "parameters": {
316
+ "type": "object",
317
+ "properties": {
318
+ "id": {"type": "string", "description": "Memory ID (from search results, first 8 chars or full UUID)"},
319
+ },
320
+ "required": ["id"],
321
+ },
322
+ },
323
+ ]
324
+
325
+ def handle_tool_call(self, tool_name: str, args: Dict[str, Any], **kwargs) -> str:
326
+ client = self._client_or_none()
327
+ if client is None:
328
+ return json.dumps({"error": "hicortex server not configured"})
329
+ try:
330
+ if tool_name == "hicortex_search":
331
+ hits = client.search(
332
+ args.get("query", ""),
333
+ limit=int(args.get("limit", 5)),
334
+ project=args.get("project") or self._project,
335
+ )
336
+ return json.dumps(hits)
337
+
338
+ elif tool_name in ("hicortex_recall_recent", "hicortex_context"):
339
+ hits = client.context(
340
+ project=args.get("project") or self._project,
341
+ limit=int(args.get("limit", 10)),
342
+ )
343
+ return json.dumps(hits)
344
+
345
+ elif tool_name == "hicortex_ingest":
346
+ content = args.get("content", "")
347
+ if not content:
348
+ return json.dumps({"error": "content is required"})
349
+ status, resp = client.ingest(
350
+ content=content,
351
+ source_agent="hermes/manual",
352
+ project=args.get("project") or self._project,
353
+ memory_type=args.get("memory_type", "episode"),
354
+ )
355
+ if status not in (200, 201):
356
+ return json.dumps({"error": resp.get("error", f"HTTP {status}")})
357
+ id_val = resp.get("id") or ""
358
+ return json.dumps({"id": id_val, "message": f"Memory stored (id: {id_val[:8]})"})
359
+
360
+ elif tool_name == "hicortex_lessons":
361
+ data = client.lessons()
362
+ lessons = (data.get("lessons") or [])
363
+ if not lessons:
364
+ return json.dumps({"message": "No lessons found."})
365
+ return json.dumps([{"content": l.get("content", "")[:500]} for l in lessons])
366
+
367
+ elif tool_name == "hicortex_index":
368
+ return json.dumps(client.index())
369
+
370
+ elif tool_name == "hicortex_graph":
371
+ op = args.get("operation", "")
372
+ result = client.graph(
373
+ op=op,
374
+ id=args.get("id"),
375
+ target_id=args.get("target_id"),
376
+ limit=args.get("limit"),
377
+ domain=args.get("domain"),
378
+ relationship=args.get("relationship"),
379
+ )
380
+ return json.dumps(result)
381
+
382
+ elif tool_name == "hicortex_update":
383
+ id_val = args.get("id", "")
384
+ if not id_val:
385
+ return json.dumps({"error": "id is required"})
386
+ status, resp = client.update(
387
+ id=id_val,
388
+ content=args.get("content"),
389
+ project=args.get("project"),
390
+ memory_type=args.get("memory_type"),
391
+ )
392
+ if status == 404:
393
+ return json.dumps({"error": f"Memory not found: {id_val}"})
394
+ if status not in (200, 201):
395
+ return json.dumps({"error": resp.get("error", f"HTTP {status}")})
396
+ return json.dumps({"updated": True, "id": resp.get("id", id_val)})
397
+
398
+ elif tool_name == "hicortex_delete":
399
+ id_val = args.get("id", "")
400
+ if not id_val:
401
+ return json.dumps({"error": "id is required"})
402
+ status, resp = client.delete(id=id_val)
403
+ if status == 404:
404
+ return json.dumps({"error": f"Memory not found: {id_val}"})
405
+ if status not in (200, 201):
406
+ return json.dumps({"error": resp.get("error", f"HTTP {status}")})
407
+ return json.dumps({"deleted": True, "id": resp.get("id", id_val)})
408
+
409
+ else:
410
+ return json.dumps({"error": f"unknown tool: {tool_name}"})
411
+
412
+ except Exception as e:
413
+ return json.dumps({"error": str(e)})
414
+
415
+ # ---------------------------------------------------------------- lifecycle
416
+ def _spawn(self, fn) -> None:
417
+ self._bg_threads = [t for t in self._bg_threads if t.is_alive()]
418
+ t = threading.Thread(target=fn, daemon=True)
419
+ t.start()
420
+ self._bg_threads.append(t)
421
+
422
+ def shutdown(self) -> None:
423
+ for t in self._bg_threads:
424
+ t.join(timeout=2.0)
425
+
426
+ def get_config_schema(self) -> List[Dict[str, Any]]:
427
+ return CONFIG_SCHEMA
428
+
429
+ def save_config(self, values: Dict[str, Any], hermes_home: str) -> None:
430
+ from .config import save_config as _save
431
+
432
+ _save(values, hermes_home)
@@ -2,69 +2,42 @@
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.7.0",
5
+ "version": "0.10.0",
6
6
  "kind": "lifecycle",
7
7
  "skills": ["./skills/hicortex-memory", "./skills/hicortex-learn", "./skills/hicortex-activate"],
8
8
  "configSchema": {
9
9
  "type": "object",
10
10
  "properties": {
11
- "licenseKey": {
12
- "type": "string",
13
- "description": "Hicortex license key (hctx-...). Leave empty for free tier (250 memory cap)."
14
- },
15
- "llmBaseUrl": {
16
- "type": "string",
17
- "description": "LLM API base URL. Auto-detected from OpenClaw config or env vars if omitted."
18
- },
19
- "llmApiKey": {
20
- "type": "string",
21
- "description": "LLM API key. Auto-detected from OpenClaw config or env vars if omitted."
22
- },
23
- "llmModel": {
11
+ "serverUrl": {
24
12
  "type": "string",
25
- "default": "qwen3.5:4b",
26
- "description": "Model for importance scoring and distillation (local recommended)"
13
+ "default": "http://127.0.0.1:8787",
14
+ "description": "Hicortex server URL. Defaults to localhost (co-located server). For multi-machine setups, point this at the remote server (e.g. http://bedrock:8787 or a Tailscale HTTPS URL)."
27
15
  },
28
- "reflectModel": {
16
+ "authToken": {
29
17
  "type": "string",
30
- "default": "qwen3.5:cloud",
31
- "description": "Model for nightly reflection (cloud recommended)"
18
+ "description": "Bearer token for the Hicortex server. Localhost bypasses auth automatically. Required for remote servers — use the authToken from ~/.hicortex/config.json on the server."
32
19
  },
33
- "consolidateHour": {
34
- "type": "number",
35
- "default": 2,
36
- "description": "Hour (0-23, local time) to run nightly consolidation"
37
- },
38
- "dbPath": {
20
+ "licenseKey": {
39
21
  "type": "string",
40
- "description": "Custom path for the SQLite database file"
22
+ "description": "Hicortex license key (hctx-...). Leave empty for free tier (250 memory cap)."
41
23
  }
42
24
  },
43
25
  "required": []
44
26
  },
45
27
  "uiHints": {
28
+ "serverUrl": {
29
+ "label": "Server URL",
30
+ "placeholder": "http://127.0.0.1:8787"
31
+ },
32
+ "authToken": {
33
+ "label": "Auth Token",
34
+ "sensitive": true,
35
+ "placeholder": "Required for remote servers"
36
+ },
46
37
  "licenseKey": {
47
38
  "label": "License Key",
48
39
  "placeholder": "hctx-... (optional, free tier without key)",
49
40
  "sensitive": true
50
- },
51
- "llmBaseUrl": {
52
- "label": "LLM API URL",
53
- "placeholder": "Auto-detected if empty"
54
- },
55
- "llmApiKey": {
56
- "label": "LLM API Key",
57
- "sensitive": true,
58
- "placeholder": "Auto-detected if empty"
59
- },
60
- "llmModel": {
61
- "label": "Scoring Model"
62
- },
63
- "reflectModel": {
64
- "label": "Reflection Model"
65
- },
66
- "consolidateHour": {
67
- "label": "Consolidation Hour"
68
41
  }
69
42
  }
70
43
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gamaze/hicortex",
3
- "version": "0.7.0",
4
- "description": "Human-like memory for self-improving AI agents. Automatic capturing, nightly reflection, and cross-agent learning. Works with Claude Code and OpenClaw.",
3
+ "version": "0.10.0",
4
+ "description": "Self-learning memory for AI agents \u2014 experience captured automatically, distilled into lessons overnight, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, and Pi.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "hicortex": "dist/cli.js"
@@ -26,14 +26,16 @@
26
26
  "files": [
27
27
  "dist/",
28
28
  "skills/",
29
+ "hermes-plugin/",
29
30
  "openclaw.plugin.json",
30
31
  "README.md"
31
32
  ],
32
33
  "scripts": {
33
- "build": "tsc",
34
+ "build": "rm -rf dist && tsc",
34
35
  "test": "vitest run",
35
36
  "test:watch": "vitest",
36
- "prepublishOnly": "npm run build"
37
+ "prepack": "npm run build && rm -rf ./hermes-plugin && mkdir -p ./hermes-plugin && cp -r ../../hermes-plugin/hicortex ./hermes-plugin/ && find ./hermes-plugin -name __pycache__ -type d -exec rm -rf {} + 2>/dev/null || true",
38
+ "prepublishOnly": "npm run build && rm -rf ./hermes-plugin && mkdir -p ./hermes-plugin && cp -r ../../hermes-plugin/hicortex ./hermes-plugin/ && find ./hermes-plugin -name __pycache__ -type d -exec rm -rf {} + 2>/dev/null || true"
37
39
  },
38
40
  "devDependencies": {
39
41
  "@types/better-sqlite3": "^7.6.0",
@@ -45,7 +47,7 @@
45
47
  "engines": {
46
48
  "node": ">=18"
47
49
  },
48
- "license": "MIT",
50
+ "license": "PolyForm-Noncommercial-1.0.0",
49
51
  "homepage": "https://hicortex.gamaze.com",
50
52
  "repository": {
51
53
  "type": "git",
@@ -1,33 +0,0 @@
1
- /**
2
- * Pro extension loader.
3
- *
4
- * Called from features.ts at boot when a valid paid license is detected.
5
- * Responsibilities:
6
- * 1. Check ~/.hicortex/pro/installed.json for the currently-installed
7
- * Pro version (if any).
8
- * 2. Fetch GET /api/pro/meta from hicortex.gamaze.com to discover the
9
- * latest available version for the caller's license tier.
10
- * 3. If the installed version is older (or missing), download the
11
- * tarball, verify the sha256 sidecar, and extract to ~/.hicortex/pro/.
12
- * 4. Dynamic-import ~/.hicortex/pro/package/index.js and call activate()
13
- * on its default export with a ProActivationContext.
14
- *
15
- * Failure modes (all soft — OSS host keeps running with defaults):
16
- * - Network to /api/pro/meta fails → use whatever is already installed
17
- * - No cached Pro and network fails → Pro not activated, OSS defaults apply
18
- * - Downloaded tarball fails sha256 → abort download, keep old version
19
- * - import() of activated module throws → log warning, keep defaults
20
- *
21
- * The loader is strictly best-effort. It must NEVER crash the OSS host.
22
- */
23
- /**
24
- * Entry point called from features.ts at boot.
25
- *
26
- * @param licenseKey The Pro license key (hctx-...) from config
27
- * @param stateDir Usually ~/.hicortex/
28
- * @param hostVersion The version of the OSS host (from package.json) — passed
29
- * to the Pro activate() for compatibility gating
30
- * @param serverUrl Override for the Pro meta/download endpoint (defaults
31
- * to https://hicortex.gamaze.com). Useful for testing.
32
- */
33
- export declare function loadPro(licenseKey: string, stateDir: string, hostVersion: string, serverUrl?: string): Promise<void>;