@gamaze/hicortex 0.17.5 → 0.18.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 (51) hide show
  1. package/README.md +26 -25
  2. package/assets/dashboard.html +121 -5
  3. package/assets/{context.html → identity.html} +18 -18
  4. package/assets/viz.html +19 -7
  5. package/dist/claude-md.d.ts +2 -1
  6. package/dist/claude-md.js +2 -1
  7. package/dist/cli-args.d.ts +9 -0
  8. package/dist/cli-args.js +16 -0
  9. package/dist/cli.js +29 -20
  10. package/dist/consolidate.d.ts +15 -0
  11. package/dist/consolidate.js +30 -3
  12. package/dist/dashboard.d.ts +58 -1
  13. package/dist/dashboard.js +27 -1
  14. package/dist/extensions.d.ts +1 -1
  15. package/dist/extensions.js +1 -1
  16. package/dist/health.d.ts +68 -0
  17. package/dist/health.js +73 -0
  18. package/dist/identity-cli.d.ts +90 -0
  19. package/dist/{context-cli.js → identity-cli.js} +66 -48
  20. package/dist/{context-store.d.ts → identity-store.d.ts} +94 -31
  21. package/dist/{context-store.js → identity-store.js} +212 -71
  22. package/dist/index.d.ts +12 -5
  23. package/dist/index.js +57 -29
  24. package/dist/init.d.ts +44 -8
  25. package/dist/init.js +142 -37
  26. package/dist/{lessons-context.d.ts → learnings-identity.d.ts} +32 -21
  27. package/dist/{lessons-context.js → learnings-identity.js} +50 -39
  28. package/dist/mcp-server.d.ts +2 -0
  29. package/dist/mcp-server.js +168 -58
  30. package/dist/memory-instructions.d.ts +6 -6
  31. package/dist/memory-instructions.js +6 -6
  32. package/dist/nightly.js +65 -6
  33. package/dist/paths.js +1 -1
  34. package/dist/recall-hook-cli.d.ts +1 -1
  35. package/dist/recall-hook-cli.js +3 -3
  36. package/dist/recall-index.js +5 -2
  37. package/dist/status.d.ts +2 -2
  38. package/dist/status.js +11 -9
  39. package/dist/telemetry.d.ts +10 -0
  40. package/dist/type-classify.d.ts +13 -9
  41. package/dist/type-classify.js +26 -12
  42. package/dist/type-labels.d.ts +30 -0
  43. package/dist/type-labels.js +43 -0
  44. package/dist/types.d.ts +28 -0
  45. package/dist/uninstall.d.ts +12 -0
  46. package/dist/uninstall.js +21 -3
  47. package/dist/viz.d.ts +24 -11
  48. package/dist/viz.js +97 -32
  49. package/hermes-plugin/hicortex/README.md +4 -2
  50. package/package.json +2 -2
  51. package/dist/context-cli.d.ts +0 -69
