@gamaze/hicortex 0.2.1 → 0.3.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.
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ /**
3
+ * Hicortex MCP HTTP/SSE Server.
4
+ *
5
+ * Persistent HTTP server that exposes Hicortex tools via MCP protocol.
6
+ * Shared across all CC sessions (and future Codex/Gemini adapters).
7
+ * One process, one DB connection, one embedder — no per-session overhead.
8
+ *
9
+ * Endpoints:
10
+ * GET /health — health check
11
+ * GET /sse — SSE stream for MCP clients
12
+ * POST /messages — message endpoint for MCP clients
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ var __importDefault = (this && this.__importDefault) || function (mod) {
48
+ return (mod && mod.__esModule) ? mod : { "default": mod };
49
+ };
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.startServer = startServer;
52
+ const express_1 = __importDefault(require("express"));
53
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
54
+ const sse_js_1 = require("@modelcontextprotocol/sdk/server/sse.js");
55
+ const zod_1 = require("zod");
56
+ const db_js_1 = require("./db.js");
57
+ const llm_js_1 = require("./llm.js");
58
+ const license_js_1 = require("./license.js");
59
+ const embedder_js_1 = require("./embedder.js");
60
+ const storage = __importStar(require("./storage.js"));
61
+ const retrieval = __importStar(require("./retrieval.js"));
62
+ const consolidate_js_1 = require("./consolidate.js");
63
+ // ---------------------------------------------------------------------------
64
+ // Server state
65
+ // ---------------------------------------------------------------------------
66
+ let db = null;
67
+ let llm = null;
68
+ let cancelConsolidation = null;
69
+ let stateDir = "";
70
+ const VERSION = "0.3.0";
71
+ // ---------------------------------------------------------------------------
72
+ // MCP Server setup
73
+ // ---------------------------------------------------------------------------
74
+ function createMcpServer() {
75
+ const server = new mcp_js_1.McpServer({
76
+ name: "hicortex",
77
+ version: VERSION,
78
+ });
79
+ // -- hicortex_search --
80
+ server.tool("hicortex_search", "Search long-term memory using semantic similarity. Returns the most relevant memories from past sessions.", {
81
+ query: zod_1.z.string().describe("Search query text"),
82
+ limit: zod_1.z.number().optional().describe("Max results (default 5)"),
83
+ project: zod_1.z.string().optional().describe("Filter by project name"),
84
+ }, async ({ query, limit, project }) => {
85
+ if (!db)
86
+ return { content: [{ type: "text", text: "Hicortex not initialized" }], isError: true };
87
+ try {
88
+ const results = await retrieval.retrieve(db, embedder_js_1.embed, query, { limit, project });
89
+ return { content: [{ type: "text", text: formatResults(results) }] };
90
+ }
91
+ catch (err) {
92
+ return { content: [{ type: "text", text: `Search failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
93
+ }
94
+ });
95
+ // -- hicortex_context --
96
+ server.tool("hicortex_context", "Get recent context memories, optionally filtered by project. Useful to recall what happened recently.", {
97
+ project: zod_1.z.string().optional().describe("Filter by project name"),
98
+ limit: zod_1.z.number().optional().describe("Max results (default 10)"),
99
+ }, async ({ project, limit }) => {
100
+ if (!db)
101
+ return { content: [{ type: "text", text: "Hicortex not initialized" }], isError: true };
102
+ try {
103
+ const results = retrieval.searchContext(db, { project, limit });
104
+ return { content: [{ type: "text", text: formatResults(results) }] };
105
+ }
106
+ catch (err) {
107
+ return { content: [{ type: "text", text: `Context search failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
108
+ }
109
+ });
110
+ // -- hicortex_ingest --
111
+ server.tool("hicortex_ingest", "Store a new memory in long-term storage. Use for important facts, decisions, or lessons.", {
112
+ content: zod_1.z.string().describe("Memory content to store"),
113
+ project: zod_1.z.string().optional().describe("Project this memory belongs to"),
114
+ memory_type: zod_1.z.enum(["episode", "lesson", "fact", "decision"]).optional().describe("Type of memory (default: episode)"),
115
+ }, async ({ content, project, memory_type }) => {
116
+ if (!db)
117
+ return { content: [{ type: "text", text: "Hicortex not initialized" }], isError: true };
118
+ const features = (0, license_js_1.getFeatures)(stateDir);
119
+ if (features.maxMemories > 0 && storage.countMemories(db) >= features.maxMemories) {
120
+ return {
121
+ content: [{
122
+ type: "text",
123
+ text: `Free tier limit reached (${features.maxMemories} memories). ` +
124
+ `Your existing memories and lessons still work — search and recall are unaffected. ` +
125
+ `New memories won't be saved until you upgrade.\n\n` +
126
+ `Upgrade for unlimited usage: https://hicortex.gamaze.com/`
127
+ }],
128
+ };
129
+ }
130
+ try {
131
+ const embedding = await (0, embedder_js_1.embed)(content);
132
+ const id = storage.insertMemory(db, content, embedding, {
133
+ sourceAgent: "claude-code/manual",
134
+ project,
135
+ memoryType: memory_type ?? "episode",
136
+ privacy: "WORK",
137
+ });
138
+ return { content: [{ type: "text", text: `Memory stored (id: ${id.slice(0, 8)})` }] };
139
+ }
140
+ catch (err) {
141
+ return { content: [{ type: "text", text: `Ingest failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
142
+ }
143
+ });
144
+ // -- hicortex_lessons --
145
+ server.tool("hicortex_lessons", "Get actionable lessons learned from past sessions. Auto-generated insights about mistakes to avoid.", {
146
+ days: zod_1.z.number().optional().describe("Look back N days (default 7)"),
147
+ project: zod_1.z.string().optional().describe("Filter by project name"),
148
+ }, async ({ days, project }) => {
149
+ if (!db)
150
+ return { content: [{ type: "text", text: "Hicortex not initialized" }], isError: true };
151
+ try {
152
+ const lessons = storage.getLessons(db, days ?? 7, project);
153
+ if (lessons.length === 0) {
154
+ return { content: [{ type: "text", text: "No lessons found for the specified period." }] };
155
+ }
156
+ const text = lessons.map((l) => `- ${l.content.slice(0, 500)}`).join("\n");
157
+ return { content: [{ type: "text", text }] };
158
+ }
159
+ catch (err) {
160
+ return { content: [{ type: "text", text: `Lessons fetch failed: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
161
+ }
162
+ });
163
+ return server;
164
+ }
165
+ // ---------------------------------------------------------------------------
166
+ // HTTP server with SSE transport
167
+ // ---------------------------------------------------------------------------
168
+ async function startServer(options = {}) {
169
+ const port = options.port ?? 8787;
170
+ const host = options.host ?? "127.0.0.1";
171
+ // Initialize core
172
+ const dbPath = (0, db_js_1.resolveDbPath)(options.dbPath);
173
+ console.log(`[hicortex] Initializing database at ${dbPath}`);
174
+ db = (0, db_js_1.initDb)(dbPath);
175
+ stateDir = dbPath.replace(/\/hicortex\.db$/, "");
176
+ // LLM config
177
+ const llmConfig = (0, llm_js_1.resolveLlmConfigForCC)();
178
+ llm = new llm_js_1.LlmClient(llmConfig);
179
+ console.log(`[hicortex] LLM: ${llmConfig.provider}/${llmConfig.model} (reflect: ${llmConfig.reflectModel})`);
180
+ // License (non-blocking)
181
+ (0, license_js_1.validateLicense)(options.licenseKey, stateDir).catch((err) => console.log(`[hicortex] License validation failed: ${err}`));
182
+ // Schedule nightly consolidation
183
+ const consolidateHour = options.consolidateHour ?? 2;
184
+ cancelConsolidation = (0, consolidate_js_1.scheduleConsolidation)(db, llm, embedder_js_1.embed, consolidateHour);
185
+ // Stats
186
+ const stats = (0, db_js_1.getStats)(db, dbPath);
187
+ console.log(`[hicortex] Ready: ${stats.memories} memories, ${stats.links} links, ` +
188
+ `${Math.round(stats.db_size_bytes / 1024)} KB`);
189
+ // Create MCP server
190
+ const mcpServer = createMcpServer();
191
+ // Express app
192
+ const app = (0, express_1.default)();
193
+ app.use(express_1.default.json());
194
+ // SSE transport management
195
+ const transports = new Map();
196
+ // Health endpoint
197
+ app.get("/health", (_req, res) => {
198
+ const s = db ? (0, db_js_1.getStats)(db, dbPath) : { memories: 0, links: 0, db_size_bytes: 0, by_type: {} };
199
+ res.json({
200
+ status: "ok",
201
+ version: VERSION,
202
+ memories: s.memories,
203
+ links: s.links,
204
+ db_size_kb: Math.round(s.db_size_bytes / 1024),
205
+ llm: `${llmConfig.provider}/${llmConfig.model}`,
206
+ });
207
+ });
208
+ // SSE endpoint — client connects here to establish MCP session
209
+ app.get("/sse", async (req, res) => {
210
+ const transport = new sse_js_1.SSEServerTransport("/messages", res);
211
+ transports.set(transport.sessionId, transport);
212
+ transport.onclose = () => {
213
+ transports.delete(transport.sessionId);
214
+ };
215
+ await mcpServer.connect(transport);
216
+ });
217
+ // Message endpoint — client POSTs MCP messages here
218
+ app.post("/messages", async (req, res) => {
219
+ const sessionId = req.query.sessionId;
220
+ if (!sessionId || !transports.has(sessionId)) {
221
+ res.status(400).json({ error: "Invalid or missing sessionId" });
222
+ return;
223
+ }
224
+ const transport = transports.get(sessionId);
225
+ // Pass parsed body since express.json() already consumed the stream
226
+ await transport.handlePostMessage(req, res, req.body);
227
+ });
228
+ // Start listening
229
+ const server = app.listen(port, host, () => {
230
+ console.log(`[hicortex] MCP server listening on http://${host}:${port}`);
231
+ console.log(`[hicortex] SSE endpoint: http://${host}:${port}/sse`);
232
+ console.log(`[hicortex] Health: http://${host}:${port}/health`);
233
+ });
234
+ // Graceful shutdown
235
+ const shutdown = () => {
236
+ console.log("[hicortex] Shutting down...");
237
+ if (cancelConsolidation) {
238
+ cancelConsolidation();
239
+ cancelConsolidation = null;
240
+ }
241
+ for (const transport of transports.values()) {
242
+ transport.close().catch(() => { });
243
+ }
244
+ transports.clear();
245
+ server.close(() => {
246
+ if (db) {
247
+ db.close();
248
+ db = null;
249
+ }
250
+ console.log("[hicortex] Server stopped.");
251
+ process.exit(0);
252
+ });
253
+ };
254
+ process.on("SIGINT", shutdown);
255
+ process.on("SIGTERM", shutdown);
256
+ }
257
+ // ---------------------------------------------------------------------------
258
+ // Helpers
259
+ // ---------------------------------------------------------------------------
260
+ function formatResults(results) {
261
+ if (results.length === 0)
262
+ return "No memories found.";
263
+ return results
264
+ .map((r) => `[${r.memory_type}] (score: ${r.score.toFixed(3)}, strength: ${r.effective_strength.toFixed(3)}) ${r.content.slice(0, 500)}`)
265
+ .join("\n\n");
266
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Nightly pipeline — manual trigger or called by the persistent server.
3
+ *
4
+ * Steps:
5
+ * 1. Read new CC transcripts since last run
6
+ * 2. Distill each session into memories via LLM
7
+ * 3. Run consolidation (scoring, reflection, linking, decay)
8
+ * 4. Inject lessons into CLAUDE.md
9
+ * 5. Update last-run timestamp
10
+ */
11
+ export declare function runNightly(options?: {
12
+ dryRun?: boolean;
13
+ dbPath?: string;
14
+ stateDir?: string;
15
+ }): Promise<void>;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ /**
3
+ * Nightly pipeline — manual trigger or called by the persistent server.
4
+ *
5
+ * Steps:
6
+ * 1. Read new CC transcripts since last run
7
+ * 2. Distill each session into memories via LLM
8
+ * 3. Run consolidation (scoring, reflection, linking, decay)
9
+ * 4. Inject lessons into CLAUDE.md
10
+ * 5. Update last-run timestamp
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.runNightly = runNightly;
47
+ const node_fs_1 = require("node:fs");
48
+ const node_path_1 = require("node:path");
49
+ const node_os_1 = require("node:os");
50
+ const db_js_1 = require("./db.js");
51
+ const llm_js_1 = require("./llm.js");
52
+ const embedder_js_1 = require("./embedder.js");
53
+ const storage = __importStar(require("./storage.js"));
54
+ const distiller_js_1 = require("./distiller.js");
55
+ const consolidate_js_1 = require("./consolidate.js");
56
+ const transcript_reader_js_1 = require("./transcript-reader.js");
57
+ const claude_md_js_1 = require("./claude-md.js");
58
+ const license_js_1 = require("./license.js");
59
+ const HICORTEX_HOME = (0, node_path_1.join)((0, node_os_1.homedir)(), ".hicortex");
60
+ const LAST_RUN_PATH = (0, node_path_1.join)(HICORTEX_HOME, "nightly-last-run.txt");
61
+ function readLastRun() {
62
+ try {
63
+ const ts = (0, node_fs_1.readFileSync)(LAST_RUN_PATH, "utf-8").trim();
64
+ const d = new Date(ts);
65
+ if (!isNaN(d.getTime()))
66
+ return d;
67
+ }
68
+ catch {
69
+ // No file — first run
70
+ }
71
+ return new Date(0); // Process everything
72
+ }
73
+ function writeLastRun() {
74
+ (0, node_fs_1.mkdirSync)(HICORTEX_HOME, { recursive: true });
75
+ (0, node_fs_1.writeFileSync)(LAST_RUN_PATH, new Date().toISOString());
76
+ }
77
+ async function runNightly(options = {}) {
78
+ const dryRun = options.dryRun ?? false;
79
+ const dbPath = (0, db_js_1.resolveDbPath)(options.dbPath);
80
+ const stateDir = options.stateDir ?? HICORTEX_HOME;
81
+ console.log(`[hicortex] Nightly pipeline starting${dryRun ? " (dry run)" : ""}`);
82
+ console.log(`[hicortex] DB: ${dbPath}`);
83
+ // Init DB
84
+ const db = (0, db_js_1.initDb)(dbPath);
85
+ try {
86
+ // Init LLM
87
+ const llmConfig = (0, llm_js_1.resolveLlmConfigForCC)();
88
+ const llm = new llm_js_1.LlmClient(llmConfig);
89
+ console.log(`[hicortex] LLM: ${llmConfig.provider}/${llmConfig.model}`);
90
+ // Step 1: Read new CC transcripts
91
+ const since = readLastRun();
92
+ console.log(`[hicortex] Reading CC transcripts since ${since.toISOString()}`);
93
+ const batches = (0, transcript_reader_js_1.readCcTranscripts)(since);
94
+ console.log(`[hicortex] Found ${batches.length} new session(s)`);
95
+ if (batches.length === 0 && !dryRun) {
96
+ // Still run consolidation — there may be unscored memories from OC
97
+ console.log(`[hicortex] No new CC transcripts. Running consolidation only.`);
98
+ }
99
+ // Step 2: Distill each session
100
+ let memoriesIngested = 0;
101
+ const features = (0, license_js_1.getFeatures)(stateDir);
102
+ for (const batch of batches) {
103
+ const transcript = (0, distiller_js_1.extractConversationText)(batch.entries);
104
+ if (transcript.length < 200) {
105
+ console.log(`[hicortex] Skip ${batch.sessionId.slice(0, 8)} (${batch.projectName}): too short`);
106
+ continue;
107
+ }
108
+ console.log(`[hicortex] Distilling ${batch.sessionId.slice(0, 8)} (${batch.projectName}, ${batch.date})`);
109
+ if (dryRun) {
110
+ console.log(`[hicortex] [dry-run] Would distill ${transcript.length} chars`);
111
+ continue;
112
+ }
113
+ // Check cap before distilling
114
+ if (features.maxMemories > 0 && storage.countMemories(db) >= features.maxMemories) {
115
+ console.log(`[hicortex] Free tier limit (${features.maxMemories} memories). Skipping new ingestion. ` +
116
+ `Upgrade: https://hicortex.gamaze.com/`);
117
+ break;
118
+ }
119
+ try {
120
+ const entries = await (0, distiller_js_1.distillSession)(llm, transcript, batch.projectName, batch.date);
121
+ for (const entry of entries) {
122
+ try {
123
+ const embedding = await (0, embedder_js_1.embed)(entry);
124
+ storage.insertMemory(db, entry, embedding, {
125
+ sourceAgent: `claude-code/${batch.projectName}`,
126
+ sourceSession: batch.sessionId,
127
+ project: batch.projectName,
128
+ privacy: "WORK",
129
+ memoryType: "episode",
130
+ });
131
+ memoriesIngested++;
132
+ }
133
+ catch (err) {
134
+ const msg = err instanceof Error ? err.message : String(err);
135
+ console.error(`[hicortex] Failed to ingest entry: ${msg}`);
136
+ }
137
+ }
138
+ console.log(`[hicortex] → ${entries.length} memories extracted`);
139
+ }
140
+ catch (err) {
141
+ const msg = err instanceof Error ? err.message : String(err);
142
+ console.error(`[hicortex] Distillation failed: ${msg}`);
143
+ }
144
+ }
145
+ console.log(`[hicortex] Distillation complete: ${memoriesIngested} new memories`);
146
+ // Step 3: Consolidation
147
+ if (!dryRun) {
148
+ console.log(`[hicortex] Running consolidation...`);
149
+ const report = await (0, consolidate_js_1.runConsolidation)(db, llm, embedder_js_1.embed, dryRun);
150
+ console.log(`[hicortex] Consolidation ${report.status} in ${report.elapsed_seconds}s` +
151
+ (report.stages.reflection ? ` (${report.stages.reflection.lessons_generated} lessons)` : ""));
152
+ }
153
+ // Step 4: Inject lessons into CLAUDE.md
154
+ if (!dryRun) {
155
+ const injection = (0, claude_md_js_1.injectLessons)(db, { stateDir });
156
+ console.log(`[hicortex] CLAUDE.md updated: ${injection.lessonsCount} lessons at ${injection.path}`);
157
+ }
158
+ // Step 5: Update last-run timestamp
159
+ if (!dryRun) {
160
+ writeLastRun();
161
+ }
162
+ console.log(`[hicortex] Nightly pipeline complete.`);
163
+ }
164
+ finally {
165
+ db.close();
166
+ }
167
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Hicortex status — show current configuration and stats.
3
+ */
4
+ export declare function runStatus(): Promise<void>;
package/dist/status.js ADDED
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ /**
3
+ * Hicortex status — show current configuration and stats.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runStatus = runStatus;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const node_os_1 = require("node:os");
10
+ const node_child_process_1 = require("node:child_process");
11
+ const db_js_1 = require("./db.js");
12
+ const HICORTEX_HOME = (0, node_path_1.join)((0, node_os_1.homedir)(), ".hicortex");
13
+ const CC_SETTINGS = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude", "settings.json");
14
+ const OC_CONFIG = (0, node_path_1.join)((0, node_os_1.homedir)(), ".openclaw", "openclaw.json");
15
+ async function runStatus() {
16
+ console.log("Hicortex Status");
17
+ console.log("─".repeat(40));
18
+ // DB
19
+ const dbPath = (0, db_js_1.resolveDbPath)();
20
+ const dbExists = (0, node_fs_1.existsSync)(dbPath);
21
+ console.log(`DB: ${dbPath} ${dbExists ? "" : "(not found)"}`);
22
+ if (dbExists) {
23
+ try {
24
+ const { initDb, getStats } = await import("./db.js");
25
+ const db = initDb(dbPath);
26
+ const stats = getStats(db, dbPath);
27
+ const typeStr = Object.entries(stats.by_type).map(([k, v]) => `${k}=${v}`).join(", ");
28
+ console.log(`Memories: ${stats.memories} (${typeStr || "none"})`);
29
+ console.log(`Links: ${stats.links}`);
30
+ console.log(`DB size: ${(stats.db_size_bytes / 1024).toFixed(1)} KB`);
31
+ db.close();
32
+ }
33
+ catch (err) {
34
+ console.log(`DB error: ${err instanceof Error ? err.message : String(err)}`);
35
+ }
36
+ }
37
+ // License
38
+ const configPath = (0, node_path_1.join)(HICORTEX_HOME, "config.json");
39
+ let licenseKey = "";
40
+ try {
41
+ const config = JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
42
+ licenseKey = config.licenseKey ?? "";
43
+ }
44
+ catch { /* no config */ }
45
+ console.log(`License: ${licenseKey ? "configured" : "free tier (250 memories)"}`);
46
+ console.log();
47
+ // Adapters
48
+ console.log("Adapters:");
49
+ // OC
50
+ let ocInstalled = false;
51
+ try {
52
+ const raw = (0, node_fs_1.readFileSync)(OC_CONFIG, "utf-8");
53
+ const config = JSON.parse(raw);
54
+ const entries = config?.plugins?.entries ?? {};
55
+ const installs = config?.plugins?.installs ?? {};
56
+ ocInstalled = "hicortex" in entries || "hicortex" in installs;
57
+ }
58
+ catch { /* no OC */ }
59
+ console.log(` OC plugin: ${ocInstalled ? "installed" : "not found"}`);
60
+ // CC
61
+ let ccRegistered = false;
62
+ let ccUrl = "";
63
+ try {
64
+ const raw = (0, node_fs_1.readFileSync)(CC_SETTINGS, "utf-8");
65
+ const settings = JSON.parse(raw);
66
+ const hc = settings?.mcpServers?.hicortex;
67
+ if (hc) {
68
+ ccRegistered = true;
69
+ ccUrl = hc.url ?? "";
70
+ }
71
+ }
72
+ catch { /* no CC settings */ }
73
+ console.log(` CC MCP: ${ccRegistered ? `registered → ${ccUrl}` : "not registered"}`);
74
+ console.log();
75
+ // Server status
76
+ console.log("Server:");
77
+ let serverRunning = false;
78
+ try {
79
+ const resp = await fetch("http://127.0.0.1:8787/health", {
80
+ signal: AbortSignal.timeout(2000),
81
+ });
82
+ if (resp.ok) {
83
+ const data = await resp.json();
84
+ serverRunning = true;
85
+ console.log(` Status: running (${data.llm})`);
86
+ }
87
+ }
88
+ catch { /* not running */ }
89
+ if (!serverRunning)
90
+ console.log(" Status: not running");
91
+ // Daemon
92
+ const os = (0, node_os_1.platform)();
93
+ if (os === "darwin") {
94
+ try {
95
+ const out = (0, node_child_process_1.execSync)("launchctl list 2>/dev/null | grep hicortex", { encoding: "utf-8" });
96
+ console.log(` Daemon: launchd (${out.trim() ? "loaded" : "not loaded"})`);
97
+ }
98
+ catch {
99
+ console.log(" Daemon: launchd (not installed)");
100
+ }
101
+ }
102
+ else if (os === "linux") {
103
+ try {
104
+ const out = (0, node_child_process_1.execSync)("systemctl --user is-active hicortex.service 2>/dev/null", { encoding: "utf-8" }).trim();
105
+ console.log(` Daemon: systemd (${out})`);
106
+ }
107
+ catch {
108
+ console.log(" Daemon: systemd (not installed)");
109
+ }
110
+ }
111
+ // Last nightly run
112
+ const lastRunPath = (0, node_path_1.join)(HICORTEX_HOME, "nightly-last-run.txt");
113
+ try {
114
+ const ts = (0, node_fs_1.readFileSync)(lastRunPath, "utf-8").trim();
115
+ console.log(` Last run: ${ts}`);
116
+ }
117
+ catch {
118
+ console.log(" Last run: never");
119
+ }
120
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CC transcript reader — reads Claude Code .jsonl session files.
3
+ *
4
+ * CC stores transcripts at ~/.claude/projects/<project-hash>/<session-uuid>.jsonl.
5
+ * Each line is a JSON object with type, message, timestamp, etc.
6
+ *
7
+ * The reader scans for new sessions since the last nightly run
8
+ * and feeds them to the existing distiller pipeline.
9
+ */
10
+ export interface TranscriptBatch {
11
+ sessionId: string;
12
+ projectName: string;
13
+ date: string;
14
+ entries: unknown[];
15
+ }
16
+ /**
17
+ * Read all CC transcripts modified since `since`.
18
+ * Returns one batch per session file.
19
+ */
20
+ export declare function readCcTranscripts(since: Date, projectsDir?: string): TranscriptBatch[];