jinzd-ai-cli 0.4.89 → 0.4.90

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.
@@ -4,9 +4,10 @@ import {
4
4
  pathTokens,
5
5
  rebuildSemanticIndex,
6
6
  semanticSearch
7
- } from "./chunk-GTKJUEBS.js";
7
+ } from "./chunk-MO7MWNWC.js";
8
8
  import "./chunk-BJAT4GNC.js";
9
- import "./chunk-XMA222FQ.js";
9
+ import "./chunk-PASCDYMH.js";
10
+ import "./chunk-JV5N65KN.js";
10
11
  export {
11
12
  buildEmbeddingText,
12
13
  hasSemanticIndex,
@@ -23,10 +23,10 @@ import {
23
23
  persistToolRound,
24
24
  rebuildExtraMessages,
25
25
  setupProxy
26
- } from "./chunk-FVRLRIKC.js";
26
+ } from "./chunk-DJGP7AR6.js";
27
27
  import {
28
28
  ConfigManager
29
- } from "./chunk-3O3U3L5W.js";
29
+ } from "./chunk-AB2LA33A.js";
30
30
  import {
31
31
  ToolExecutor,
32
32
  ToolRegistry,
@@ -44,7 +44,7 @@ import {
44
44
  spawnAgentContext,
45
45
  truncateOutput,
46
46
  undoStack
47
- } from "./chunk-ABPT6XCI.js";
47
+ } from "./chunk-G65IDWVP.js";
48
48
  import "./chunk-2ZD3YTVM.js";
49
49
  import "./chunk-4BKXL7SM.js";
50
50
  import "./chunk-ANYYM4CF.js";
@@ -53,7 +53,7 @@ import "./chunk-KJLJPUY2.js";
53
53
  import "./chunk-6VRJGH25.js";
54
54
  import "./chunk-2DXY7UGF.js";
55
55
  import "./chunk-KHYD3WXE.js";
56
- import "./chunk-TKYNTXKB.js";
56
+ import "./chunk-EEEAFWNK.js";
57
57
  import {
58
58
  AGENTIC_BEHAVIOR_GUIDELINE,
59
59
  AUTHOR,
@@ -72,7 +72,7 @@ import {
72
72
  SKILLS_DIR_NAME,
73
73
  VERSION,
74
74
  buildUserIdentityPrompt
75
- } from "./chunk-E7YC4GWV.js";
75
+ } from "./chunk-WPQ4D6T3.js";
76
76
 
77
77
  // src/web/server.ts
78
78
  import express from "express";
@@ -622,6 +622,12 @@ var SessionHandler = class _SessionHandler {
622
622
  }
623
623
  return;
624
624
  }