@@ -1,32 +1,37 @@
1
1
  /**
2
- * lessons-context — query-time context injection for the CC SessionStart hook.
2
+ * learnings-identity — query-time identity + lessons injection for the CC
3
+ * SessionStart hook. (Canonical command name `learnings-identity` since #264;
4
+ * the legacy `lessons-context` subcommand is kept as a backcompat alias via
5
+ * resolveCommandAlias so existing installed hooks keep working. Fetches the
6
+ * identity layer + the lessons block.)
3
7
  *
4
8
  * Replaces file-based injection (injectLessons / injectLessonsFromServer).
5
9
  * Reads ~/.hicortex/config.json to find the server URL, then fetches TWO
6
10
  * endpoints concurrently and prints a compact Markdown block to stdout so CC
7
11
  * picks it up as session context:
8
12
  *
9
- * GET /context → the standing context layer (user info + rules; 0.12).
10
- * Injected as a `## Context` block ONLY when this harness
11
- * ("cc") is in the server-resolved `clients` list (self-gate).
13
+ * GET /identity → the standing identity layer (user info + rules; 0.12,
14
+ * renamed from /context in 0.18 #264). Injected as a
15
+ * `## Identity` block ONLY when this harness ("cc") is in
16
+ * the server-resolved `clients` list (self-gate).
12
17
  * GET /lessons → episodic memory lessons + memory index, rendered as the
13
18
  * existing `## Hicortex Memory` block.
14
19
  *
15
20
  * The two fetches run in Promise.all, each with its OWN 3 s timeout and
16
- * INDEPENDENT fail-soft: a /context failure must never cost the lessons block,
17
- * and vice versa. Sequential fetches would double worst-case SessionStart
18
- * latency (~6 s) — see spec §7.
21
+ * INDEPENDENT fail-soft: an /identity failure must never cost the lessons
22
+ * block, and vice versa. Sequential fetches would double worst-case
23
+ * SessionStart latency (~6 s) — see spec §7.
19
24
  *
20
25
  * Fail-soft by design: ANY failure (missing config, network error, non-2xx,
21
26
  * parse error) results in silent exit-0. A broken hook must never block a
22
- * CC session, and a broken /context fetch must never blank the whole output.
27
+ * CC session, and a broken /identity fetch must never blank the whole output.
23
28
  */
24
29
  /**
25
- * The GET /context response shape, shared by the CC hook and the OC plugin so
30
+ * The GET /identity response shape, shared by the CC hook and the OC plugin so
26
31
  * their gating cannot drift. `agent`/`mode` are echoed by a 0.13 server whenever
27
32
  * `?agent=` was sent (in EVERY mode); a pre-0.13 server omits them.
28
33
  */
