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 CHANGED
@@ -15996,7 +15996,7 @@ async function bootstrapKnowledgeBase(options) {
15996
15996
  }
15997
15997
 
15998
15998
  // src/apps/server/index.ts
15999
- import { Hono as Hono11 } from "hono";
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 Hono10 } from "hono";
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 = getServiceFromQuery(c);
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 = getServiceFromQuery(c);
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 Hono10().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);
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 Hono11();
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.48");
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);