@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
@@ -43,6 +43,7 @@ exports.parseJsonLenient = parseJsonLenient;
43
43
  exports.runConsolidation = runConsolidation;
44
44
  exports.msUntilHour = msUntilHour;
45
45
  exports.scheduleConsolidation = scheduleConsolidation;
46
+ const types_js_1 = require("./types.js");
46
47
  const retrieval_js_1 = require("./retrieval.js");
47
48
  const storage = __importStar(require("./storage.js"));
48
49
  const prompts_js_1 = require("./prompts.js");
@@ -267,13 +268,6 @@ async function stageReflection(db, memories, llm, budget, embedFn, dryRun) {
267
268
  minor: 0.6,
268
269
  };
269
270
  try {
270
- // Check memory cap before storing lesson
271
- if ((0, features_js_1.memoryCapReached)(storage.countMemories(db))) {
272
- console.log(`[hicortex] Free tier limit (${(0, features_js_1.maxMemoriesAllowed)()} memories). ` +
273
- `Existing memories and lessons still work. New lessons won't be saved. ` +
274
- `Upgrade for unlimited usage: https://hicortex.gamaze.com/`);
275
- break;
276
- }
277
271
  const embedding = await embedFn(content);
278
272
  // Contradiction check: find semantically similar existing lessons.
279
273
  // If a very similar lesson exists, ask the LLM whether the new one
@@ -487,12 +481,17 @@ async function stageDomainCuration(db, llm, budget, dryRun, stateDir) {
487
481
  console.log(`[hicortex] Domain curation: ${domains.length} domains from ${projectRows.length} projects`);
488
482
  return { curated: true, domains: domains.length };
489
483
  }
490
- // ---------------------------------------------------------------------------
491
- // Stage 3: Link Discovery (vector similarity auto-link)
492
- // ---------------------------------------------------------------------------
493
- async function stageLinks(db, memories, embedFn, dryRun) {
484
+ /** Batch size for LLM edge classification calls. */
485
+ const EDGE_CLASSIFICATION_BATCH_SIZE = 8;
486
+ /** Valid relationship type set for fast lookup. */
487
+ const VALID_REL_SET = new Set(types_js_1.VALID_RELATIONSHIP_TYPES);
488
+ async function stageLinks(db, memories, embedFn, dryRun, llm, budget) {
494
489
  let autoLinked = 0;
490
+ let llmClassified = 0;
491
+ let heuristicFallback = 0;
495
492
  let failed = 0;
493
+ // Phase A: Discovery — collect candidates via vector similarity
494
+ const candidates = [];
496
495
  for (const mem of memories) {
497
496
  try {
498
497
  const embedding = await embedFn(mem.content);
@@ -500,27 +499,78 @@ async function stageLinks(db, memories, embedFn, dryRun) {
500
499
  for (const neighbor of neighbors) {
501
500
  const similarity = 1.0 - neighbor.distance;
502
501
  if (similarity > CONSOLIDATE_LINK_THRESHOLD) {
503
- const relationship = classifyRelationship(mem, neighbor, similarity);
504
- if (!dryRun) {
505
- try {
506
- storage.addLink(db, mem.id, neighbor.id, relationship, similarity);
507
- autoLinked++;
502
+ const heuristicType = classifyRelationship(mem, neighbor, similarity);
503
+ candidates.push({ source: mem, target: neighbor, similarity, heuristicType });
504
+ }
505
+ }
506
+ }
507
+ catch {
508
+ failed++;
509
+ }
510
+ }
511
+ if (candidates.length === 0) {
512
+ return { auto_linked: 0, llm_classified: 0, heuristic_fallback: 0, failed };
513
+ }
514
+ // Phase B: LLM batch classification
515
+ // Build batches and classify with LLM where budget allows
516
+ const classifiedTypes = new Array(candidates.length);
517
+ for (let i = 0; i < candidates.length; i += EDGE_CLASSIFICATION_BATCH_SIZE) {
518
+ const batch = candidates.slice(i, i + EDGE_CLASSIFICATION_BATCH_SIZE);
519
+ // Attempt LLM classification if budget allows
520
+ if (budget.use("edge_classification")) {
521
+ try {
522
+ const pairsBlock = batch.map((c, idx) => {
523
+ const srcContent = c.source.content.slice(0, 200);
524
+ const tgtContent = c.target.content.slice(0, 200);
525
+ return `[${idx}] SOURCE: ${c.source.memory_type} | ${c.source.project ?? "global"} | ${srcContent}\n TARGET: ${c.target.memory_type} | ${c.target.project ?? "global"} | ${tgtContent}\n similarity: ${c.similarity.toFixed(2)}`;
526
+ }).join("\n\n");
527
+ const prompt = (0, prompts_js_1.edgeClassification)(pairsBlock);
528
+ const raw = await llm.completeFast(prompt, 512);
529
+ const parsed = parseJsonLenient(raw, []);
530
+ if (Array.isArray(parsed) && parsed.length > 0) {
531
+ for (let j = 0; j < batch.length; j++) {
532
+ const llmType = parsed[j];
533
+ if (typeof llmType === "string" && VALID_REL_SET.has(llmType)) {
534
+ classifiedTypes[i + j] = llmType;
535
+ llmClassified++;
508
536
  }
509
- catch {
510
- failed++;
537
+ else {
538
+ // Invalid type from LLM — fall back to heuristic
539
+ classifiedTypes[i + j] = batch[j].heuristicType;
540
+ heuristicFallback++;
511
541
  }
512
542
  }
513
- else {
514
- autoLinked++;
515
- }
543
+ continue;
516
544
  }
517
545
  }
546
+ catch {
547
+ // LLM call failed — fall through to heuristic for this batch
548
+ }
518
549
  }
519
- catch {
520
- failed++;
550
+ // Budget exhausted or LLM failed — use heuristic for entire batch
551
+ for (let j = 0; j < batch.length; j++) {
552
+ classifiedTypes[i + j] = batch[j].heuristicType;
553
+ heuristicFallback++;
554
+ }
555
+ }
556
+ // Phase C: Store all classified links
557
+ for (let i = 0; i < candidates.length; i++) {
558
+ const c = candidates[i];
559
+ const relationship = classifiedTypes[i];
560
+ if (!dryRun) {
561
+ try {
562
+ storage.addLink(db, c.source.id, c.target.id, relationship, c.similarity);
563
+ autoLinked++;
564
+ }
565
+ catch {
566
+ failed++;
567
+ }
568
+ }
569
+ else {
570
+ autoLinked++;
521
571
  }
522
572
  }
523
- return { auto_linked: autoLinked, failed };
573
+ return { auto_linked: autoLinked, llm_classified: llmClassified, heuristic_fallback: heuristicFallback, failed };
524
574
  }
525
575
  /**
526
576
  * Classify the relationship between two memories based on type, temporal ordering, and similarity.
@@ -660,8 +710,8 @@ async function runConsolidation(db, llm, embedFn, dryRun = false, skipReflection
660
710
  }
661
711
  // Stage 2.7: Domain Curation
662
712
  report.stages.domain_curation = await stageDomainCuration(db, llm, budget, dryRun, stateDir);
663
- // Stage 3: Link Discovery
664
- report.stages.links = await stageLinks(db, precheck.newMemories, embedFn, dryRun);
713
+ // Stage 3: Link Discovery (with LLM-assisted edge classification)
714
+ report.stages.links = await stageLinks(db, precheck.newMemories, embedFn, dryRun, llm, budget);
665
715
  // Stage 3.5: Hub Detection — boost highly-connected memories
666
716
  report.stages.hub_boost = stageHubBoost(db, dryRun);
667
717
  // Stage 4: Decay & Prune
package/dist/db.js CHANGED
@@ -226,6 +226,30 @@ const MIGRATIONS = [
226
226
  db.exec("CREATE INDEX IF NOT EXISTS idx_memories_domain ON memories(domain)");
227
227
  },
228
228
  },
229
+ {
230
+ version: 4,
231
+ name: "unique_source_session",
232
+ up: (db) => {
233
+ // De-duplicate any pre-existing source_session values (e.g. from the
234
+ // /ingest + /distill race before this migration): keep the oldest row per
235
+ // source_session, NULL the rest so they lose their dedup key (the memory
236
+ // itself is preserved). Then add a UNIQUE partial index so the server can
237
+ // idempotently re-distill a segment without double-inserting.
238
+ db.exec(`
239
+ UPDATE memories SET source_session = NULL
240
+ WHERE rowid NOT IN (
241
+ SELECT MIN(rowid) FROM memories
242
+ WHERE source_session IS NOT NULL
243
+ GROUP BY source_session
244
+ )
245
+ AND source_session IS NOT NULL
246
+ `);
247
+ db.exec(`
248
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_source_session_unique
249
+ ON memories(source_session) WHERE source_session IS NOT NULL
250
+ `);
251
+ },
252
+ },
229
253
  ];
230
254
  /**
231
255
  * Run all pending migrations against the database.
@@ -6,6 +6,17 @@
6
6
  * installed. The model is lazy-loaded on first call.
7
7
  */
8
8
  export declare const EMBEDDING_DIMENSIONS = 384;
9
+ /**
10
+ * Resolve the directory where @huggingface/transformers caches model weights.
11
+ *
12
+ * Exported as a pure function so it can be unit-tested without mocking the
13
+ * dynamic import. The default (`~/.hicortex/models`) is stable across package
14
+ * upgrades and writable by the installing user even under global npm installs
15
+ * (where the package dir is root-owned).
16
+ *
17
+ * @param home Override for the user home directory (used in tests).
18
+ */
19
+ export declare function resolveModelCacheDir(home?: string): string;
9
20
  /**
10
21
  * Embed a single text string. Returns a Float32Array of 384 dimensions.
11
22
  */
package/dist/embedder.js CHANGED
@@ -8,14 +8,31 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.EMBEDDING_DIMENSIONS = void 0;
11
+ exports.resolveModelCacheDir = resolveModelCacheDir;
11
12
  exports.embed = embed;
12
13
  exports.embedBatch = embedBatch;
13
14
  exports.dimensions = dimensions;
15
+ const node_fs_1 = require("node:fs");
16
+ const node_path_1 = require("node:path");
17
+ const node_os_1 = require("node:os");
14
18
  exports.EMBEDDING_DIMENSIONS = 384;
15
19
  const MODEL_NAME = "Xenova/bge-small-en-v1.5";
16
20
  // Pipeline is lazy-loaded on first use
17
21
  let pipeline = null;
18
22
  let initPromise = null;
23
+ /**
24
+ * Resolve the directory where @huggingface/transformers caches model weights.
25
+ *
26
+ * Exported as a pure function so it can be unit-tested without mocking the
27
+ * dynamic import. The default (`~/.hicortex/models`) is stable across package
28
+ * upgrades and writable by the installing user even under global npm installs
29
+ * (where the package dir is root-owned).
30
+ *
31
+ * @param home Override for the user home directory (used in tests).
32
+ */
33
+ function resolveModelCacheDir(home) {
34
+ return (0, node_path_1.join)(home ?? (0, node_os_1.homedir)(), ".hicortex", "models");
35
+ }
19
36
  /**
20
37
  * Initialize the embedding pipeline (called lazily on first embed call).
21
38
  * Throws with a clear error if @huggingface/transformers is not available.
@@ -32,6 +49,16 @@ async function ensureInit() {
32
49
  // Dynamic import — package may not be installed (it's optional)
33
50
  // eslint-disable-next-line @typescript-eslint/no-require-imports
34
51
  const transformers = await Function('return import("@huggingface/transformers")')();
52
+ // Point the model cache at a stable user-writable directory so the
53
+ // ~130 MB weights survive package upgrades and work under global installs
54
+ // (the package dir is root-owned; defaulting to it causes EACCES).
55
+ const cacheDir = resolveModelCacheDir();
56
+ (0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
57
+ const env = transformers.env ?? transformers.default?.env;
58
+ if (env) {
59
+ env.cacheDir = cacheDir;
60
+ }
61
+ console.log(`[hicortex] Model cache: ${cacheDir}`);
35
62
  const pipelineFn = transformers.pipeline ?? transformers.default?.pipeline;
36
63
  if (!pipelineFn) {
37
64
  throw new Error("Could not find pipeline function in @huggingface/transformers");
@@ -1,39 +1,37 @@
1
1
  /**
2
- * Extension interfaces for the OSS/Pro split.
2
+ * Extension interfaces + default implementations.
3
3
  *
4
- * The OSS client defines these interfaces and ships default implementations
5
- * (the current behaviour). Pro features (in src/pro/, never published) provide
6
- * alternative implementations that are loaded at runtime via dynamic import,
7
- * gated by the license check in features.ts.
4
+ * Originally the seam for the OSS/Pro split (Pro retired in #122 the
5
+ * product is fully featured for everyone). The interfaces and the
6
+ * setExtensions() override hook remain so alternative implementations can
7
+ * still be swapped in (tests, future experiments).
8
8
  *
9
- * Why these specific interfaces:
9
+ * LessonSelector lesson selection sites:
10
+ * lessons-context.ts:fetchLessonsContext (CC SessionStart hook),
11
+ * index.ts:before_agent_start (OC in-process plugin).
12
+ * The default is the domain-aware scoring selector (lesson-selection.ts):
13
+ * ranks lessons by project match + domain affinity + recency +
14
+ * base_strength + access affinity, with prefix-based dedup. Restored
15
+ * into core in #123 after being deleted with the Pro loader in #122.
10
16
  *
11
- * LessonSelectorthere are exactly 3 lesson selection sites in the OSS
12
- * code (claude-md.ts:injectLessons, index.ts:before_agent_start,
13
- * nightly.ts:injectLessonsFromServer). All three currently do
14
- * `lessons.slice(0, maxLessons)` after a DB or HTTP fetch. The Pro
15
- * selector ranks lessons against project context, recency, and
16
- * effectiveness scores instead of dumb-truncating.
17
- *
18
- * PromptStrategy — the current prompts.ts exports three pure functions
19
- * (distillation, reflection, importanceScoring). The Pro variant has
20
- * prescriptive prompts (`when X do Y` format) and re-trained reflection
21
- * that produces a richer schema. The strategy bundles the prompt WITH
22
- * its parser so a Pro prompt with a different output schema cannot
23
- * silently fail when the OSS consumer parses it with the wrong shape.
17
+ * PromptStrategyprompts.ts exports three pure functions
18
+ * (distillation, reflection, importanceScoring). The strategy bundles
19
+ * the prompt WITH its parser so a prompt with a different output schema
20
+ * cannot silently fail when the consumer parses it with the wrong shape.
24
21
  *
25
22
  * NOT in this file (deliberately deferred):
26
23
  * - ContextAssembler — over-abstracted; the real seam is buildProjectContext
27
24
  * in claude-md.ts, not the whole assembler. Will add when needed.
28
- * - LessonValidator — speculative; no validation exists today. Will add
29
- * when the first Pro use case demands it.
25
+ * - LessonValidator — speculative; no validation exists today.
30
26
  */
31
27
  import type { ModuleIndex } from "./types.js";
32
28
  /**
33
29
  * Minimum fields a lesson must have for the selector to work.
34
30
  *
35
- * The default selector only needs `content`. Pro selectors may need more
36
- * (project for in-project weighting, base_strength for ranking, etc.).
31
+ * Only `content` is required. The default (domain-aware) selector uses the
32
+ * optional fields when present — project for in-project/domain weighting,
33
+ * created_at for recency, base_strength for importance, access_count for
34
+ * proven-usefulness — and falls back to neutral scores when absent.
37
35
  *
38
36
  * Memory satisfies this interface (it's a structural subset), and the
39
37
  * client-mode HTTP shape `{content, created_at, base_strength, access_count}`
@@ -52,20 +50,21 @@ export interface SelectableLesson {
52
50
  export interface LessonSelectorContext {
53
51
  /** Maximum number of lessons to return. Caller decides this from features.lessonsLimit(). */
54
52
  maxLessons: number;
55
- /** Current project, if known. Pro selectors weight in-project lessons higher. */
53
+ /** Current project, if known. The default selector weights in-project lessons higher. */
56
54
  project?: string | null;
57
- /** Optional: agent id, for cross-agent learning context (Pro). */
55
+ /** Optional: agent id, for cross-agent learning context. */
58
56
  agentId?: string;
59
- /** Optional: current task description, for relevance scoring (Pro). */
57
+ /** Optional: current task description, for relevance scoring. */
60
58
  currentTask?: string;
61
- /** MODULE_INDEX for domain-aware lesson selection (Pro). */
59
+ /** MODULE_INDEX for domain-aware lesson selection (same-domain projects score 0.5). */
62
60
  moduleIndex?: ModuleIndex;
63
61
  }
64
62
  export interface LessonSelector {
65
63
  /**
66
64
  * Pick `ctx.maxLessons` lessons from the candidate pool.
67
- * Default impl: take the first N (caller passes them in priority order).
68
- * Pro impl: rank by relevance to ctx.project / ctx.currentTask / effectiveness.
65
+ * Default impl: domain-aware scoring (lesson-selection.ts) ranks by
66
+ * project match, domain affinity, recency, base_strength, and access
67
+ * affinity, with prefix-based dedup.
69
68
  *
70
69
  * Generic so the output type matches the input type — Memory[] in returns
71
70
  * Memory[] out, partial-shape in returns partial-shape out.
@@ -73,8 +72,13 @@ export interface LessonSelector {
73
72
  select<T extends SelectableLesson>(lessons: T[], ctx: LessonSelectorContext): T[] | Promise<T[]>;
74
73
  }
75
74
  /**
76
- * Default LessonSelector — preserves current OSS behaviour exactly.
77
- * `slice(0, maxLessons)` over the candidate pool, no re-ranking.
75
+ * Default LessonSelector — the domain-aware scoring selector.
76
+ *
77
+ * Ranks lessons by project match (1.0 exact / 0.5 same-domain via moduleIndex
78
+ * / 0.3 global), recency (30-day half-life), base_strength, and access
79
+ * affinity; dedups near-identical lessons by normalized prefix. When lessons
80
+ * carry no metadata, all scores tie and stable sort preserves input order
81
+ * (equivalent to the old slice(0, N) behaviour).
78
82
  */
79
83
  export declare const defaultLessonSelector: LessonSelector;
80
84
  /** Output schema produced by the reflection prompt and consumed by consolidate.ts. */
@@ -108,69 +112,18 @@ export interface PromptStrategy {
108
112
  }
109
113
  export declare const defaultPromptStrategy: PromptStrategy;
110
114
  /**
111
- * Holder for the active extension implementations. The OSS client always uses
112
- * the defaults; Pro features (in src/pro/, loaded via dynamic import) replace
113
- * these at boot if a valid license is present.
114
- *
115
- * Wiring will happen via setExtensions() called from src/pro/ after license
116
- * validation (not yet implemented in OSS). Until Pro code exists and is loaded,
117
- * every call site uses the defaults — zero behavioural change for OSS users.
115
+ * Holder for the active extension implementations. Every install uses the
116
+ * defaults; setExtensions() remains as an override hook for tests and future
117
+ * alternative implementations.
118
118
  */
119
119
  declare let activeExtensions: {
120
120
  selector: LessonSelector;
121
121
  prompts: PromptStrategy;
122
122
  };
123
- /** Replace the active extensions (called from features.ts when Pro loads). */
123
+ /** Replace the active extensions (override hook tests, experiments). */
124
124
  export declare function setExtensions(ext: Partial<typeof activeExtensions>): void;
125
- /** Get the active LessonSelector (default unless Pro is loaded). */
125
+ /** Get the active LessonSelector. */
126
126
  export declare function getLessonSelector(): LessonSelector;
127
- /** Get the active PromptStrategy (default unless Pro is loaded). */
127
+ /** Get the active PromptStrategy. */
128
128
  export declare function getPromptStrategy(): PromptStrategy;
129
- /**
130
- * The object passed to a Pro package's `activate()` function at boot.
131
- * Pro packages receive this to register their extensions and access OSS
132
- * runtime APIs they need.
133
- *
134
- * Design rationale: Pro code never STATICALLY imports from the OSS client.
135
- * All runtime access is through this context object. This has two benefits:
136
- * 1. Pro bundles are self-contained — they don't have `require("../...")`
137
- * calls that would break when the tarball is installed to
138
- * ~/.hicortex/pro/ at runtime.
139
- * 2. Pro code can only access what the OSS client exposes here, so the
140
- * blast radius of a malicious/buggy Pro release is contained.
141
- *
142
- * Type-only imports of `LessonSelector`, `PromptStrategy` etc. in Pro code
143
- * are fine — they're erased at compile time and produce no runtime imports.
144
- */
145
- export interface ProActivationContext {
146
- /** Register a lesson selector implementation. */
147
- setSelector(selector: LessonSelector): void;
148
- /** Register a prompt strategy implementation. */
149
- setPrompts(prompts: PromptStrategy): void;
150
- /** The version of the OSS host (from package.json). Pro can use this
151
- * to gate features against host compatibility. */
152
- hostVersion: string;
153
- /** Log through the OSS logging surface so Pro logs get the [hicortex]
154
- * prefix and unified formatting. */
155
- log(message: string): void;
156
- }
157
- /**
158
- * The shape Pro packages must export as their default export.
159
- * See `packages/hicortex/src/pro/index.ts` for the reference impl.
160
- */
161
- export interface ProPackage {
162
- /** Called once at OSS boot if a Pro license is valid and the Pro
163
- * tarball has been downloaded + extracted. Should register extensions
164
- * via the context and return. Errors abort Pro activation but do not
165
- * abort the OSS host. */
166
- activate(ctx: ProActivationContext): void | Promise<void>;
167
- }
168
- /**
169
- * Build an activation context for a Pro package. Called from the Pro
170
- * loader in features.ts / pro-loader.ts.
171
- *
172
- * Keep this function small — it's the ONLY surface a Pro package gets.
173
- * Expanding it expands the attack surface, so add fields deliberately.
174
- */
175
- export declare function createProActivationContext(hostVersion: string): ProActivationContext;
176
129
  export {};
@@ -1,49 +1,49 @@
1
1
  "use strict";
2
2
  /**
3
- * Extension interfaces for the OSS/Pro split.
3
+ * Extension interfaces + default implementations.
4
4
  *
5
- * The OSS client defines these interfaces and ships default implementations
6
- * (the current behaviour). Pro features (in src/pro/, never published) provide
7
- * alternative implementations that are loaded at runtime via dynamic import,
8
- * gated by the license check in features.ts.
5
+ * Originally the seam for the OSS/Pro split (Pro retired in #122 the
6
+ * product is fully featured for everyone). The interfaces and the
7
+ * setExtensions() override hook remain so alternative implementations can
8
+ * still be swapped in (tests, future experiments).
9
9
  *
10
- * Why these specific interfaces:
10
+ * LessonSelector lesson selection sites:
11
+ * lessons-context.ts:fetchLessonsContext (CC SessionStart hook),
12
+ * index.ts:before_agent_start (OC in-process plugin).
13
+ * The default is the domain-aware scoring selector (lesson-selection.ts):
14
+ * ranks lessons by project match + domain affinity + recency +
15
+ * base_strength + access affinity, with prefix-based dedup. Restored
16
+ * into core in #123 after being deleted with the Pro loader in #122.
11
17
  *
12
- * LessonSelectorthere are exactly 3 lesson selection sites in the OSS
13
- * code (claude-md.ts:injectLessons, index.ts:before_agent_start,
14
- * nightly.ts:injectLessonsFromServer). All three currently do
15
- * `lessons.slice(0, maxLessons)` after a DB or HTTP fetch. The Pro
16
- * selector ranks lessons against project context, recency, and
17
- * effectiveness scores instead of dumb-truncating.
18
- *
19
- * PromptStrategy — the current prompts.ts exports three pure functions
20
- * (distillation, reflection, importanceScoring). The Pro variant has
21
- * prescriptive prompts (`when X do Y` format) and re-trained reflection
22
- * that produces a richer schema. The strategy bundles the prompt WITH
23
- * its parser so a Pro prompt with a different output schema cannot
24
- * silently fail when the OSS consumer parses it with the wrong shape.
18
+ * PromptStrategyprompts.ts exports three pure functions
19
+ * (distillation, reflection, importanceScoring). The strategy bundles
20
+ * the prompt WITH its parser so a prompt with a different output schema
21
+ * cannot silently fail when the consumer parses it with the wrong shape.
25
22
  *
26
23
  * NOT in this file (deliberately deferred):
27
24
  * - ContextAssembler — over-abstracted; the real seam is buildProjectContext
28
25
  * in claude-md.ts, not the whole assembler. Will add when needed.
29
- * - LessonValidator — speculative; no validation exists today. Will add
30
- * when the first Pro use case demands it.
26
+ * - LessonValidator — speculative; no validation exists today.
31
27
  */
32
28
  Object.defineProperty(exports, "__esModule", { value: true });
33
29
  exports.defaultPromptStrategy = exports.defaultLessonSelector = void 0;
34
30
  exports.setExtensions = setExtensions;
35
31
  exports.getLessonSelector = getLessonSelector;
36
32
  exports.getPromptStrategy = getPromptStrategy;
37
- exports.createProActivationContext = createProActivationContext;
33
+ // The domain-aware scoring selector is THE default for every install.
34
+ // (lesson-selection.ts only imports types from this file, so there is no
35
+ // runtime import cycle — `import type` is erased at compile time.)
36
+ const lesson_selection_js_1 = require("./lesson-selection.js");
38
37
  /**
39
- * Default LessonSelector — preserves current OSS behaviour exactly.
40
- * `slice(0, maxLessons)` over the candidate pool, no re-ranking.
38
+ * Default LessonSelector — the domain-aware scoring selector.
39
+ *
40
+ * Ranks lessons by project match (1.0 exact / 0.5 same-domain via moduleIndex
41
+ * / 0.3 global), recency (30-day half-life), base_strength, and access
42
+ * affinity; dedups near-identical lessons by normalized prefix. When lessons
43
+ * carry no metadata, all scores tie and stable sort preserves input order
44
+ * (equivalent to the old slice(0, N) behaviour).
41
45
  */
42
- exports.defaultLessonSelector = {
43
- select(lessons, ctx) {
44
- return lessons.slice(0, ctx.maxLessons);
45
- },
46
- };
46
+ exports.defaultLessonSelector = lesson_selection_js_1.domainAwareLessonSelector;
47
47
  // ---------------------------------------------------------------------------
48
48
  // Default PromptStrategy — wraps the current prompts.ts and the lenient JSON
49
49
  // parser from consolidate.ts. Preserves current OSS behaviour exactly.
@@ -126,51 +126,26 @@ exports.defaultPromptStrategy = {
126
126
  },
127
127
  };
128
128
  // ---------------------------------------------------------------------------
129
- // Loader — used by call sites to get either the OSS default or a Pro override
129
+ // Loader — used by call sites to get the active implementations
130
130
  // ---------------------------------------------------------------------------
131
131
  /**
132
- * Holder for the active extension implementations. The OSS client always uses
133
- * the defaults; Pro features (in src/pro/, loaded via dynamic import) replace
134
- * these at boot if a valid license is present.
135
- *
136
- * Wiring will happen via setExtensions() called from src/pro/ after license
137
- * validation (not yet implemented in OSS). Until Pro code exists and is loaded,
138
- * every call site uses the defaults — zero behavioural change for OSS users.
132
+ * Holder for the active extension implementations. Every install uses the
133
+ * defaults; setExtensions() remains as an override hook for tests and future
134
+ * alternative implementations.
139
135
  */
140
136
  let activeExtensions = {
141
137
  selector: exports.defaultLessonSelector,
142
138
  prompts: exports.defaultPromptStrategy,
143
139
  };
144
- /** Replace the active extensions (called from features.ts when Pro loads). */
140
+ /** Replace the active extensions (override hook tests, experiments). */
145
141
  function setExtensions(ext) {
146
142
  activeExtensions = { ...activeExtensions, ...ext };
147
143
  }
148
- /** Get the active LessonSelector (default unless Pro is loaded). */
144
+ /** Get the active LessonSelector. */
149
145
  function getLessonSelector() {
150
146
  return activeExtensions.selector;
151
147
  }
152
- /** Get the active PromptStrategy (default unless Pro is loaded). */
148
+ /** Get the active PromptStrategy. */
153
149
  function getPromptStrategy() {
154
150
  return activeExtensions.prompts;
155
151
  }
156
- /**
157
- * Build an activation context for a Pro package. Called from the Pro
158
- * loader in features.ts / pro-loader.ts.
159
- *
160
- * Keep this function small — it's the ONLY surface a Pro package gets.
161
- * Expanding it expands the attack surface, so add fields deliberately.
162
- */
163
- function createProActivationContext(hostVersion) {
164
- return {
165
- setSelector(selector) {
166
- activeExtensions = { ...activeExtensions, selector };
167
- },
168
- setPrompts(prompts) {
169
- activeExtensions = { ...activeExtensions, prompts };
170
- },
171
- hostVersion,
172
- log(message) {
173
- console.log(`[hicortex][pro] ${message}`);
174
- },
175
- };
176
- }
@@ -1,37 +1,33 @@
1
1
  /**
2
- * Centralized feature gating — single source of truth for tier-dependent values.
2
+ * Feature gating — all gates removed as of 0.10.0.
3
3
  *
4
- * Why this exists:
5
- * - getFeatures() in license.ts was sync but validateLicense was async, creating
6
- * a race where Pro users got free-tier features during the validation window.
7
- * - License checks were scattered across 8+ call sites with subtly different
8
- * handling (e.g., consolidate.ts:308 had a dynamic import in a hot loop to
9
- * dodge a circular import).
4
+ * Personal and noncommercial use is fully featured under the
5
+ * PolyForm Noncommercial License. Commercial use requires a per-seat
6
+ * license (see COMMERCIAL.md). There is no technical feature gating;
7
+ * the license key's only remaining role is the "licensed to <org>"
8
+ * display in `hicortex status`.
10
9
  *
11
- * All feature decisions now flow through this module. Call initFeatures() once at
12
- * process boot before serving any requests; sync getters become deterministic.
10
+ * The functions below are kept as trivial wrappers so call sites
11
+ * compile without churn. They will be removed entirely in a future
12
+ * cleanup pass once callers have been audited.
13
13
  */
14
14
  import type { LicenseInfo } from "./types.js";
15
15
  /**
16
- * Initialize the feature cache. Call ONCE at process boot before any feature
17
- * gating queries. Race fix:
18
- * 1. Synchronously load persisted tier from disk (instant, deterministic)
19
- * 2. If no persisted tier and we have a key, AWAIT first validation
20
- * 3. If persisted tier exists, kick off background re-validation
21
- *
22
- * After this returns, sync getters (isPro, lessonsLimit, etc.) are deterministic
23
- * and reflect the user's actual tier — no more "free during validation window".
16
+ * Initialize license display. Call ONCE at process boot.
17
+ * No feature gates are applied regardless of the validation result.
24
18
  */
25
- export declare function initFeatures(licenseKey: string | undefined, stateDir?: string, hostVersion?: string): Promise<void>;
26
- /** Are we on a paid tier (Pro, Team, Lifetime)? */
19
+ export declare function initFeatures(licenseKey: string | undefined, stateDir?: string, _hostVersion?: string): Promise<void>;
20
+ /** Returns the validated license info if a key was supplied and validated. */
21
+ export declare function getValidatedLicense(): LicenseInfo | null;
22
+ /** Always false — no memory cap. */
27
23
  export declare function isPro(): boolean;
28
- /** Memory count cap. -1 = unlimited (paid). */
24
+ /** Always -1 (unlimited). */
29
25
  export declare function maxMemoriesAllowed(): number;
30
- /** Has the memory cap been hit? Pass current count from caller. */
31
- export declare function memoryCapReached(currentCount: number): boolean;
32
- /** Number of lessons to inject into CLAUDE.md / before_agent_start. */
26
+ /** Always false no cap is ever reached. */
27
+ export declare function memoryCapReached(_currentCount: number): boolean;
28
+ /** Always 20. */
33
29
  export declare function lessonsLimit(): number;
34
- /** Is remote /ingest allowed? Free + Team yes, Pro (single-machine) no. */
30
+ /** Always true — remote ingest is always allowed. */
35
31
  export declare function remoteIngestAllowed(): boolean;
36
- /** Direct read of the underlying features (for callers that need the full record). */
32
+ /** Direct read of the underlying features record. */
37
33
  export declare function getCurrentFeatures(): LicenseInfo["features"];