625
+ case "memory_search":
626
+ return this.handleMemorySearch(msg.query, msg.topK, msg.minScore, msg.excludeCurrentSession);
627
+ case "memory_status_request":
628
+ return this.handleMemoryStatus();
629
+ case "memory_rebuild":
630
+ return this.handleMemoryRebuild(Boolean(msg.full));
625
631
  case "auto_pause_response": {
626
632
  const resolve3 = this.pendingAutoPause.get(msg.requestId);
627
633
  if (resolve3) {
@@ -2231,7 +2237,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2231
2237
  case "test": {
2232
2238
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2233
2239
  try {
2234
- const { executeTests } = await import("./run-tests-5TO5G3YH.js");
2240
+ const { executeTests } = await import("./run-tests-2DYVHTIH.js");
2235
2241
  const argStr = args.join(" ").trim();
2236
2242
  let testArgs = {};
2237
2243
  if (argStr) {
@@ -2745,6 +2751,106 @@ Add .md files to create commands.` });
2745
2751
  this.send({ type: "error", message: `Failed to clear memory: ${err.message}` });
2746
2752
  }
2747
2753
  }
2754
+ // ── B4 chat memory recall (v0.4.90+) ──────────────────────────────
2755
+ // Lazy-imported so the 117 MB embedder stays out of the load path for
2756
+ // clients that never open the Memory panel.
2757
+ async handleMemorySearch(query, topK, minScore, excludeCurrent) {
2758
+ const q = (query ?? "").trim();
2759
+ if (!q) {
2760
+ this.send({ type: "error", message: "Memory search: query is empty." });
2761
+ return;
2762
+ }
2763
+ try {
2764
+ const { searchChatMemory, loadChatIndex } = await import("./chat-index-W2UZ34ZI.js");
2765
+ const loaded = loadChatIndex();
2766
+ if (!loaded || loaded.idx.chunks.length === 0) {
2767
+ this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
2768
+ return;
2769
+ }
2770
+ const hits = await searchChatMemory(q, {
2771
+ topK: topK ?? 8,
2772
+ minScore: minScore ?? 0.2,
2773
+ excludeSessionId: excludeCurrent ? this.sessions.current?.id : void 0
2774
+ });
2775
+ this.send({
2776
+ type: "memory_hits",
2777
+ query: q,
2778
+ hits: hits.map((h) => ({
2779
+ id: h.chunk.id,
2780
+ sessionId: h.chunk.sessionId,
2781
+ sessionTitle: h.chunk.sessionTitle,
2782
+ provider: h.chunk.provider,
2783
+ model: h.chunk.model,
2784
+ timestamp: h.chunk.timestamp,
2785
+ score: h.score,
2786
+ text: h.chunk.text,
2787
+ startMessageIdx: h.chunk.startMessageIdx,
2788
+ endMessageIdx: h.chunk.endMessageIdx
2789
+ }))
2790
+ });
2791
+ } catch (err) {
2792
+ this.send({
2793
+ type: "error",
2794
+ message: `Memory search failed: ${err instanceof Error ? err.message : String(err)}`
2795
+ });
2796
+ }
2797
+ }
2798
+ async handleMemoryStatus() {
2799
+ try {
2800
+ const { getChatIndexStatus } = await import("./chat-index-W2UZ34ZI.js");
2801
+ const s = getChatIndexStatus();
2802
+ this.send({
2803
+ type: "memory_status",
2804
+ exists: s.exists,
2805
+ chunks: s.chunks,
2806
+ sessions: s.sessions,
2807
+ built: s.built,
2808
+ model: s.model,
2809
+ vecFileSizeBytes: s.vecFileSizeBytes,
2810
+ chunksFileSizeBytes: s.chunksFileSizeBytes
2811
+ });
2812
+ } catch (err) {
2813
+ this.send({
2814
+ type: "error",
2815
+ message: `Memory status failed: ${err instanceof Error ? err.message : String(err)}`
2816
+ });
2817
+ }
2818
+ }
2819
+ async handleMemoryRebuild(full) {
2820
+ try {
2821
+ this.send({
2822
+ type: "info",
2823
+ message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
2824
+ });
2825
+ const { buildChatIndex } = await import("./chat-index-W2UZ34ZI.js");
2826
+ const stats = await buildChatIndex({
2827
+ full,
2828
+ onProgress: (p) => {
2829
+ this.send({
2830
+ type: "memory_rebuild_progress",
2831
+ stage: p.stage,
2832
+ processed: p.processed,
2833
+ total: p.total
2834
+ });
2835
+ }
2836
+ });
2837
+ this.send({
2838
+ type: "memory_rebuild_done",
2839
+ chunksTotal: stats.chunksTotal,
2840
+ chunksAdded: stats.chunksAdded,
2841
+ chunksRemoved: stats.chunksRemoved,
2842
+ sessionsIndexed: stats.sessionsIndexed,
2843
+ sessionsSkipped: stats.sessionsSkipped,
2844
+ durationMs: stats.durationMs
2845
+ });
2846
+ await this.handleMemoryStatus();
2847
+ } catch (err) {
2848
+ this.send({
2849
+ type: "error",
2850
+ message: `Memory rebuild failed: ${err instanceof Error ? err.message : String(err)}`
2851
+ });
2852
+ }
2853
+ }
2748
2854
  sendSessionMessages() {
2749
2855
  const session = this.sessions.current;
2750
2856
  if (!session) return;
@@ -3,7 +3,7 @@ import {
3
3
  ToolRegistry,
4
4
  getDangerLevel,
5
5
  schemaToJsonSchema
6
- } from "./chunk-ABPT6XCI.js";
6
+ } from "./chunk-G65IDWVP.js";
7
7
  import "./chunk-2ZD3YTVM.js";
8
8
  import "./chunk-4BKXL7SM.js";
9
9
  import "./chunk-ANYYM4CF.js";
@@ -12,10 +12,10 @@ import "./chunk-KJLJPUY2.js";
12
12
  import "./chunk-6VRJGH25.js";
13
13
  import "./chunk-2DXY7UGF.js";
14
14
  import "./chunk-KHYD3WXE.js";
15
- import "./chunk-TKYNTXKB.js";
15
+ import "./chunk-EEEAFWNK.js";
16
16
  import {
17
17
  VERSION
18
- } from "./chunk-E7YC4GWV.js";
18
+ } from "./chunk-WPQ4D6T3.js";
19
19
 
20
20
  // src/mcp/server.ts
21
21
  import { createInterface } from "readline";
@@ -4,7 +4,7 @@ import {
4
4
  getDangerLevel,
5
5
  googleSearchContext,
6
6
  truncateOutput
7
- } from "./chunk-ABPT6XCI.js";
7
+ } from "./chunk-G65IDWVP.js";
8
8
  import "./chunk-2ZD3YTVM.js";
9
9
  import "./chunk-4BKXL7SM.js";
10
10
  import "./chunk-ANYYM4CF.js";
@@ -13,10 +13,10 @@ import "./chunk-KJLJPUY2.js";
13
13
  import "./chunk-6VRJGH25.js";
14
14
  import "./chunk-2DXY7UGF.js";
15
15
  import "./chunk-KHYD3WXE.js";
16
- import "./chunk-TKYNTXKB.js";
16
+ import "./chunk-EEEAFWNK.js";
17
17
  import {
18
18
  SUBAGENT_ALLOWED_TOOLS
19
- } from "./chunk-E7YC4GWV.js";
19
+ } from "./chunk-WPQ4D6T3.js";
20
20
 
21
21
  // src/hub/task-orchestrator.ts
22
22
  import { createInterface } from "readline";
@@ -4,7 +4,8 @@ import {
4
4
  loadVectorStore,
5
5
  saveVectorStore,
6
6
  searchVectorStore
7
- } from "./chunk-XMA222FQ.js";
7
+ } from "./chunk-PASCDYMH.js";
8
+ import "./chunk-JV5N65KN.js";
8
9
  export {
9
10
  clearVectorStore,
10
11
  emptyVectorStore,
@@ -187,6 +187,10 @@ function handleServerMessage(msg) {
187
187
  case 'tools_list': renderToolsList(msg); switchSidebarTab('tools'); break;
188
188
  case 'export_data': handleExportData(msg); break;
189
189
  case 'memory_content': handleMemoryContent(msg); break;
190
+ case 'memory_hits': renderMemoryHits(msg); break;
191
+ case 'memory_status': renderMemoryStatus(msg); break;
192
+ case 'memory_rebuild_progress': renderMemoryRebuildProgress(msg); break;
193
+ case 'memory_rebuild_done': renderMemoryRebuildDone(msg); break;
190
194
  case 'auth_required': showAuthScreen(msg.hasUsers); break;
191
195
  case 'auth_result': handleAuthResult(msg); break;
192
196
  case 'info': addInfoMessage(msg.message); break;
@@ -2869,3 +2873,200 @@ function showEnableAuthDialog() {
2869
2873
  })
2870
2874
  .catch(err => alert('Failed: ' + err.message));
2871
2875
  }
2876
+
2877
+ // ── B4 Chat Memory recall panel (v0.4.90+) ────────────────────────────
2878
+ // UI for the semantic index built from all past sessions. The tab is
2879
+ // opt-in: we only request a status refresh + wire handlers when the
2880
+ // user actually clicks 🧠 Memory, so unused sessions pay zero cost.
2881
+
2882
+ let memoryPanelInit = false;
2883
+ let memoryStatusCache = null;
2884
+
2885
+ function initMemoryPanel() {
2886
+ if (memoryPanelInit) return;
2887
+ memoryPanelInit = true;
2888
+
2889
+ const input = document.getElementById('memory-search-input');
2890
+ const btnSearch = document.getElementById('btn-memory-search');
2891
+ const btnRefresh = document.getElementById('btn-memory-refresh');
2892
+ const btnRebuild = document.getElementById('btn-memory-rebuild');
2893
+
2894
+ const runSearch = () => {
2895
+ const q = (input?.value || '').trim();
2896
+ if (!q) return;
2897
+ const excl = document.getElementById('memory-exclude-current')?.checked;
2898
+ const hitsEl = document.getElementById('memory-hits');
2899
+ if (hitsEl) {
2900
+ hitsEl.innerHTML = '<div class="text-xs opacity-40 text-center py-4">Searching…</div>';
2901
+ }
2902
+ send({
2903
+ type: 'memory_search',
2904
+ query: q,
2905
+ topK: 8,
2906
+ minScore: 0.2,
2907
+ excludeCurrentSession: !!excl,
2908
+ });
2909
+ };
2910
+
2911
+ btnSearch?.addEventListener('click', runSearch);
2912
+ input?.addEventListener('keydown', (e) => {
2913
+ if (e.key === 'Enter') {
2914
+ e.preventDefault();
2915
+ runSearch();
2916
+ }
2917
+ });
2918
+
2919
+ btnRefresh?.addEventListener('click', () => {
2920
+ send({ type: 'memory_rebuild', full: false });
2921
+ });
2922
+ btnRebuild?.addEventListener('click', () => {
2923
+ if (!confirm('Full rebuild re-embeds every chat chunk. On first run this downloads ~117 MB and can take minutes. Continue?')) return;
2924
+ send({ type: 'memory_rebuild', full: true });
2925
+ });
2926
+
2927
+ send({ type: 'memory_status_request' });
2928
+ }
2929
+
2930
+ function renderMemoryStatus(msg) {
2931
+ memoryStatusCache = msg;
2932
+ const el = document.getElementById('memory-status');
2933
+ if (!el) return;
2934
+ if (!msg.exists) {
2935
+ el.textContent = 'Index not built — click ⟳ Rebuild to create it.';
2936
+ el.className = 'text-xs opacity-70 truncate';
2937
+ return;
2938
+ }
2939
+ const built = msg.built ? msg.built.replace('T', ' ').slice(0, 16) : '-';
2940
+ const mb = ((msg.vecFileSizeBytes + msg.chunksFileSizeBytes) / 1024 / 1024).toFixed(2);
2941
+ el.textContent = `${msg.chunks} chunks · ${msg.sessions} sessions · ${mb} MB · built ${built}`;
2942
+ el.className = 'text-xs opacity-50 truncate';
2943
+ el.title = `model: ${msg.model || '-'}`;
2944
+ }
2945
+
2946
+ function renderMemoryHits(msg) {
2947
+ const el = document.getElementById('memory-hits');
2948
+ if (!el) return;
2949
+ if (msg.indexMissing) {
2950
+ el.innerHTML = '<div class="text-xs opacity-60 text-center py-4">Chat index is empty — click ⟳ Rebuild first.</div>';
2951
+ return;
2952
+ }
2953
+ if (!msg.hits || msg.hits.length === 0) {
2954
+ el.innerHTML = `<div class="text-xs opacity-60 text-center py-4">No memories matched "${escapeHtml(msg.query)}".<br>Try a broader phrase or lower minScore.</div>`;
2955
+ return;
2956
+ }
2957
+ // Cache hit texts on the container so inject buttons can find them by id
2958
+ // without us having to embed full-text in data-* attrs (would bloat DOM).
2959
+ memoryHitsCache = new Map();
2960
+ for (const h of msg.hits) memoryHitsCache.set(h.id, h);
2961
+
2962
+ // Top toolbar: inject top-3 / clear results.
2963
+ const header = `
2964
+ <div class="flex items-center gap-1 text-xs pb-1 mb-1 border-b border-base-content/10">
2965
+ <span class="opacity-60 flex-1">${msg.hits.length} hit(s) for "${escapeHtml(msg.query)}"</span>
2966
+ <button class="btn btn-xs btn-primary btn-outline" id="btn-memory-inject-top3" title="Inject top 3 hits into chat input as a quoted context block">➕ Inject top 3</button>
2967
+ </div>
2968
+ `;
2969
+
2970
+ const items = msg.hits.map((h) => {
2971
+ const ts = (h.timestamp || '').replace('T', ' ').slice(0, 16);
2972
+ const title = h.sessionTitle || h.sessionId.slice(0, 8);
2973
+ const score = typeof h.score === 'number' ? h.score.toFixed(3) : '-';
2974
+ const preview = h.text.length > 500 ? h.text.slice(0, 500) + '…' : h.text;
2975
+ return `
2976
+ <div class="memory-hit card bg-base-100 border border-base-content/10 p-2 hover:border-primary/40"
2977
+ data-hit-id="${escapeHtml(h.id)}">
2978
+ <div class="flex items-center gap-1 text-xs opacity-70 mb-1">
2979
+ <span class="font-semibold truncate flex-1">${escapeHtml(title)}</span>
2980
+ <span class="badge badge-xs">${score}</span>
2981
+ </div>
2982
+ <div class="text-xs opacity-50 mb-1 flex items-center gap-2">
2983
+ <span class="flex-1">${ts} · session ${escapeHtml(h.sessionId.slice(0, 8))}</span>
2984
+ <button class="btn btn-xs btn-ghost memory-hit-inject" title="Inject this hit into chat input">➕</button>
2985
+ <button class="btn btn-xs btn-ghost memory-hit-load" title="Load this session in current tab">↗</button>
2986
+ </div>
2987
+ <div class="text-xs whitespace-pre-wrap leading-snug opacity-90" style="max-height: 8em; overflow: hidden;">${escapeHtml(preview)}</div>
2988
+ </div>
2989
+ `;
2990
+ }).join('');
2991
+ el.innerHTML = header + items;
2992
+
2993
+ document.getElementById('btn-memory-inject-top3')?.addEventListener('click', (e) => {
2994
+ e.stopPropagation();
2995
+ injectMemoryHits(msg.hits.slice(0, 3));
2996
+ });
2997
+ el.querySelectorAll('.memory-hit').forEach((card) => {
2998
+ const hitId = card.getAttribute('data-hit-id');
2999
+ const h = hitId ? memoryHitsCache.get(hitId) : null;
3000
+ if (!h) return;
3001
+ card.querySelector('.memory-hit-inject')?.addEventListener('click', (e) => {
3002
+ e.stopPropagation();
3003
+ injectMemoryHits([h]);
3004
+ });
3005
+ card.querySelector('.memory-hit-load')?.addEventListener('click', (e) => {
3006
+ e.stopPropagation();
3007
+ loadSessionInTab(h.sessionId, h.sessionTitle || '');
3008
+ });
3009
+ });
3010
+ }
3011
+
3012
+ /**
3013
+ * Inject one or more memory hits into the chat input as a quoted context
3014
+ * block. User can then edit or add their question before sending, giving
3015
+ * them full control over what lands in the AI's context (vs automatic
3016
+ * injection which is surprising).
3017
+ */
3018
+ function injectMemoryHits(hits) {
3019
+ if (!hits || hits.length === 0) return;
3020
+ const lines = ['> 🧠 Recalled from past sessions:', '>'];
3021
+ for (const h of hits) {
3022
+ const ts = (h.timestamp || '').replace('T', ' ').slice(0, 16);
3023
+ const title = h.sessionTitle || h.sessionId.slice(0, 8);
3024
+ const body = h.text.length > 800 ? h.text.slice(0, 800) + '…' : h.text;
3025
+ lines.push(`> **${title}** · ${ts}`);
3026
+ for (const ln of body.split('\n')) lines.push(`> ${ln}`);
3027
+ lines.push('>');
3028
+ }
3029
+ lines.push('');
3030
+ const block = lines.join('\n');
3031
+ const existing = userInput?.value || '';
3032
+ if (userInput) {
3033
+ // Prepend — user's in-progress question stays after the quoted block.
3034
+ userInput.value = block + existing;
3035
+ // Fire input event so the auto-resize textarea adapts its height.
3036
+ userInput.dispatchEvent(new Event('input', { bubbles: true }));
3037
+ userInput.focus();
3038
+ // Move caret to end so user can keep typing.
3039
+ const len = userInput.value.length;
3040
+ try { userInput.setSelectionRange(len, len); } catch { /* ignore */ }
3041
+ }
3042
+ addInfoMessage(`🧠 Injected ${hits.length} memory hit(s) into input. Edit and send when ready.`);
3043
+ }
3044
+
3045
+ let memoryHitsCache = new Map();
3046
+
3047
+ function renderMemoryRebuildProgress(msg) {
3048
+ const el = document.getElementById('memory-status');
3049
+ if (!el) return;
3050
+ if (msg.stage === 'embedding' && msg.total) {
3051
+ el.textContent = `Embedding ${msg.processed || 0} / ${msg.total} chunks…`;
3052
+ } else if (msg.stage !== 'done') {
3053
+ el.textContent = `${msg.stage}…`;
3054
+ }
3055
+ el.className = 'text-xs opacity-70 truncate';
3056
+ }
3057
+
3058
+ function renderMemoryRebuildDone(msg) {
3059
+ const el = document.getElementById('memory-status');
3060
+ if (el) {
3061
+ el.textContent = `✓ ${msg.chunksTotal} chunks (+${msg.chunksAdded} / −${msg.chunksRemoved}) · ${msg.sessionsIndexed} re-indexed · ${(msg.durationMs / 1000).toFixed(1)}s`;
3062
+ el.className = 'text-xs opacity-70 truncate';
3063
+ }
3064
+ }
3065
+
3066
+ // Lazy-init memory panel on first click of the 🧠 Memory sidebar tab.
3067
+ // switchSidebarTab already toggles visibility — we just need to bootstrap.
3068
+ document.querySelectorAll('.sidebar-tab').forEach(btn => {
3069
+ if (btn.dataset.tab === 'memory') {
3070
+ btn.addEventListener('click', () => initMemoryPanel());
3071
+ }
3072
+ });
@@ -108,6 +108,7 @@
108
108
  <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="branches" title="Conversation branches (B2)">🌿 Branches</button>
109
109
  <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="tools">🔧 Tools</button>
110
110
  <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="files">📁 Files</button>
111
+ <button class="sidebar-tab flex-1 text-xs font-semibold py-2 px-1 text-center" data-tab="memory" title="Chat memory semantic recall (B4, v0.4.90)">🧠 Memory</button>
111
112
  </div>
112
113
  <!-- Sessions tab -->
113
114
  <div id="tab-sessions" class="sidebar-tab-content flex flex-col flex-1 overflow-hidden">
@@ -158,6 +159,29 @@
158
159
  <div class="text-xs opacity-40 text-center py-4">Click tab to load</div>
159
160
  </div>
160
161
  </div>
162
+
163
+ <!-- Memory tab (B4, v0.4.90+) -->
164
+ <div id="tab-memory" class="sidebar-tab-content flex flex-col flex-1 overflow-hidden hidden">
165
+ <div class="p-2 border-b border-base-content/10 flex flex-col gap-1">
166
+ <div class="flex items-center gap-1">
167
+ <input id="memory-search-input" type="text" class="input input-xs input-bordered flex-1 min-w-0" placeholder="Search past chats (semantic)…">
168
+ <button id="btn-memory-search" class="btn btn-xs btn-primary btn-outline flex-shrink-0" title="Search">🔍</button>
169
+ </div>
170
+ <div class="flex items-center gap-1 text-xs">
171
+ <label class="flex items-center gap-1 opacity-70 cursor-pointer">
172
+ <input id="memory-exclude-current" type="checkbox" class="checkbox checkbox-xs">
173
+ <span>exclude current</span>
174
+ </label>
175
+ <span class="flex-1"></span>
176
+ <button id="btn-memory-refresh" class="btn btn-xs btn-ghost" title="Incremental refresh">↻</button>
177
+ <button id="btn-memory-rebuild" class="btn btn-xs btn-ghost" title="Full rebuild (slow first run)">⟳ Rebuild</button>
178
+ </div>
179
+ <div id="memory-status" class="text-xs opacity-50 truncate">Loading index status…</div>
180
+ </div>
181
+ <div id="memory-hits" class="flex-1 overflow-y-auto p-2 flex flex-col gap-2 text-sm">
182
+ <div class="text-xs opacity-40 text-center py-4">Type a query above to recall past chats.</div>
183
+ </div>
184
+ </div>
161
185
  </aside>
162
186
  <!-- Sidebar resize handle -->
163
187
  <div id="sidebar-resize" class="sidebar-resize-handle" title="Drag to resize sidebar"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.89",
3
+ "version": "0.4.90",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",