29
- export interface ContextResponse {
34
+ export interface IdentityResponse {
30
35
  sections?: Record<string, string>;
31
36
  updated_at?: string;
32
37
  clients?: string[];
@@ -37,7 +42,7 @@ export interface ResolvedConfig {
37
42
  serverUrl: string;
38
43
  authToken: string | undefined;
39
44
  home: string;
40
- /** Per-agent context id sent as ?agent= (0.13); null → global (no param). */
45
+ /** Per-agent identity id sent as ?agent= (0.13); null → global (no param). */
41
46
  agentName: string | null;
42
47
  /** Max lessons to inject (config.lessonsLimit, default 10). */
43
48
  lessonsLimit?: number;
@@ -52,7 +57,7 @@ export declare function resolveConfig(): ResolvedConfig | null;
52
57
  /**
53
58
  * Title-case a section name for its heading: split on `-`/`_`, capitalize each
54
59
  * word ("user" → "User", "my_notes" → "My Notes").
55
- * Exported so the OC plugin (index.ts) renders the `## Context` block
60
+ * Exported so the OC plugin (index.ts) renders the `## Identity` block
56
61
  * identically to the CC hook rather than duplicating the logic.
57
62
  */
58
63
  export declare function titleCaseSection(name: string): string;
@@ -64,15 +69,15 @@ export declare function titleCaseSection(name: string): string;
64
69
  */
65
70
  export declare function orderSectionNames(names: string[]): string[];
66
71
  /**
67
- * Render the `## Context` block from a resolved section map, or null when there
72
+ * Render the `## Identity` block from a resolved section map, or null when there
68
73
  * is nothing to inject (no sections, or every section blank after trimming).
69
74
  * Pure — no gating, no I/O. Shared verbatim by the CC hook and the OC plugin so
70
75
  * both harnesses emit an identical block. Sections are ordered (user, rules,
71
76
  * then alphabetical) and rendered under title-cased `###` headings.
72
77
  */
73
- export declare function renderContextBlock(sections: Record<string, string>): string | null;
78
+ export declare function renderIdentityBlock(sections: Record<string, string>): string | null;
74
79
  /**
75
- * Gate a GET /context response and render the `## Context` block, or null when
80
+ * Gate a GET /identity response and render the `## Identity` block, or null when
76
81
  * nothing should be injected: `harness` not in the server-resolved `clients`,
77
82
  * an empty/blank section set, or — when `requireAgentEcho` — a response that
78
83
  * does not echo `agent`. The SINGLE gate used by both CC and OC so the two can
@@ -81,22 +86,28 @@ export declare function renderContextBlock(sections: Record<string, string>): st
81
86
  *
82
87
  * `requireAgentEcho` is the old-server guard, and it is the CALLER's decision:
83
88
  * - OC passes `agentId !== null` — when it actually sent an id, a 0.12 server
84
- * that ignores `?agent=` (200 global, no echo) must NOT leak global context
89
+ * that ignores `?agent=` (200 global, no echo) must NOT leak global identity
85
90
  * into every persona; on a bare fetch (no id) the guard is off (amendment
86
91
  * A2).
87
92
  * - CC passes `false` ALWAYS and deliberately (see the call site): a thin CC
88
93
  * client auto-upgrades via npx BEFORE the server does, so during the upgrade
89
94
  * window it talks to a 0.12 server that cannot hold ANY per-agent config —
90
95
  * global IS the operator's intended state there, and a guard would instead
91
- * blank ALL context for every CC session in that window.
96
+ * blank ALL identity for every CC session in that window.
92
97
  */
93
- export declare function gateAndRenderContext(data: ContextResponse, harness: string, opts: {
98
+ export declare function gateAndRenderIdentity(data: IdentityResponse, harness: string, opts: {
94
99
  requireAgentEcho: boolean;
95
100
  }): string | null;
96
101
  /**
97
- * Fetch context + lessons concurrently and return the combined Markdown block,
102
+ * Fetch identity + lessons concurrently and return the combined Markdown block,
98
103
  * or null when neither yields anything (nothing to inject; caller prints
99
- * nothing and exits 0). The `## Context` block is prepended before the existing
104
+ * nothing and exits 0). The `## Identity` block is prepended before the existing
100
105
  * `## Hicortex Memory` block.
101
106
  */
102
- export declare function fetchLessonsContext(): Promise<string | null>;
107
+ export declare function fetchLessonsIdentity(): Promise<string | null>;
108
+ /** Backcompat alias (#264). */
109
+ export declare const fetchLessonsContext: typeof fetchLessonsIdentity;
110
+ /** Backcompat aliases (#264) for the renamed symbols. */
111
+ export declare const renderContextBlock: typeof renderIdentityBlock;
112
+ export declare const gateAndRenderContext: typeof gateAndRenderIdentity;
113
+ export type ContextResponse = IdentityResponse;
@@ -1,43 +1,49 @@
1
1
  "use strict";
2
2
  /**
3
- * lessons-context — query-time context injection for the CC SessionStart hook.
3
+ * learnings-identity — query-time identity + lessons injection for the CC
4
+ * SessionStart hook. (Canonical command name `learnings-identity` since #264;
5
+ * the legacy `lessons-context` subcommand is kept as a backcompat alias via
6
+ * resolveCommandAlias so existing installed hooks keep working. Fetches the
7
+ * identity layer + the lessons block.)
4
8
  *
5
9
  * Replaces file-based injection (injectLessons / injectLessonsFromServer).
6
10
  * Reads ~/.hicortex/config.json to find the server URL, then fetches TWO
7
11
  * endpoints concurrently and prints a compact Markdown block to stdout so CC
8
12
  * picks it up as session context:
9
13
  *
10
- * GET /context → the standing context layer (user info + rules; 0.12).
11
- * Injected as a `## Context` block ONLY when this harness
12
- * ("cc") is in the server-resolved `clients` list (self-gate).
14
+ * GET /identity → the standing identity layer (user info + rules; 0.12,
15
+ * renamed from /context in 0.18 #264). Injected as a
16
+ * `## Identity` block ONLY when this harness ("cc") is in
17
+ * the server-resolved `clients` list (self-gate).
13
18
  * GET /lessons → episodic memory lessons + memory index, rendered as the
14
19
  * existing `## Hicortex Memory` block.
15
20
  *
16
21
  * The two fetches run in Promise.all, each with its OWN 3 s timeout and
17
- * INDEPENDENT fail-soft: a /context failure must never cost the lessons block,
18
- * and vice versa. Sequential fetches would double worst-case SessionStart
19
- * latency (~6 s) — see spec §7.
22
+ * INDEPENDENT fail-soft: an /identity failure must never cost the lessons
23
+ * block, and vice versa. Sequential fetches would double worst-case
24
+ * SessionStart latency (~6 s) — see spec §7.
20
25
  *
21
26
  * Fail-soft by design: ANY failure (missing config, network error, non-2xx,
22
27
  * parse error) results in silent exit-0. A broken hook must never block a
23
- * CC session, and a broken /context fetch must never blank the whole output.
28
+ * CC session, and a broken /identity fetch must never blank the whole output.
24
29
  */
25
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.gateAndRenderContext = exports.renderContextBlock = exports.fetchLessonsContext = void 0;
26
32
  exports.resolveConfig = resolveConfig;
27
33
  exports.titleCaseSection = titleCaseSection;
28
34
  exports.orderSectionNames = orderSectionNames;
29
- exports.renderContextBlock = renderContextBlock;
30
- exports.gateAndRenderContext = gateAndRenderContext;
31
- exports.fetchLessonsContext = fetchLessonsContext;
35
+ exports.renderIdentityBlock = renderIdentityBlock;
36
+ exports.gateAndRenderIdentity = gateAndRenderIdentity;
37
+ exports.fetchLessonsIdentity = fetchLessonsIdentity;
32
38
  const node_fs_1 = require("node:fs");
33
39
  const node_path_1 = require("node:path");
34
- const context_store_js_1 = require("./context-store.js");
40
+ const identity_store_js_1 = require("./identity-store.js");
35
41
  const features_js_1 = require("./features.js");
36
42
  const extensions_js_1 = require("./extensions.js");
37
43
  const state_js_1 = require("./state.js");
38
44
  const paths_js_1 = require("./paths.js");
39
45
  const DEFAULT_PORT = 8787;
40
- /** Harness name this hook injects for — used to self-gate on GET /context `clients`. */
46
+ /** Harness name this hook injects for — used to self-gate on GET /identity `clients`. */
41
47
  const THIS_HARNESS = "cc";
42
48
  /**
43
49
  * Read ~/.hicortex/config.json and resolve the server URL + auth token, or
@@ -58,12 +64,12 @@ function resolveConfig() {
58
64
  const serverUrl = config.mode === "client" && typeof config.serverUrl === "string"
59
65
  ? config.serverUrl.replace(/\/+$/, "")
60
66
  : `http://127.0.0.1:${config.port ?? DEFAULT_PORT}`;
61
- // Per-agent context id (0.13) via the shared resolver, so the id sent here
67
+ // Per-agent identity id (0.13) via the shared resolver, so the id sent here
62
68
  // always matches what `hicortex status` reports. No configured agentName →
63
69
  // agentId null → NO ?agent= (bare fetch): CC's default is the shared global
64
- // context. A configured agentName that sanitizes to null → agentId null too
70
+ // identity. A configured agentName that sanitizes to null → agentId null too
65
71
  // (NO ?agent=), never a 400 that the fail-soft hook would silently swallow.
66
- const agentName = (0, context_store_js_1.resolveAgentIdentity)(config).agentId;
72
+ const agentName = (0, identity_store_js_1.resolveAgentIdentity)(config).agentId;
67
73
  return {
68
74
  serverUrl,
69
75
  authToken: config.authToken,
@@ -133,7 +139,7 @@ async function fetchLessonsBlock(cfg) {
133
139
  /**
134
140
  * Title-case a section name for its heading: split on `-`/`_`, capitalize each
135
141
  * word ("user" → "User", "my_notes" → "My Notes").
136
- * Exported so the OC plugin (index.ts) renders the `## Context` block
142
+ * Exported so the OC plugin (index.ts) renders the `## Identity` block
137
143
  * identically to the CC hook rather than duplicating the logic.
138
144
  */
139
145
  function titleCaseSection(name) {
@@ -155,13 +161,13 @@ function orderSectionNames(names) {
155
161
  return [...primaries, ...rest];
156
162
  }
157
163
  /**
158
- * Render the `## Context` block from a resolved section map, or null when there
164
+ * Render the `## Identity` block from a resolved section map, or null when there
159
165
  * is nothing to inject (no sections, or every section blank after trimming).
160
166
  * Pure — no gating, no I/O. Shared verbatim by the CC hook and the OC plugin so
161
167
  * both harnesses emit an identical block. Sections are ordered (user, rules,
162
168
  * then alphabetical) and rendered under title-cased `###` headings.
163
169
  */
164
- function renderContextBlock(sections) {
170
+ function renderIdentityBlock(sections) {
165
171
  if (!sections || typeof sections !== "object" || Array.isArray(sections))
166
172
  return null;
167
173
  const names = orderSectionNames(Object.keys(sections));
@@ -174,10 +180,10 @@ function renderContextBlock(sections) {
174
180
  }
175
181
  if (bodyParts.length === 0)
176
182
  return null;
177
- return ["## Context", "", ...bodyParts].join("\n");
183
+ return ["## Identity", "", ...bodyParts].join("\n");
178
184
  }
179
185
  /**
180
- * Gate a GET /context response and render the `## Context` block, or null when
186
+ * Gate a GET /identity response and render the `## Identity` block, or null when
181
187
  * nothing should be injected: `harness` not in the server-resolved `clients`,
182
188
  * an empty/blank section set, or — when `requireAgentEcho` — a response that
183
189
  * does not echo `agent`. The SINGLE gate used by both CC and OC so the two can
@@ -186,16 +192,16 @@ function renderContextBlock(sections) {
186
192
  *
187
193
  * `requireAgentEcho` is the old-server guard, and it is the CALLER's decision:
188
194
  * - OC passes `agentId !== null` — when it actually sent an id, a 0.12 server
189
- * that ignores `?agent=` (200 global, no echo) must NOT leak global context
195
+ * that ignores `?agent=` (200 global, no echo) must NOT leak global identity
190
196
  * into every persona; on a bare fetch (no id) the guard is off (amendment
191
197
  * A2).
192
198
  * - CC passes `false` ALWAYS and deliberately (see the call site): a thin CC
193
199
  * client auto-upgrades via npx BEFORE the server does, so during the upgrade
194
200
  * window it talks to a 0.12 server that cannot hold ANY per-agent config —
195
201
  * global IS the operator's intended state there, and a guard would instead
196
- * blank ALL context for every CC session in that window.
202
+ * blank ALL identity for every CC session in that window.
197
203
  */
198
- function gateAndRenderContext(data, harness, opts) {
204
+ function gateAndRenderIdentity(data, harness, opts) {
199
205
  if (!data || typeof data !== "object")
200
206
  return null;
201
207
  const clients = Array.isArray(data.clients) ? data.clients : [];
@@ -203,21 +209,21 @@ function gateAndRenderContext(data, harness, opts) {
203
209
  return null;
204
210
  if (opts.requireAgentEcho && typeof data.agent !== "string")
205
211
  return null;
206
- return renderContextBlock(data.sections ?? {});
212
+ return renderIdentityBlock(data.sections ?? {});
207
213
  }
208
214
  /**
209
- * Fetch /context and build the `## Context` block, or null when nothing should
215
+ * Fetch /identity and build the `## Identity` block, or null when nothing should
210
216
  * be injected: non-2xx, this harness not in `clients`, no sections, or all
211
217
  * sections empty. Throws propagate to the caller's fail-soft catch.
212
218
  */
213
- async function fetchContextBlock(cfg) {
219
+ async function fetchIdentityBlock(cfg) {
214
220
  // Send ?agent= only when we have a valid id; the server does the merge and
215
221
  // returns the resolved sections, so the hook stays dumb (no client-side mode
216
222
  // logic). A null id (CC's default: no configured agentName, or a configured
217
- // value that sanitizes to nothing) → bare /context → the shared global set.
223
+ // value that sanitizes to nothing) → bare /identity → the shared global set.
218
224
  const url = cfg.agentName
219
- ? `${cfg.serverUrl}/context?agent=${encodeURIComponent(cfg.agentName)}`
220
- : `${cfg.serverUrl}/context`;
225
+ ? `${cfg.serverUrl}/identity?agent=${encodeURIComponent(cfg.agentName)}`
226
+ : `${cfg.serverUrl}/identity`;
221
227
  const resp = await fetch(url, {
222
228
  headers: authHeaders(cfg.authToken),
223
229
  signal: AbortSignal.timeout(3000),
@@ -227,30 +233,35 @@ async function fetchContextBlock(cfg) {
227
233
  const data = await resp.json();
228
234
  // CC deliberately passes requireAgentEcho: false (NOT the OC/Hermes old-server
229
235
  // guard). A thin CC client auto-upgrades via npx BEFORE the server does, so
230
- // mid-upgrade it may hit a 0.12 server that returns global context with no
236
+ // mid-upgrade it may hit a 0.12 server that returns global identity with no
231
237
  // `agent` echo — and a 0.12 server cannot hold per-agent config, so global is
232
- // the intended state. Guarding here would blank ALL CC context in that window.
233
- return gateAndRenderContext(data, THIS_HARNESS, { requireAgentEcho: false });
238
+ // the intended state. Guarding here would blank ALL CC identity in that window.
239
+ return gateAndRenderIdentity(data, THIS_HARNESS, { requireAgentEcho: false });
234
240
  }
235
241
  /**
236
- * Fetch context + lessons concurrently and return the combined Markdown block,
242
+ * Fetch identity + lessons concurrently and return the combined Markdown block,
237
243
  * or null when neither yields anything (nothing to inject; caller prints
238
- * nothing and exits 0). The `## Context` block is prepended before the existing
244
+ * nothing and exits 0). The `## Identity` block is prepended before the existing
239
245
  * `## Hicortex Memory` block.
240
246
  */
241
- async function fetchLessonsContext() {
247
+ async function fetchLessonsIdentity() {
242
248
  const cfg = resolveConfig();
243
249
  if (!cfg)
244
250
  return null;
245
251
  // Independent fail-soft: each branch degrades to null without affecting the
246
252
  // other. Promise.all runs them concurrently — each carries its own 3 s
247
253
  // timeout, so worst-case latency stays ~3 s, not ~6 s (spec §7).
248
- const [contextBlock, lessonsBlock] = await Promise.all([
249
- fetchContextBlock(cfg).catch(() => null),
254
+ const [identityBlock, lessonsBlock] = await Promise.all([
255
+ fetchIdentityBlock(cfg).catch(() => null),
250
256
  fetchLessonsBlock(cfg).catch(() => null),
251
257
  ]);
252
- const blocks = [contextBlock, lessonsBlock].filter((b) => b !== null && b !== "");
258
+ const blocks = [identityBlock, lessonsBlock].filter((b) => b !== null && b !== "");
253
259
  if (blocks.length === 0)
254
260
  return null;
255
261
  return blocks.join("\n\n");
256
262
  }
263
+ /** Backcompat alias (#264). */
264
+ exports.fetchLessonsContext = fetchLessonsIdentity;
265
+ /** Backcompat aliases (#264) for the renamed symbols. */
266
+ exports.renderContextBlock = renderIdentityBlock;
267
+ exports.gateAndRenderContext = gateAndRenderIdentity;
@@ -10,9 +10,11 @@
10
10
  * GET /sse — SSE stream for MCP clients
11
11
  * POST /messages — message endpoint for MCP clients
12
12
  */
13
+ import type { MemorySearchResult } from "./types.js";
13
14
  export declare function startServer(options?: {
14
15
  port?: number;
15
16
  host?: string;
16
17
  dbPath?: string;
17
18
  licenseKey?: string;
18
19
  }): Promise<void>;
20
+ export declare function formatResults(results: MemorySearchResult[]): string;