@gamaze/hicortex 0.17.6 → 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.
- package/README.md +26 -25
- package/assets/dashboard.html +121 -5
- package/assets/{context.html → identity.html} +18 -18
- package/assets/viz.html +19 -7
- package/dist/claude-md.d.ts +2 -1
- package/dist/claude-md.js +2 -1
- package/dist/cli-args.d.ts +9 -0
- package/dist/cli-args.js +16 -0
- package/dist/cli.js +29 -20
- package/dist/consolidate.d.ts +15 -0
- package/dist/consolidate.js +30 -3
- package/dist/dashboard.d.ts +58 -1
- package/dist/dashboard.js +27 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/health.d.ts +68 -0
- package/dist/health.js +73 -0
- package/dist/identity-cli.d.ts +90 -0
- package/dist/{context-cli.js → identity-cli.js} +66 -48
- package/dist/{context-store.d.ts → identity-store.d.ts} +94 -31
- package/dist/{context-store.js → identity-store.js} +212 -71
- package/dist/index.d.ts +12 -5
- package/dist/index.js +57 -29
- package/dist/init.d.ts +44 -8
- package/dist/init.js +142 -37
- package/dist/{lessons-context.d.ts → learnings-identity.d.ts} +32 -21
- package/dist/{lessons-context.js → learnings-identity.js} +50 -39
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +168 -58
- package/dist/memory-instructions.d.ts +6 -6
- package/dist/memory-instructions.js +6 -6
- package/dist/nightly.js +65 -6
- package/dist/paths.js +1 -1
- package/dist/recall-hook-cli.d.ts +1 -1
- package/dist/recall-hook-cli.js +3 -3
- package/dist/recall-index.js +5 -2
- package/dist/status.d.ts +2 -2
- package/dist/status.js +11 -9
- package/dist/telemetry.d.ts +10 -0
- package/dist/type-classify.js +4 -1
- package/dist/type-labels.d.ts +30 -0
- package/dist/type-labels.js +43 -0
- package/dist/types.d.ts +28 -0
- package/dist/uninstall.d.ts +12 -0
- package/dist/uninstall.js +21 -3
- package/dist/viz.d.ts +24 -11
- package/dist/viz.js +97 -32
- package/hermes-plugin/hicortex/README.md +4 -2
- package/package.json +2 -2
- package/dist/context-cli.d.ts +0 -69
package/dist/paths.js
CHANGED
|
@@ -8,7 +8,7 @@ exports.hicortexHome = hicortexHome;
|
|
|
8
8
|
* HICORTEX_DB_PATH convention in db.ts); otherwise defaults to ~/.hicortex.
|
|
9
9
|
* Every module that needs the home dir routes through here, so the override
|
|
10
10
|
* behaves consistently across all commands instead of being honored by some
|
|
11
|
-
* (
|
|
11
|
+
* (identity-cli, learnings-identity) and hardcoded away by others.
|
|
12
12
|
*/
|
|
13
13
|
const node_os_1 = require("node:os");
|
|
14
14
|
const node_path_1 = require("node:path");
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - SessionStart (startup/resume/clear/compact): POST a reset so the
|
|
9
9
|
* server's per-session shown-set matches the fresh context window.
|
|
10
10
|
*
|
|
11
|
-
* Fail-soft like
|
|
11
|
+
* Fail-soft like learnings-identity: ANY failure (no config, timeout, non-2xx,
|
|
12
12
|
* parse error) prints nothing and exits 0 — a broken hook must never block or
|
|
13
13
|
* slow a CC session beyond the fetch timeout (1000 ms, owner-set).
|
|
14
14
|
*/
|
package/dist/recall-hook-cli.js
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* - SessionStart (startup/resume/clear/compact): POST a reset so the
|
|
10
10
|
* server's per-session shown-set matches the fresh context window.
|
|
11
11
|
*
|
|
12
|
-
* Fail-soft like
|
|
12
|
+
* Fail-soft like learnings-identity: ANY failure (no config, timeout, non-2xx,
|
|
13
13
|
* parse error) prints nothing and exits 0 — a broken hook must never block or
|
|
14
14
|
* slow a CC session beyond the fetch timeout (1000 ms, owner-set).
|
|
15
15
|
*/
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.buildHookRequest = buildHookRequest;
|
|
18
18
|
exports.runRecallHook = runRecallHook;
|
|
19
|
-
const
|
|
19
|
+
const learnings_identity_js_1 = require("./learnings-identity.js");
|
|
20
20
|
const node_path_1 = require("node:path");
|
|
21
21
|
const FETCH_TIMEOUT_MS = 1000;
|
|
22
22
|
/** Read all of stdin (CC pipes the hook payload JSON). */
|
|
@@ -51,7 +51,7 @@ function buildHookRequest(payload, cwd = process.cwd()) {
|
|
|
51
51
|
return { session_id: sessionId, prompt, project: (0, node_path_1.basename)(cwd) };
|
|
52
52
|
}
|
|
53
53
|
async function runRecallHook() {
|
|
54
|
-
const cfg = (0,
|
|
54
|
+
const cfg = (0, learnings_identity_js_1.resolveConfig)();
|
|
55
55
|
if (!cfg)
|
|
56
56
|
return;
|
|
57
57
|
let payload;
|
package/dist/recall-index.js
CHANGED
|
@@ -62,6 +62,7 @@ exports.handleRecallIndex = handleRecallIndex;
|
|
|
62
62
|
exports.handleMemoryGet = handleMemoryGet;
|
|
63
63
|
exports.formatMemoryGetText = formatMemoryGetText;
|
|
64
64
|
const storage = __importStar(require("./storage.js"));
|
|
65
|
+
const type_labels_js_1 = require("./type-labels.js");
|
|
65
66
|
/** Relevance-gate floor for vector-only candidates (config `recallMinSimilarity`).
|
|
66
67
|
* 0.62 (was 0.55; raised 2026-08-03 on the fine-grain floor sweep — see the
|
|
67
68
|
* minSimilarity doc above). */
|
|
@@ -116,7 +117,7 @@ function formatIndexLine(r, maxLen = DEFAULT_TITLE_CHARS) {
|
|
|
116
117
|
formatDate(r.created_at),
|
|
117
118
|
r.domain ?? r.project ?? undefined,
|
|
118
119
|
r.source_agent ?? undefined,
|
|
119
|
-
r.memory_type,
|
|
120
|
+
(0, type_labels_js_1.labelForType)(r.memory_type),
|
|
120
121
|
]
|
|
121
122
|
.filter(Boolean)
|
|
122
123
|
.join(", ");
|
|
@@ -281,7 +282,9 @@ function formatMemoryGetText(db, query) {
|
|
|
281
282
|
const mem = r.body.memory;
|
|
282
283
|
const citation = r.body.citation; // carries FETCHED (#204)
|
|
283
284
|
const date = (mem.created_at ?? "").slice(0, 10);
|
|
284
|
-
|
|
285
|
+
// #264 WS2: render the human-term label (Knowledge/Experience/...), not the
|
|
286
|
+
// internal enum, in the citation header shown to the agent/user.
|
|
287
|
+
const header = `[memory ${mem.id} | ${(0, type_labels_js_1.labelForType)(mem.memory_type ?? "episode")} | ${mem.project ?? "-"} | from ${mem.source_agent ?? "unknown"} | ${date}]\n` +
|
|
285
288
|
`Cite as ${citation} where this shapes your answer; it may be stale — newer memories supersede older.`;
|
|
286
289
|
return { status: 200, text: `${header}\n\n${mem.content ?? ""}` };
|
|
287
290
|
}
|
package/dist/status.d.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* The value shown after "Agent name:" in `hicortex status` (#179, A3). Reports
|
|
6
6
|
* EXACTLY what the CC hook resolves (shared `resolveAgentIdentity`), so the
|
|
7
|
-
* operator never keys `
|
|
7
|
+
* operator never keys `identityAgents`/`agents/<id>/` on an id the install does
|
|
8
8
|
* not actually send. Unset → the install sends no `?agent=` and shares the
|
|
9
|
-
* global
|
|
9
|
+
* global identity (CC default). A configured-but-unsanitizable value is called
|
|
10
10
|
* out as invalid (the hook sends none) rather than silently accepted.
|
|
11
11
|
*/
|
|
12
12
|
export declare function statusAgentLine(config: Record<string, unknown>): string;
|
package/dist/status.js
CHANGED
|
@@ -13,27 +13,27 @@ const node_child_process_1 = require("node:child_process");
|
|
|
13
13
|
const db_js_1 = require("./db.js");
|
|
14
14
|
const features_js_1 = require("./features.js");
|
|
15
15
|
const state_js_1 = require("./state.js");
|
|
16
|
-
const
|
|
16
|
+
const identity_store_js_1 = require("./identity-store.js");
|
|
17
17
|
const HICORTEX_HOME = (0, paths_js_1.hicortexHome)();
|
|
18
18
|
const CC_SETTINGS = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude", "settings.json");
|
|
19
19
|
const OC_CONFIG = (0, node_path_1.join)((0, node_os_1.homedir)(), ".openclaw", "openclaw.json");
|
|
20
20
|
/**
|
|
21
21
|
* The value shown after "Agent name:" in `hicortex status` (#179, A3). Reports
|
|
22
22
|
* EXACTLY what the CC hook resolves (shared `resolveAgentIdentity`), so the
|
|
23
|
-
* operator never keys `
|
|
23
|
+
* operator never keys `identityAgents`/`agents/<id>/` on an id the install does
|
|
24
24
|
* not actually send. Unset → the install sends no `?agent=` and shares the
|
|
25
|
-
* global
|
|
25
|
+
* global identity (CC default). A configured-but-unsanitizable value is called
|
|
26
26
|
* out as invalid (the hook sends none) rather than silently accepted.
|
|
27
27
|
*/
|
|
28
28
|
function statusAgentLine(config) {
|
|
29
|
-
const id = (0,
|
|
29
|
+
const id = (0, identity_store_js_1.resolveAgentIdentity)(config);
|
|
30
30
|
switch (id.source) {
|
|
31
31
|
case "configured":
|
|
32
32
|
return id.agentId;
|
|
33
33
|
case "invalid-config":
|
|
34
34
|
return `(invalid configured value "${id.rawConfigured}" — fix config.agentName; hook sends none)`;
|
|
35
35
|
default: // unset
|
|
36
|
-
return "(not set — global
|
|
36
|
+
return "(not set — global identity)";
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
async function runStatus() {
|
|
@@ -87,8 +87,8 @@ async function runStatus() {
|
|
|
87
87
|
else if (!isClientMode && !savedAuthToken) {
|
|
88
88
|
console.log(`Auth token: not configured (run: npx @gamaze/hicortex init)`);
|
|
89
89
|
}
|
|
90
|
-
// Per-agent
|
|
91
|
-
// key operators use for
|
|
90
|
+
// Per-agent identity id (#179) — the id this install sends as ?agent= and the
|
|
91
|
+
// key operators use for identityAgents / agents/<id>/ dirs.
|
|
92
92
|
console.log(`Agent name: ${statusAgentLine(parsedConfig)}`);
|
|
93
93
|
console.log();
|
|
94
94
|
// Adapters
|
|
@@ -119,11 +119,13 @@ async function runStatus() {
|
|
|
119
119
|
catch { /* no CC settings */ }
|
|
120
120
|
console.log(` CC MCP: ${ccRegistered ? `registered → ${ccUrl}` : "not registered"}`);
|
|
121
121
|
console.log();
|
|
122
|
-
// Server status
|
|
122
|
+
// Server status. /health/detail carries the diagnostics (version, memories,
|
|
123
|
+
// llm) — /health itself is the public minimal {status:"ok"} probe (#253).
|
|
124
|
+
// localhost bypasses auth, so on-box `hicortex status` gets the fields.
|
|
123
125
|
console.log("Server:");
|
|
124
126
|
let serverRunning = false;
|
|
125
127
|
try {
|
|
126
|
-
const resp = await fetch("http://127.0.0.1:8787/health", {
|
|
128
|
+
const resp = await fetch("http://127.0.0.1:8787/health/detail", {
|
|
127
129
|
signal: AbortSignal.timeout(2000),
|
|
128
130
|
});
|
|
129
131
|
if (resp.ok) {
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -106,6 +106,16 @@ export interface TelemetryPayload {
|
|
|
106
106
|
* wire (that lives in the dashboard snapshot, not the telemetry ping).
|
|
107
107
|
*/
|
|
108
108
|
tokens_this_run?: number;
|
|
109
|
+
/**
|
|
110
|
+
* True when the per-tenant consolidation budget (`consolidateMaxLlmCalls`)
|
|
111
|
+
* was exhausted this run (#255) — LLM-bound stages deferred remaining work.
|
|
112
|
+
* A quality-degradation signal concentrated on heavy users; absent on a
|
|
113
|
+
* pre-#255 ping, a capture-only/no-LLM/throttled/skipped run, or when the
|
|
114
|
+
* budget was NOT exhausted (additive optional — the aggregate treats absent
|
|
115
|
+
* as "no exhaustion / not measurable"). Per-stage deferred counts live in
|
|
116
|
+
* the dashboard snapshot, not on the wire (mirrors `tokens_this_run`).
|
|
117
|
+
*/
|
|
118
|
+
budget_exhausted?: boolean;
|
|
109
119
|
}
|
|
110
120
|
/**
|
|
111
121
|
* Check if telemetry is enabled. Disabled by:
|
package/dist/type-classify.js
CHANGED
|
@@ -45,6 +45,7 @@ const node_path_1 = require("node:path");
|
|
|
45
45
|
const db_js_1 = require("./db.js");
|
|
46
46
|
const state_js_1 = require("./state.js");
|
|
47
47
|
const llm_js_1 = require("./llm.js");
|
|
48
|
+
const type_labels_js_1 = require("./type-labels.js");
|
|
48
49
|
const HICORTEX_HOME = (0, paths_js_1.hicortexHome)();
|
|
49
50
|
/** Max chars of memory content fed to the classify prompt. */
|
|
50
51
|
const CLASSIFY_CONTENT_MAX_CHARS = 1500;
|
|
@@ -293,7 +294,9 @@ async function runClassifyTypes(options = {}) {
|
|
|
293
294
|
.all();
|
|
294
295
|
for (const c of counts)
|
|
295
296
|
report.byType[c.memory_type] = c.cnt;
|
|
296
|
-
|
|
297
|
+
// #264 WS2: display the human-term label (Knowledge/Experience/...), not
|
|
298
|
+
// the internal enum — the operator reading the log sees human terms.
|
|
299
|
+
const breakdown = counts.map((c) => `${(0, type_labels_js_1.labelForType)(c.memory_type)}=${c.cnt}`).join(", ") || "none";
|
|
297
300
|
console.log(`[hicortex] classify-types ${report.aborted ? "ABORTED" : "complete"}: ` +
|
|
298
301
|
`${report.scanned} classified, ${report.reclassified} reclassified, ` +
|
|
299
302
|
`${report.unchanged} unchanged, ${report.failed} infra-skipped`);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-term labels for the internal `memory_type` enum (#264 WS2).
|
|
3
|
+
*
|
|
4
|
+
* The data model stores four types under unintuitive internal names
|
|
5
|
+
* (`fact` / `episode` / `decision` / `lesson`). Product-facing surfaces show
|
|
6
|
+
* the human terms instead — Knowledge / Experience / Decisions / Learnings —
|
|
7
|
+
* via this single label map. The enum values themselves are NEVER changed:
|
|
8
|
+
* no DB column, query, distiller tag, or storage path is altered. This is a
|
|
9
|
+
* DISPLAY rename only; every user-facing rendering routes through
|
|
10
|
+
* `labelForType`.
|
|
11
|
+
*
|
|
12
|
+
* Mapping (decided 2026-08-11, research/2026-08-11-identity-reframe-brainstorm.md):
|
|
13
|
+
* fact → Knowledge
|
|
14
|
+
* episode → Experience
|
|
15
|
+
* decision → Decisions
|
|
16
|
+
* lesson → Learnings
|
|
17
|
+
*
|
|
18
|
+
* Unknown / future types fall back to the raw value (never silently remapped).
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* The four documented memory types mapped to their human-term labels.
|
|
22
|
+
* Kept as a plain record so it can be iterated for coverage assertions.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MEMORY_TYPE_LABELS: Record<string, string>;
|
|
25
|
+
/**
|
|
26
|
+
* Return the human-term label for a `memory_type` enum value. Unknown or
|
|
27
|
+
* future types (including null/undefined) fall back to the raw input so new
|
|
28
|
+
* types are visible rather than silently mislabeled.
|
|
29
|
+
*/
|
|
30
|
+
export declare function labelForType(t: string | null | undefined): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Human-term labels for the internal `memory_type` enum (#264 WS2).
|
|
4
|
+
*
|
|
5
|
+
* The data model stores four types under unintuitive internal names
|
|
6
|
+
* (`fact` / `episode` / `decision` / `lesson`). Product-facing surfaces show
|
|
7
|
+
* the human terms instead — Knowledge / Experience / Decisions / Learnings —
|
|
8
|
+
* via this single label map. The enum values themselves are NEVER changed:
|
|
9
|
+
* no DB column, query, distiller tag, or storage path is altered. This is a
|
|
10
|
+
* DISPLAY rename only; every user-facing rendering routes through
|
|
11
|
+
* `labelForType`.
|
|
12
|
+
*
|
|
13
|
+
* Mapping (decided 2026-08-11, research/2026-08-11-identity-reframe-brainstorm.md):
|
|
14
|
+
* fact → Knowledge
|
|
15
|
+
* episode → Experience
|
|
16
|
+
* decision → Decisions
|
|
17
|
+
* lesson → Learnings
|
|
18
|
+
*
|
|
19
|
+
* Unknown / future types fall back to the raw value (never silently remapped).
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.MEMORY_TYPE_LABELS = void 0;
|
|
23
|
+
exports.labelForType = labelForType;
|
|
24
|
+
/**
|
|
25
|
+
* The four documented memory types mapped to their human-term labels.
|
|
26
|
+
* Kept as a plain record so it can be iterated for coverage assertions.
|
|
27
|
+
*/
|
|
28
|
+
exports.MEMORY_TYPE_LABELS = {
|
|
29
|
+
fact: "Knowledge",
|
|
30
|
+
episode: "Experience",
|
|
31
|
+
decision: "Decisions",
|
|
32
|
+
lesson: "Learnings",
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Return the human-term label for a `memory_type` enum value. Unknown or
|
|
36
|
+
* future types (including null/undefined) fall back to the raw input so new
|
|
37
|
+
* types are visible rather than silently mislabeled.
|
|
38
|
+
*/
|
|
39
|
+
function labelForType(t) {
|
|
40
|
+
if (!t)
|
|
41
|
+
return "—";
|
|
42
|
+
return exports.MEMORY_TYPE_LABELS[t] ?? t;
|
|
43
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -161,6 +161,26 @@ export interface ConsolidationReport {
|
|
|
161
161
|
calls_used: number;
|
|
162
162
|
calls_remaining: number;
|
|
163
163
|
calls_by_stage: Record<string, number>;
|
|
164
|
+
/**
|
|
165
|
+
* True when `calls_used >= max_calls` at run end (#255). The run continued
|
|
166
|
+
* to completion (no abort) but LLM-bound stages past the boundary deferred
|
|
167
|
+
* their remaining work — a quality-degradation signal, not a failure.
|
|
168
|
+
* Absent on pre-#255 reports; treat as false.
|
|
169
|
+
*/
|
|
170
|
+
exhausted?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Per-stage count of LLM-call REQUESTS refused because the budget was
|
|
173
|
+
* exhausted (#255). Keys are the same stage labels passed to
|
|
174
|
+
* `BudgetTracker.use()`. The value is the SUM of the `count` args passed
|
|
175
|
+
* to each refused `use()` call in that stage — in production every `use()`
|
|
176
|
+
* call passes count=1, so a stage present here with count N hit the
|
|
177
|
+
* boundary and had N further single-call requests denied (stages break on
|
|
178
|
+
* first refusal, so N is small per stage). For item-level "how many
|
|
179
|
+
* memories/pairs were skipped" see the per-stage reports (e.g.
|
|
180
|
+
* stages.importance.skipped_budget), which count MEMORIES not call
|
|
181
|
+
* requests. Absent on pre-#255 reports.
|
|
182
|
+
*/
|
|
183
|
+
deferred_by_stage?: Record<string, number>;
|
|
164
184
|
/**
|
|
165
185
|
* Token usage per stage (#246). Each value sums prompt + completion +
|
|
166
186
|
* total across every metered LLM call in that stage this run. A stage with
|
|
@@ -187,6 +207,14 @@ export interface HicortexConfig {
|
|
|
187
207
|
serverUrl?: string;
|
|
188
208
|
/** Bearer token for the Hicortex server. Localhost bypasses auth by default. */
|
|
189
209
|
authToken?: string;
|
|
210
|
+
/**
|
|
211
|
+
* Optional PRIOR bearer token kept around during rotation (#254). When set,
|
|
212
|
+
* BOTH `authToken` and `authTokenPrevious` are accepted (constant-time,
|
|
213
|
+
* zero-downtime rotation). Absent/empty → single-token behaviour. Rotate by
|
|
214
|
+
* writing the new value to `authToken` and the old value here, then later
|
|
215
|
+
* clearing this key once all clients have switched.
|
|
216
|
+
*/
|
|
217
|
+
authTokenPrevious?: string;
|
|
190
218
|
/**
|
|
191
219
|
* Stable per-install UUID generated by `init` (see ensureAgentId in init.ts;
|
|
192
220
|
* never rotated). Attribution identity of the capturing client — stored on
|
package/dist/uninstall.d.ts
CHANGED
|
@@ -2,4 +2,16 @@
|
|
|
2
2
|
* Hicortex uninstall — clean removal of CC integration.
|
|
3
3
|
* Preserves the database (user data).
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* Matches a CC SessionStart hook `command` that runs the Hicortex
|
|
7
|
+
* identity/learnings hook — the canonical `learnings-identity` (#264) OR the
|
|
8
|
+
* legacy `lessons-context` alias. Exported so the uninstall behavior (which
|
|
9
|
+
* name variants get cleaned up) is unit-testable without spinning up CC.
|
|
10
|
+
* Word-boundary guard so "learnings-identity" never matches a hypothetical
|
|
11
|
+
* "learnings-identity-foo", the two names stay distinct from each other, and
|
|
12
|
+
* neither collides with the sibling `recall-hook` SessionStart hook.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SESSION_START_HOOK_COMMAND_RE: RegExp;
|
|
15
|
+
/** True when a CC hook `command` string runs the Hicortex SessionStart hook. */
|
|
16
|
+
export declare function isHicortexSessionStartHook(command: string): boolean;
|
|
5
17
|
export declare function runUninstall(): Promise<void>;
|
package/dist/uninstall.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Preserves the database (user data).
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SESSION_START_HOOK_COMMAND_RE = void 0;
|
|
8
|
+
exports.isHicortexSessionStartHook = isHicortexSessionStartHook;
|
|
7
9
|
exports.runUninstall = runUninstall;
|
|
8
10
|
const paths_js_1 = require("./paths.js");
|
|
9
11
|
const node_fs_1 = require("node:fs");
|
|
@@ -17,6 +19,20 @@ const HICORTEX_HOME = (0, paths_js_1.hicortexHome)();
|
|
|
17
19
|
const CC_SETTINGS = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude", "settings.json");
|
|
18
20
|
const CC_COMMANDS_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude", "commands");
|
|
19
21
|
const CLAUDE_MD = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude", "CLAUDE.md");
|
|
22
|
+
/**
|
|
23
|
+
* Matches a CC SessionStart hook `command` that runs the Hicortex
|
|
24
|
+
* identity/learnings hook — the canonical `learnings-identity` (#264) OR the
|
|
25
|
+
* legacy `lessons-context` alias. Exported so the uninstall behavior (which
|
|
26
|
+
* name variants get cleaned up) is unit-testable without spinning up CC.
|
|
27
|
+
* Word-boundary guard so "learnings-identity" never matches a hypothetical
|
|
28
|
+
* "learnings-identity-foo", the two names stay distinct from each other, and
|
|
29
|
+
* neither collides with the sibling `recall-hook` SessionStart hook.
|
|
30
|
+
*/
|
|
31
|
+
exports.SESSION_START_HOOK_COMMAND_RE = /(^|\s)(?:learnings-identity|lessons-context)(\s|$)/;
|
|
32
|
+
/** True when a CC hook `command` string runs the Hicortex SessionStart hook. */
|
|
33
|
+
function isHicortexSessionStartHook(command) {
|
|
34
|
+
return typeof command === "string" && exports.SESSION_START_HOOK_COMMAND_RE.test(command);
|
|
35
|
+
}
|
|
20
36
|
async function ask(question) {
|
|
21
37
|
const rl = (0, node_readline_1.createInterface)({ input: process.stdin, output: process.stdout });
|
|
22
38
|
return new Promise((resolve) => {
|
|
@@ -130,7 +146,9 @@ async function runUninstall() {
|
|
|
130
146
|
}
|
|
131
147
|
if (removedCmds > 0)
|
|
132
148
|
console.log(` ✓ Removed ${removedCmds} legacy CC command${removedCmds > 1 ? "s" : ""} (/learn, /hicortex-activate)`);
|
|
133
|
-
// 4. Remove SessionStart hook (JSON merge — filter out entries containing
|
|
149
|
+
// 4. Remove SessionStart hook (JSON merge — filter out entries containing
|
|
150
|
+
// EITHER the canonical "learnings-identity" OR the legacy "lessons-context"
|
|
151
|
+
// alias, #264 backcompat: an install may have written either name.)
|
|
134
152
|
try {
|
|
135
153
|
const raw = (0, node_fs_1.readFileSync)(CC_SETTINGS, "utf-8");
|
|
136
154
|
const settings = JSON.parse(raw);
|
|
@@ -147,7 +165,7 @@ async function runUninstall() {
|
|
|
147
165
|
if (typeof h !== "object" || h === null)
|
|
148
166
|
return false;
|
|
149
167
|
const hook = h;
|
|
150
|
-
return typeof hook.command === "string" && hook.command
|
|
168
|
+
return typeof hook.command === "string" && isHicortexSessionStartHook(hook.command);
|
|
151
169
|
});
|
|
152
170
|
}
|
|
153
171
|
return true;
|
|
@@ -155,7 +173,7 @@ async function runUninstall() {
|
|
|
155
173
|
if (filtered.length < before) {
|
|
156
174
|
hooks.SessionStart = filtered;
|
|
157
175
|
(0, node_fs_1.writeFileSync)(CC_SETTINGS, JSON.stringify(settings, null, 2));
|
|
158
|
-
console.log(" ✓ Removed SessionStart
|
|
176
|
+
console.log(" ✓ Removed SessionStart learnings-identity hook");
|
|
159
177
|
}
|
|
160
178
|
}
|
|
161
179
|
}
|
package/dist/viz.d.ts
CHANGED
|
@@ -37,8 +37,16 @@ export declare const VIZ_VENDOR_FILES: ReadonlySet<string>;
|
|
|
37
37
|
* middleware before this runs). With no token configured, remote requests are
|
|
38
38
|
* REJECTED (not open): the default bind is 0.0.0.0, so "no token = no auth"
|
|
39
39
|
* would expose the whole memory store to the network.
|
|
40
|
+
*
|
|
41
|
+
* `authTokenPrevious` (optional, #254) is the prior token kept around during
|
|
42
|
+
* rotation. Both tokens are accepted; this gives a zero-downtime rotation
|
|
43
|
+
* window — in-flight clients configured with the old token keep working until
|
|
44
|
+
* they pick up the new one. BOTH comparisons are constant-time and both are
|
|
45
|
+
* always evaluated (no short-circuit), so a caller cannot learn WHICH token
|
|
46
|
+
* matched from the response timing. Absent/empty `authTokenPrevious` behaves
|
|
47
|
+
* exactly as the single-token middleware always has.
|
|
40
48
|
*/
|
|
41
|
-
export declare function createAuthMiddleware(authToken: string | undefined): express.RequestHandler;
|
|
49
|
+
export declare function createAuthMiddleware(authToken: string | undefined, authTokenPrevious?: string): express.RequestHandler;
|
|
42
50
|
/**
|
|
43
51
|
* Resolve the on-disk path of the viz page. Throws (fail explicitly) when the
|
|
44
52
|
* asset is missing — a broken install should surface, not degrade silently.
|
|
@@ -52,24 +60,29 @@ export declare function readVizHtml(): string;
|
|
|
52
60
|
*/
|
|
53
61
|
export declare function vizHandler(): express.RequestHandler;
|
|
54
62
|
/**
|
|
55
|
-
* Resolve the on-disk path of the
|
|
63
|
+
* Resolve the on-disk path of the identity-layer editor page. Throws (fail
|
|
56
64
|
* explicitly) when the asset is missing — same contract as resolveVizHtmlPath.
|
|
57
65
|
* assets/ sits next to both dist/ (dist/viz.js → ../assets/) and src/
|
|
58
66
|
* (src/viz.ts → ../assets/ under tsx), so one sibling candidate covers both.
|
|
59
67
|
*/
|
|
60
|
-
export declare function
|
|
61
|
-
/** Read the
|
|
62
|
-
export declare function
|
|
68
|
+
export declare function resolveIdentityHtmlPath(): string;
|
|
69
|
+
/** Read the identity editor page. Read at request time so a reinstall is live. */
|
|
70
|
+
export declare function readIdentityHtml(): string;
|
|
63
71
|
/**
|
|
64
|
-
* Express handler for GET /
|
|
65
|
-
* standing
|
|
66
|
-
* cannot be read, exactly like vizHandler.
|
|
72
|
+
* Express handler for GET /identity/ui — the PRIMARY edit surface for the
|
|
73
|
+
* standing identity layer. 503 with the usual {error} shape when the asset
|
|
74
|
+
* cannot be read, exactly like vizHandler. Also serves the legacy
|
|
75
|
+
* /context/ui URL (#264 backcompat).
|
|
67
76
|
*/
|
|
68
|
-
export declare function
|
|
77
|
+
export declare function identityUiHandler(): express.RequestHandler;
|
|
78
|
+
/** Backcompat aliases (#264). */
|
|
79
|
+
export declare const resolveContextHtmlPath: typeof resolveIdentityHtmlPath;
|
|
80
|
+
export declare const readContextHtml: typeof readIdentityHtml;
|
|
81
|
+
export declare const contextUiHandler: typeof identityUiHandler;
|
|
69
82
|
/**
|
|
70
83
|
* Resolve the on-disk path of the dashboard page. Throws (fail explicitly)
|
|
71
84
|
* when the asset is missing — same contract as resolveVizHtmlPath and
|
|
72
|
-
*
|
|
85
|
+
* resolveIdentityHtmlPath. assets/ sits next to both dist/ and src/ (the
|
|
73
86
|
* sibling layout the other resolvers rely on).
|
|
74
87
|
*/
|
|
75
88
|
export declare function resolveDashboardHtmlPath(): string;
|
|
@@ -78,7 +91,7 @@ export declare function readDashboardHtml(): string;
|
|
|
78
91
|
/**
|
|
79
92
|
* Express handler for GET /dashboard — the view-only analytics page (#224).
|
|
80
93
|
* 503 with the usual {error} shape when the asset cannot be read, exactly like
|
|
81
|
-
* vizHandler and
|
|
94
|
+
* vizHandler and identityUiHandler. The page SHELL is public (exempted in
|
|
82
95
|
* createAuthMiddleware); all data comes from GET /dashboard/data (bearer-only).
|
|
83
96
|
*/
|
|
84
97
|
export declare function dashboardHandler(): express.RequestHandler;
|