claude-memory-layer 1.0.48 → 1.0.50
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/dist/cli/index.js +442 -8
- package/dist/cli/index.js.map +4 -4
- package/dist/server/api/index.js +439 -5
- package/dist/server/api/index.js.map +4 -4
- package/dist/server/index.js +441 -7
- package/dist/server/index.js.map +4 -4
- package/dist/ui/assets/js/bootstrap.js +63 -1
- package/dist/ui/assets/js/disclosure.js +158 -10
- package/dist/ui/assets/js/modals.js +39 -18
- package/dist/ui/assets/js/overview.js +99 -9
- package/dist/ui/assets/js/state.js +28 -1
- package/dist/ui/assets/js/views.js +626 -15
- package/dist/ui/index.html +130 -0
- package/dist/ui/style.css +460 -0
- package/package.json +4 -1
package/dist/cli/index.js
CHANGED
|
@@ -15996,7 +15996,7 @@ async function bootstrapKnowledgeBase(options) {
|
|
|
15996
15996
|
}
|
|
15997
15997
|
|
|
15998
15998
|
// src/apps/server/index.ts
|
|
15999
|
-
import { Hono as
|
|
15999
|
+
import { Hono as Hono12 } from "hono";
|
|
16000
16000
|
import { cors } from "hono/cors";
|
|
16001
16001
|
import { getCookie, setCookie, deleteCookie } from "hono/cookie";
|
|
16002
16002
|
import { logger } from "hono/logger";
|
|
@@ -16008,7 +16008,7 @@ import { createHmac, timingSafeEqual } from "crypto";
|
|
|
16008
16008
|
import { fileURLToPath as fileUrlToPath } from "url";
|
|
16009
16009
|
|
|
16010
16010
|
// src/apps/server/api/index.ts
|
|
16011
|
-
import { Hono as
|
|
16011
|
+
import { Hono as Hono11 } from "hono";
|
|
16012
16012
|
|
|
16013
16013
|
// src/apps/server/api/sessions.ts
|
|
16014
16014
|
import { Hono } from "hono";
|
|
@@ -16085,10 +16085,25 @@ sessionsRouter.get("/", async (c) => {
|
|
|
16085
16085
|
id: event.sessionId,
|
|
16086
16086
|
startedAt: event.timestamp,
|
|
16087
16087
|
eventCount: 1,
|
|
16088
|
-
lastEventAt: event.timestamp
|
|
16088
|
+
lastEventAt: event.timestamp,
|
|
16089
|
+
promptPreview: event.eventType === "user_prompt" ? event.content.slice(0, 160) : "",
|
|
16090
|
+
firstUserPromptAt: event.eventType === "user_prompt" ? event.timestamp : null,
|
|
16091
|
+
toolCount: event.eventType === "tool_observation" ? 1 : 0,
|
|
16092
|
+
responseCount: event.eventType === "agent_response" ? 1 : 0,
|
|
16093
|
+
eventTypeCounts: { [event.eventType || "unknown"]: 1 },
|
|
16094
|
+
source: typeof event.metadata?.source === "string" ? event.metadata.source : null
|
|
16089
16095
|
});
|
|
16090
16096
|
} else {
|
|
16091
16097
|
existing.eventCount++;
|
|
16098
|
+
const eventType = event.eventType || "unknown";
|
|
16099
|
+
existing.eventTypeCounts[eventType] = (existing.eventTypeCounts[eventType] || 0) + 1;
|
|
16100
|
+
if (event.eventType === "tool_observation") existing.toolCount++;
|
|
16101
|
+
if (event.eventType === "agent_response") existing.responseCount++;
|
|
16102
|
+
if (event.eventType === "user_prompt" && (!existing.firstUserPromptAt || event.timestamp < existing.firstUserPromptAt)) {
|
|
16103
|
+
existing.firstUserPromptAt = event.timestamp;
|
|
16104
|
+
existing.promptPreview = event.content.slice(0, 160);
|
|
16105
|
+
}
|
|
16106
|
+
if (!existing.source && typeof event.metadata?.source === "string") existing.source = event.metadata.source;
|
|
16092
16107
|
if (event.timestamp < existing.startedAt) {
|
|
16093
16108
|
existing.startedAt = event.timestamp;
|
|
16094
16109
|
}
|
|
@@ -18131,7 +18146,7 @@ turnsRouter.get("/", async (c) => {
|
|
|
18131
18146
|
if (!sessionId) {
|
|
18132
18147
|
return c.json({ error: "sessionId is required" }, 400);
|
|
18133
18148
|
}
|
|
18134
|
-
const memoryService =
|
|
18149
|
+
const memoryService = getLightweightServiceFromQuery(c);
|
|
18135
18150
|
try {
|
|
18136
18151
|
await memoryService.initialize();
|
|
18137
18152
|
const turns = await memoryService.getSessionTurns(sessionId, { limit, offset });
|
|
@@ -18165,7 +18180,7 @@ turnsRouter.get("/", async (c) => {
|
|
|
18165
18180
|
});
|
|
18166
18181
|
turnsRouter.get("/:turnId", async (c) => {
|
|
18167
18182
|
const { turnId } = c.req.param();
|
|
18168
|
-
const memoryService =
|
|
18183
|
+
const memoryService = getLightweightServiceFromQuery(c);
|
|
18169
18184
|
try {
|
|
18170
18185
|
await memoryService.initialize();
|
|
18171
18186
|
const events = await memoryService.getEventsByTurn(turnId);
|
|
@@ -18240,6 +18255,58 @@ import * as fs14 from "fs";
|
|
|
18240
18255
|
import * as path16 from "path";
|
|
18241
18256
|
import * as os10 from "os";
|
|
18242
18257
|
var projectsRouter = new Hono7();
|
|
18258
|
+
projectsRouter.get("/:hash/detail", async (c) => {
|
|
18259
|
+
const { hash } = c.req.param();
|
|
18260
|
+
const registry = loadSessionRegistry();
|
|
18261
|
+
const projectPath = getRegisteredProjectPath(registry, hash);
|
|
18262
|
+
const storagePath = resolveProjectStoragePath(hash);
|
|
18263
|
+
const memoryService = new MemoryService({
|
|
18264
|
+
storagePath,
|
|
18265
|
+
projectHash: hash,
|
|
18266
|
+
...projectPath ? { projectPath } : {},
|
|
18267
|
+
readOnly: true,
|
|
18268
|
+
lightweightMode: true,
|
|
18269
|
+
analyticsEnabled: false,
|
|
18270
|
+
sharedStoreConfig: DISABLED_SHARED_STORE_CONFIG
|
|
18271
|
+
});
|
|
18272
|
+
try {
|
|
18273
|
+
await memoryService.initialize();
|
|
18274
|
+
const [stats, recentEvents, retrieval, outbox] = await Promise.all([
|
|
18275
|
+
memoryService.getStats(),
|
|
18276
|
+
memoryService.getRecentEvents(1e3),
|
|
18277
|
+
memoryService.getRetrievalTraceStats(),
|
|
18278
|
+
memoryService.getOutboxStats()
|
|
18279
|
+
]);
|
|
18280
|
+
const eventSummary = summarizeProjectEvents(recentEvents);
|
|
18281
|
+
return c.json({
|
|
18282
|
+
project: {
|
|
18283
|
+
hash,
|
|
18284
|
+
projectName: projectPath ? path16.basename(projectPath) : `unknown (${hash})`,
|
|
18285
|
+
registered: Boolean(projectPath)
|
|
18286
|
+
},
|
|
18287
|
+
storage: {
|
|
18288
|
+
eventCount: stats.totalEvents,
|
|
18289
|
+
vectorCount: stats.vectorCount,
|
|
18290
|
+
levels: stats.levelStats || []
|
|
18291
|
+
},
|
|
18292
|
+
sessions: eventSummary.sessions,
|
|
18293
|
+
eventTypes: eventSummary.eventTypes,
|
|
18294
|
+
sources: eventSummary.sources,
|
|
18295
|
+
activity: eventSummary.activity,
|
|
18296
|
+
retrieval: {
|
|
18297
|
+
totalQueries: retrieval.totalQueries,
|
|
18298
|
+
avgCandidateCount: retrieval.avgCandidateCount,
|
|
18299
|
+
avgSelectedCount: retrieval.avgSelectedCount,
|
|
18300
|
+
selectionRate: retrieval.selectionRate
|
|
18301
|
+
},
|
|
18302
|
+
outbox: summarizeProjectOutbox(outbox)
|
|
18303
|
+
});
|
|
18304
|
+
} catch {
|
|
18305
|
+
return c.json({ error: "Project detail unavailable" }, 500);
|
|
18306
|
+
} finally {
|
|
18307
|
+
await memoryService.shutdown();
|
|
18308
|
+
}
|
|
18309
|
+
});
|
|
18243
18310
|
projectsRouter.get("/", async (c) => {
|
|
18244
18311
|
try {
|
|
18245
18312
|
const projectsDir = path16.join(os10.homedir(), ".claude-code", "memory", "projects");
|
|
@@ -18279,6 +18346,57 @@ projectsRouter.get("/", async (c) => {
|
|
|
18279
18346
|
return c.json({ projects: [], error: error.message }, 500);
|
|
18280
18347
|
}
|
|
18281
18348
|
});
|
|
18349
|
+
function getRegisteredProjectPath(registry, hash) {
|
|
18350
|
+
for (const entry of Object.values(registry.sessions)) {
|
|
18351
|
+
if (entry.projectHash === hash) {
|
|
18352
|
+
return entry.projectPath;
|
|
18353
|
+
}
|
|
18354
|
+
}
|
|
18355
|
+
return void 0;
|
|
18356
|
+
}
|
|
18357
|
+
function summarizeProjectEvents(events) {
|
|
18358
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
18359
|
+
const eventTypes = {};
|
|
18360
|
+
const sources = {};
|
|
18361
|
+
let firstEventAt = null;
|
|
18362
|
+
let lastEventAt = null;
|
|
18363
|
+
for (const event of events) {
|
|
18364
|
+
if (event.sessionId) sessions.add(event.sessionId);
|
|
18365
|
+
incrementBucket(eventTypes, event.eventType || "unknown");
|
|
18366
|
+
const source = typeof event.metadata?.source === "string" ? event.metadata.source : "unknown";
|
|
18367
|
+
incrementBucket(sources, source || "unknown");
|
|
18368
|
+
const timestamp = normalizeIsoTimestamp(event.timestamp);
|
|
18369
|
+
if (!timestamp) continue;
|
|
18370
|
+
if (!firstEventAt || timestamp < firstEventAt) firstEventAt = timestamp;
|
|
18371
|
+
if (!lastEventAt || timestamp > lastEventAt) lastEventAt = timestamp;
|
|
18372
|
+
}
|
|
18373
|
+
return {
|
|
18374
|
+
sessions: { total: sessions.size },
|
|
18375
|
+
eventTypes,
|
|
18376
|
+
sources,
|
|
18377
|
+
activity: { firstEventAt, lastEventAt }
|
|
18378
|
+
};
|
|
18379
|
+
}
|
|
18380
|
+
function summarizeProjectOutbox(outbox) {
|
|
18381
|
+
const embedding = outbox.embedding || {};
|
|
18382
|
+
const vector = outbox.vector || {};
|
|
18383
|
+
return {
|
|
18384
|
+
pending: (embedding.pending || 0) + (vector.pending || 0),
|
|
18385
|
+
processing: (embedding.processing || 0) + (vector.processing || 0),
|
|
18386
|
+
failed: (embedding.failed || 0) + (vector.failed || 0),
|
|
18387
|
+
stuckProcessing: (embedding.stuckProcessing || 0) + (vector.stuckProcessing || 0)
|
|
18388
|
+
};
|
|
18389
|
+
}
|
|
18390
|
+
function incrementBucket(bucket, rawLabel) {
|
|
18391
|
+
const label = rawLabel.replace(/[^a-zA-Z0-9_.:-]/g, "_").slice(0, 80) || "unknown";
|
|
18392
|
+
bucket[label] = (bucket[label] || 0) + 1;
|
|
18393
|
+
}
|
|
18394
|
+
function normalizeIsoTimestamp(value) {
|
|
18395
|
+
if (!value) return null;
|
|
18396
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
18397
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
18398
|
+
return date.toISOString();
|
|
18399
|
+
}
|
|
18282
18400
|
function formatBytes(bytes) {
|
|
18283
18401
|
if (bytes === 0) return "0 B";
|
|
18284
18402
|
const k = 1024;
|
|
@@ -18567,7 +18685,101 @@ function streamClaudeResponse(prompt, stream) {
|
|
|
18567
18685
|
|
|
18568
18686
|
// src/apps/server/api/health.ts
|
|
18569
18687
|
import { Hono as Hono9 } from "hono";
|
|
18688
|
+
import { spawnSync } from "child_process";
|
|
18570
18689
|
var healthRouter = new Hono9();
|
|
18690
|
+
function hasEnvSignal(name) {
|
|
18691
|
+
const value = process.env[name];
|
|
18692
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
18693
|
+
}
|
|
18694
|
+
function claudeAuthSignal() {
|
|
18695
|
+
return hasEnvSignal("ANTHROPIC_API_KEY") || hasEnvSignal("CLAUDE_API_KEY") || hasEnvSignal("CLAUDE_CODE_OAUTH_TOKEN") ? "env-present" : "not-detected";
|
|
18696
|
+
}
|
|
18697
|
+
function detectClaudeCli() {
|
|
18698
|
+
const result = spawnSync("claude", ["--version"], {
|
|
18699
|
+
encoding: "utf-8",
|
|
18700
|
+
timeout: 3e3
|
|
18701
|
+
});
|
|
18702
|
+
const authSignal = claudeAuthSignal();
|
|
18703
|
+
const errorCode = result.error?.code;
|
|
18704
|
+
if (errorCode === "ENOENT") {
|
|
18705
|
+
return { status: "missing", command: "claude", authSignal };
|
|
18706
|
+
}
|
|
18707
|
+
if (result.status === 0) {
|
|
18708
|
+
const version = String(result.stdout || "").split("\n")[0]?.trim().slice(0, 80) || void 0;
|
|
18709
|
+
return { status: "available", command: "claude", authSignal, ...version ? { version } : {} };
|
|
18710
|
+
}
|
|
18711
|
+
return { status: "error", command: "claude", authSignal };
|
|
18712
|
+
}
|
|
18713
|
+
function detectEmbeddingBackend() {
|
|
18714
|
+
const disabled = ["1", "true", "yes"].includes(String(process.env.CLAUDE_MEMORY_DISABLE_VECTOR || "").toLowerCase());
|
|
18715
|
+
return {
|
|
18716
|
+
status: disabled ? "disabled" : "enabled",
|
|
18717
|
+
backend: "@huggingface/transformers"
|
|
18718
|
+
};
|
|
18719
|
+
}
|
|
18720
|
+
function aggregateOutbox(outbox) {
|
|
18721
|
+
const pending = (outbox.embedding?.pending || 0) + (outbox.vector?.pending || 0);
|
|
18722
|
+
const processing = (outbox.embedding?.processing || 0) + (outbox.vector?.processing || 0);
|
|
18723
|
+
const failed = (outbox.embedding?.failed || 0) + (outbox.vector?.failed || 0);
|
|
18724
|
+
const stuckProcessing = (outbox.embedding?.stuckProcessing || 0) + (outbox.vector?.stuckProcessing || 0);
|
|
18725
|
+
return { pending, processing, failed, stuckProcessing };
|
|
18726
|
+
}
|
|
18727
|
+
healthRouter.get("/setup", async (c) => {
|
|
18728
|
+
const memoryService = getLightweightServiceFromQuery(c);
|
|
18729
|
+
try {
|
|
18730
|
+
await memoryService.initialize();
|
|
18731
|
+
const [stats, outbox] = await Promise.all([
|
|
18732
|
+
memoryService.getStats(),
|
|
18733
|
+
memoryService.getOutboxStats()
|
|
18734
|
+
]);
|
|
18735
|
+
const outboxTotals = aggregateOutbox(outbox);
|
|
18736
|
+
const claudeCli = detectClaudeCli();
|
|
18737
|
+
const embeddings = detectEmbeddingBackend();
|
|
18738
|
+
const recommendations = [];
|
|
18739
|
+
if (claudeCli.status !== "available") {
|
|
18740
|
+
recommendations.push("Install or authenticate Claude CLI to enable Ask Memory assistant responses.");
|
|
18741
|
+
}
|
|
18742
|
+
if (embeddings.status === "disabled") {
|
|
18743
|
+
recommendations.push("Enable vector embeddings to improve semantic retrieval and memory usefulness.");
|
|
18744
|
+
}
|
|
18745
|
+
if (outboxTotals.failed > 0 || outboxTotals.stuckProcessing > 0) {
|
|
18746
|
+
recommendations.push("Run vector health recovery before trusting retrieval freshness.");
|
|
18747
|
+
}
|
|
18748
|
+
let status = "ok";
|
|
18749
|
+
if (claudeCli.status !== "available" || embeddings.status === "disabled") {
|
|
18750
|
+
status = "needs-setup";
|
|
18751
|
+
} else if (outboxTotals.failed > 0 || outboxTotals.stuckProcessing > 0) {
|
|
18752
|
+
status = "needs-attention";
|
|
18753
|
+
}
|
|
18754
|
+
const scoped = Boolean(c.req.query("project") || c.req.query("projectId"));
|
|
18755
|
+
return c.json({
|
|
18756
|
+
status,
|
|
18757
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18758
|
+
setup: {
|
|
18759
|
+
scope: scoped ? "project" : "global",
|
|
18760
|
+
storage: {
|
|
18761
|
+
status: "ok",
|
|
18762
|
+
totalEvents: stats.totalEvents,
|
|
18763
|
+
vectorCount: stats.vectorCount
|
|
18764
|
+
},
|
|
18765
|
+
outbox: outboxTotals
|
|
18766
|
+
},
|
|
18767
|
+
providers: {
|
|
18768
|
+
claudeCli,
|
|
18769
|
+
embeddings
|
|
18770
|
+
},
|
|
18771
|
+
recommendations
|
|
18772
|
+
});
|
|
18773
|
+
} catch {
|
|
18774
|
+
return c.json({
|
|
18775
|
+
status: "error",
|
|
18776
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18777
|
+
error: "Setup health check failed"
|
|
18778
|
+
}, 500);
|
|
18779
|
+
} finally {
|
|
18780
|
+
await memoryService.shutdown();
|
|
18781
|
+
}
|
|
18782
|
+
});
|
|
18571
18783
|
healthRouter.get("/", async (c) => {
|
|
18572
18784
|
const memoryService = getLightweightServiceFromQuery(c);
|
|
18573
18785
|
try {
|
|
@@ -18659,8 +18871,230 @@ healthRouter.post("/recover", async (c) => {
|
|
|
18659
18871
|
}
|
|
18660
18872
|
});
|
|
18661
18873
|
|
|
18874
|
+
// src/apps/server/api/playground.ts
|
|
18875
|
+
import { Hono as Hono10 } from "hono";
|
|
18876
|
+
var playgroundRouter = new Hono10();
|
|
18877
|
+
function normalizeWindowSize(value) {
|
|
18878
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
18879
|
+
if (!Number.isFinite(parsed)) return 3;
|
|
18880
|
+
return Math.max(1, Math.min(10, Math.trunc(parsed)));
|
|
18881
|
+
}
|
|
18882
|
+
function disclosureOptions(options = {}) {
|
|
18883
|
+
const {
|
|
18884
|
+
windowSize: _windowSize,
|
|
18885
|
+
selectedResultId: _selectedResultId,
|
|
18886
|
+
...rest
|
|
18887
|
+
} = options;
|
|
18888
|
+
return rest;
|
|
18889
|
+
}
|
|
18890
|
+
var SOURCE_EVENT_PREVIEW_CHARS = 500;
|
|
18891
|
+
var SOURCE_EVENT_LIMIT = 3;
|
|
18892
|
+
function asRecord(value) {
|
|
18893
|
+
return value && typeof value === "object" ? value : null;
|
|
18894
|
+
}
|
|
18895
|
+
function safeSourcePreview(value) {
|
|
18896
|
+
const raw = typeof value === "string" ? value : String(value ?? "");
|
|
18897
|
+
const sanitized = String(sanitizeGovernanceAuditValue(raw));
|
|
18898
|
+
return sanitized.length > SOURCE_EVENT_PREVIEW_CHARS ? `${sanitized.slice(0, SOURCE_EVENT_PREVIEW_CHARS)}...` : sanitized;
|
|
18899
|
+
}
|
|
18900
|
+
function sanitizeSourceEvent(event) {
|
|
18901
|
+
const record = asRecord(event);
|
|
18902
|
+
if (!record) {
|
|
18903
|
+
return { preview: safeSourcePreview(event) };
|
|
18904
|
+
}
|
|
18905
|
+
const safe = {};
|
|
18906
|
+
if (record.id !== void 0) safe.id = sanitizeGovernanceAuditValue(record.id, "id");
|
|
18907
|
+
if (record.eventId !== void 0) safe.eventId = sanitizeGovernanceAuditValue(record.eventId, "eventId");
|
|
18908
|
+
if (record.sessionId !== void 0) safe.sessionId = sanitizeGovernanceAuditValue(record.sessionId, "sessionId");
|
|
18909
|
+
if (record.eventType !== void 0) safe.eventType = sanitizeGovernanceAuditValue(record.eventType, "eventType");
|
|
18910
|
+
if (record.timestamp !== void 0) safe.timestamp = sanitizeGovernanceAuditValue(record.timestamp, "timestamp");
|
|
18911
|
+
const previewSource = record.content ?? record.preview ?? "";
|
|
18912
|
+
safe.preview = safeSourcePreview(previewSource);
|
|
18913
|
+
if (typeof record.content === "string") {
|
|
18914
|
+
safe.contentLength = record.content.length;
|
|
18915
|
+
}
|
|
18916
|
+
return safe;
|
|
18917
|
+
}
|
|
18918
|
+
function sanitizeStringArray(value) {
|
|
18919
|
+
if (!Array.isArray(value)) return void 0;
|
|
18920
|
+
return value.map((item) => safeSourcePreview(item).slice(0, 160)).filter((item) => item.length > 0);
|
|
18921
|
+
}
|
|
18922
|
+
function sanitizePlaygroundSource(source) {
|
|
18923
|
+
const record = asRecord(source);
|
|
18924
|
+
if (!record) return source;
|
|
18925
|
+
const safe = {};
|
|
18926
|
+
if (record.sourceRef !== void 0) safe.sourceRef = sanitizeGovernanceAuditValue(record.sourceRef, "sourceRef");
|
|
18927
|
+
if (record.sourceType !== void 0) safe.sourceType = sanitizeGovernanceAuditValue(record.sourceType, "sourceType");
|
|
18928
|
+
if (record.retrievalLayer !== void 0) safe.retrievalLayer = sanitizeGovernanceAuditValue(record.retrievalLayer, "retrievalLayer");
|
|
18929
|
+
if (record.summary !== void 0) safe.summary = sanitizeGovernanceAuditValue(record.summary, "summary");
|
|
18930
|
+
const eventIds = sanitizeStringArray(record.eventIds);
|
|
18931
|
+
if (eventIds) safe.eventIds = eventIds;
|
|
18932
|
+
const rawEvents = Array.isArray(record.rawEvents) ? record.rawEvents : [];
|
|
18933
|
+
safe.rawEvents = rawEvents.slice(0, SOURCE_EVENT_LIMIT).map(sanitizeSourceEvent);
|
|
18934
|
+
if (rawEvents.length > SOURCE_EVENT_LIMIT) {
|
|
18935
|
+
safe.omittedRawEventCount = rawEvents.length - SOURCE_EVENT_LIMIT;
|
|
18936
|
+
}
|
|
18937
|
+
if (record.primaryEvent !== void 0) safe.primaryEvent = sanitizeSourceEvent(record.primaryEvent);
|
|
18938
|
+
if (record.rawEvent !== void 0) safe.rawEvent = sanitizeSourceEvent(record.rawEvent);
|
|
18939
|
+
if (record.event !== void 0) safe.event = sanitizeSourceEvent(record.event);
|
|
18940
|
+
return safe;
|
|
18941
|
+
}
|
|
18942
|
+
function sanitizeScore(value) {
|
|
18943
|
+
const score = typeof value === "number" ? value : Number(value);
|
|
18944
|
+
return Number.isFinite(score) ? score : void 0;
|
|
18945
|
+
}
|
|
18946
|
+
function sanitizeReasons(value) {
|
|
18947
|
+
return sanitizeStringArray(value)?.slice(0, 8) ?? [];
|
|
18948
|
+
}
|
|
18949
|
+
function sanitizeSearchResult(result) {
|
|
18950
|
+
const record = asRecord(result);
|
|
18951
|
+
if (!record) return { snippet: safeSourcePreview(result) };
|
|
18952
|
+
const safe = {};
|
|
18953
|
+
if (record.id !== void 0) safe.id = sanitizeGovernanceAuditValue(record.id, "id");
|
|
18954
|
+
if (record.sourceRef !== void 0) safe.sourceRef = sanitizeGovernanceAuditValue(record.sourceRef, "sourceRef");
|
|
18955
|
+
if (record.resultType !== void 0) safe.resultType = sanitizeGovernanceAuditValue(record.resultType, "resultType");
|
|
18956
|
+
const score = sanitizeScore(record.score);
|
|
18957
|
+
if (score !== void 0) safe.score = score;
|
|
18958
|
+
safe.snippet = safeSourcePreview(record.snippet ?? record.preview ?? record.summary ?? "");
|
|
18959
|
+
if (record.preview !== void 0) safe.preview = safeSourcePreview(record.preview);
|
|
18960
|
+
safe.reasons = sanitizeReasons(record.reasons);
|
|
18961
|
+
return safe;
|
|
18962
|
+
}
|
|
18963
|
+
var PLAYGROUND_META_FIELDS = [
|
|
18964
|
+
"total",
|
|
18965
|
+
"totalMatches",
|
|
18966
|
+
"usedVector",
|
|
18967
|
+
"usedKeyword",
|
|
18968
|
+
"usedRerank",
|
|
18969
|
+
"queryTimeMs",
|
|
18970
|
+
"strategy"
|
|
18971
|
+
];
|
|
18972
|
+
function copySafeMetaValue(target, source, field) {
|
|
18973
|
+
const value = source[field];
|
|
18974
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
18975
|
+
target[field] = value;
|
|
18976
|
+
} else if (typeof value === "string") {
|
|
18977
|
+
target[field] = safeSourcePreview(value).slice(0, 160);
|
|
18978
|
+
}
|
|
18979
|
+
}
|
|
18980
|
+
function sanitizeMeta(meta) {
|
|
18981
|
+
const record = asRecord(meta);
|
|
18982
|
+
if (!record) return void 0;
|
|
18983
|
+
const safe = {};
|
|
18984
|
+
for (const field of PLAYGROUND_META_FIELDS) {
|
|
18985
|
+
copySafeMetaValue(safe, record, field);
|
|
18986
|
+
}
|
|
18987
|
+
return safe;
|
|
18988
|
+
}
|
|
18989
|
+
function sanitizePlaygroundSearch(search) {
|
|
18990
|
+
const record = asRecord(search);
|
|
18991
|
+
if (!record) return search;
|
|
18992
|
+
const safe = {
|
|
18993
|
+
results: Array.isArray(record.results) ? record.results.map(sanitizeSearchResult) : []
|
|
18994
|
+
};
|
|
18995
|
+
const meta = sanitizeMeta(record.meta);
|
|
18996
|
+
if (meta) safe.meta = meta;
|
|
18997
|
+
return safe;
|
|
18998
|
+
}
|
|
18999
|
+
function sanitizeExpansionFact(fact) {
|
|
19000
|
+
const record = asRecord(fact);
|
|
19001
|
+
if (!record) return { snippet: safeSourcePreview(fact) };
|
|
19002
|
+
const safe = {};
|
|
19003
|
+
if (record.id !== void 0) safe.id = sanitizeGovernanceAuditValue(record.id, "id");
|
|
19004
|
+
if (record.eventId !== void 0) safe.eventId = sanitizeGovernanceAuditValue(record.eventId, "eventId");
|
|
19005
|
+
if (record.sourceRef !== void 0) safe.sourceRef = sanitizeGovernanceAuditValue(record.sourceRef, "sourceRef");
|
|
19006
|
+
if (record.eventType !== void 0) safe.eventType = sanitizeGovernanceAuditValue(record.eventType, "eventType");
|
|
19007
|
+
if (record.sessionId !== void 0) safe.sessionId = sanitizeGovernanceAuditValue(record.sessionId, "sessionId");
|
|
19008
|
+
if (record.timestamp !== void 0) safe.timestamp = sanitizeGovernanceAuditValue(record.timestamp, "timestamp");
|
|
19009
|
+
const preview2 = safeSourcePreview(record.snippet ?? record.summary ?? record.preview ?? record.content ?? "");
|
|
19010
|
+
safe.snippet = preview2;
|
|
19011
|
+
safe.preview = preview2;
|
|
19012
|
+
return safe;
|
|
19013
|
+
}
|
|
19014
|
+
function sanitizeRelatedSource(source) {
|
|
19015
|
+
const record = asRecord(source);
|
|
19016
|
+
if (!record) return { preview: safeSourcePreview(source) };
|
|
19017
|
+
const safe = {};
|
|
19018
|
+
if (record.sourceRef !== void 0) safe.sourceRef = sanitizeGovernanceAuditValue(record.sourceRef, "sourceRef");
|
|
19019
|
+
const eventIds = sanitizeStringArray(record.eventIds);
|
|
19020
|
+
if (eventIds) safe.eventIds = eventIds;
|
|
19021
|
+
const previewSource = record.snippet ?? record.summary ?? record.preview;
|
|
19022
|
+
if (previewSource !== void 0) safe.preview = safeSourcePreview(previewSource);
|
|
19023
|
+
return safe;
|
|
19024
|
+
}
|
|
19025
|
+
function sanitizePlaygroundExpansion(expansion) {
|
|
19026
|
+
const record = asRecord(expansion);
|
|
19027
|
+
if (!record) return expansion;
|
|
19028
|
+
const safe = {};
|
|
19029
|
+
if (record.target !== void 0) safe.target = sanitizeSearchResult(record.target);
|
|
19030
|
+
safe.surroundingFacts = Array.isArray(record.surroundingFacts) ? record.surroundingFacts.slice(0, 12).map(sanitizeExpansionFact) : [];
|
|
19031
|
+
safe.relatedSources = Array.isArray(record.relatedSources) ? record.relatedSources.slice(0, 12).map(sanitizeRelatedSource) : [];
|
|
19032
|
+
return safe;
|
|
19033
|
+
}
|
|
19034
|
+
function selectedResultIdFrom(searchResult, requested) {
|
|
19035
|
+
if (requested && searchResult.results?.some((r) => r.id === requested || r.sourceRef === requested)) {
|
|
19036
|
+
return requested;
|
|
19037
|
+
}
|
|
19038
|
+
const first = searchResult.results?.[0];
|
|
19039
|
+
return first?.id ?? first?.sourceRef ?? null;
|
|
19040
|
+
}
|
|
19041
|
+
playgroundRouter.post("/dry-run", async (c) => {
|
|
19042
|
+
let body;
|
|
19043
|
+
try {
|
|
19044
|
+
body = await c.req.json();
|
|
19045
|
+
} catch {
|
|
19046
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
19047
|
+
}
|
|
19048
|
+
const query = body.query?.trim();
|
|
19049
|
+
if (!query) {
|
|
19050
|
+
return c.json({ error: "Query is required" }, 400);
|
|
19051
|
+
}
|
|
19052
|
+
const useFastStrategy = body.options?.strategy === "fast";
|
|
19053
|
+
const memoryService = useFastStrategy ? getLightweightServiceFromQuery(c) : getServiceFromQuery(c);
|
|
19054
|
+
const replayTrace = [];
|
|
19055
|
+
try {
|
|
19056
|
+
await memoryService.initialize();
|
|
19057
|
+
replayTrace.push("search");
|
|
19058
|
+
const search = await memoryService.searchDisclosure(query, disclosureOptions(body.options));
|
|
19059
|
+
const selectedResultId = selectedResultIdFrom(search, body.options?.selectedResultId);
|
|
19060
|
+
const safeSearch = sanitizePlaygroundSearch(search);
|
|
19061
|
+
if (!selectedResultId) {
|
|
19062
|
+
replayTrace.push("no-results");
|
|
19063
|
+
return c.json({
|
|
19064
|
+
dryRun: true,
|
|
19065
|
+
mutated: false,
|
|
19066
|
+
query,
|
|
19067
|
+
selectedResultId: null,
|
|
19068
|
+
search: safeSearch,
|
|
19069
|
+
expansion: null,
|
|
19070
|
+
source: null,
|
|
19071
|
+
replayTrace
|
|
19072
|
+
});
|
|
19073
|
+
}
|
|
19074
|
+
const windowSize = normalizeWindowSize(body.options?.windowSize);
|
|
19075
|
+
replayTrace.push(`expand:${selectedResultId}`);
|
|
19076
|
+
const expansion = sanitizePlaygroundExpansion(await memoryService.expandDisclosure(selectedResultId, { windowSize }));
|
|
19077
|
+
replayTrace.push(`source:${selectedResultId}`);
|
|
19078
|
+
const source = sanitizePlaygroundSource(await memoryService.sourceDisclosure(selectedResultId));
|
|
19079
|
+
return c.json({
|
|
19080
|
+
dryRun: true,
|
|
19081
|
+
mutated: false,
|
|
19082
|
+
query,
|
|
19083
|
+
selectedResultId,
|
|
19084
|
+
search: safeSearch,
|
|
19085
|
+
expansion,
|
|
19086
|
+
source,
|
|
19087
|
+
replayTrace
|
|
19088
|
+
});
|
|
19089
|
+
} catch (error) {
|
|
19090
|
+
return c.json({ error: safeSourcePreview(error.message), dryRun: true, mutated: false, replayTrace }, 500);
|
|
19091
|
+
} finally {
|
|
19092
|
+
await memoryService.shutdown();
|
|
19093
|
+
}
|
|
19094
|
+
});
|
|
19095
|
+
|
|
18662
19096
|
// src/apps/server/api/index.ts
|
|
18663
|
-
var apiRouter = new
|
|
19097
|
+
var apiRouter = new Hono11().route("/sessions", sessionsRouter).route("/events", eventsRouter).route("/search", searchRouter).route("/stats", statsRouter).route("/citations", citationsRouter).route("/turns", turnsRouter).route("/projects", projectsRouter).route("/chat", chatRouter).route("/health", healthRouter).route("/playground", playgroundRouter);
|
|
18664
19098
|
|
|
18665
19099
|
// src/apps/server/index.ts
|
|
18666
19100
|
var moduleDir = path17.dirname(fileUrlToPath(import.meta.url));
|
|
@@ -18821,7 +19255,7 @@ function createAuthOptions(options) {
|
|
|
18821
19255
|
};
|
|
18822
19256
|
}
|
|
18823
19257
|
function createDashboardApp(options = {}) {
|
|
18824
|
-
const app2 = new
|
|
19258
|
+
const app2 = new Hono12();
|
|
18825
19259
|
const authOptions = createAuthOptions(options);
|
|
18826
19260
|
app2.use("*", cors());
|
|
18827
19261
|
app2.use("*", logger());
|
|
@@ -21104,7 +21538,7 @@ async function runOperationCli(action, label) {
|
|
|
21104
21538
|
}
|
|
21105
21539
|
}
|
|
21106
21540
|
var program = new Command();
|
|
21107
|
-
program.name("claude-memory-layer").description("Claude Code Memory Plugin CLI").version("1.0.
|
|
21541
|
+
program.name("claude-memory-layer").description("Claude Code Memory Plugin CLI").version("1.0.50");
|
|
21108
21542
|
program.command("market-context").description("Fetch read-only DART/FRED/Finnhub context with structured MarketContextSnapshot bull/bear/risk/catalyst analysis").option("--company <name>", "Company name for DART fallback search and report subject").option("--dart-corp-code <code>", "Exact DART corp_code for issuer-specific filings").option("--symbol <ticker>", "Listed ticker for Finnhub company profile").option("--providers <list>", "Comma-separated providers: dart,fred,finnhub").option("--fred-series <list>", "Comma-separated FRED series IDs").option("--json", "Print structured JSON including analysis.marketSnapshot").option("--no-snapshot", "Disable MarketContextSnapshot and DART company snapshot analysis").action(async (options) => {
|
|
21109
21543
|
try {
|
|
21110
21544
|
await runMarketContextCommand(options);
|