scream-code 0.8.8 → 0.8.10

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.
@@ -122344,7 +122344,11 @@ const dictionaries = {
122344
122344
  "badge.loop": "循环",
122345
122345
  "badge.goal": "目标",
122346
122346
  "badge.auto": "自动",
122347
- "badge.yes": "YES"
122347
+ "badge.yes": "YES",
122348
+ "kw.lang_toggle": "English",
122349
+ "kw.embedding_downloading": "向量模型下载中…",
122350
+ "kw.embedding_failed": "向量模型加载失败(建议科学上网,5分钟后自动重试)",
122351
+ "kw.embedding_ready": "向量模型已就绪"
122348
122352
  },
122349
122353
  en: {
122350
122354
  "status.not_set": "Not set",
@@ -123403,7 +123407,11 @@ const dictionaries = {
123403
123407
  "badge.loop": "Loop",
123404
123408
  "badge.goal": "Goal",
123405
123409
  "badge.auto": "Auto",
123406
- "badge.yes": "YES"
123410
+ "badge.yes": "YES",
123411
+ "kw.lang_toggle": "中文",
123412
+ "kw.embedding_downloading": "Vector model downloading…",
123413
+ "kw.embedding_failed": "Vector model load failed (try VPN, auto-retry in 5 min)",
123414
+ "kw.embedding_ready": "Vector model ready"
123407
123415
  }
123408
123416
  };
123409
123417
  function detectSystemLocale() {
@@ -124856,7 +124864,7 @@ function optionalBuildString(value) {
124856
124864
  return typeof value === "string" && value.length > 0 ? value : void 0;
124857
124865
  }
124858
124866
  const SCREAM_BUILD_INFO = {
124859
- version: optionalBuildString("0.8.8"),
124867
+ version: optionalBuildString("0.8.10"),
124860
124868
  channel: optionalBuildString(""),
124861
124869
  commit: optionalBuildString(""),
124862
124870
  buildTarget: optionalBuildString("darwin-arm64")
@@ -136483,6 +136491,11 @@ function openUrl(url) {
136483
136491
  //#endregion
136484
136492
  //#region src/tui/commands/knowledge-store.ts
136485
136493
  let knowledgeStoreInstance;
136494
+ let embeddingEngineInstance;
136495
+ let embeddingStatus = "loading";
136496
+ let loadPromise;
136497
+ let embeddingRetryTimer;
136498
+ const EMBEDDING_RETRY_MS = 300 * 1e3;
136486
136499
  function getEmbeddingCacheDir() {
136487
136500
  const dir = join(getDataDir(), "cache", "fastembed");
136488
136501
  mkdirSync(dir, { recursive: true });
@@ -136492,10 +136505,51 @@ async function getKnowledgeStore() {
136492
136505
  if (knowledgeStoreInstance === void 0) {
136493
136506
  knowledgeStoreInstance = new KnowledgeStore(getDataDir());
136494
136507
  await knowledgeStoreInstance.init();
136495
- knowledgeStoreInstance.setEmbeddingEngine(createFastEmbedEngine(getEmbeddingCacheDir()));
136508
+ embeddingEngineInstance = createFastEmbedEngine(getEmbeddingCacheDir());
136509
+ knowledgeStoreInstance.setEmbeddingEngine(embeddingEngineInstance);
136510
+ loadPromise = triggerEmbeddingLoad();
136496
136511
  }
136497
136512
  return knowledgeStoreInstance;
136498
136513
  }
136514
+ function getEmbeddingStatus() {
136515
+ return embeddingStatus;
136516
+ }
136517
+ async function triggerEmbeddingLoad() {
136518
+ if (embeddingEngineInstance === void 0) return;
136519
+ embeddingStatus = "loading";
136520
+ if (await embeddingEngineInstance.ensureReady()) {
136521
+ embeddingStatus = "ready";
136522
+ stopRetryTimer();
136523
+ return;
136524
+ }
136525
+ embeddingStatus = "failed";
136526
+ startRetryTimer();
136527
+ }
136528
+ function startRetryTimer() {
136529
+ if (embeddingRetryTimer !== void 0) return;
136530
+ embeddingRetryTimer = setInterval(() => {
136531
+ loadPromise = triggerEmbeddingLoad();
136532
+ }, EMBEDDING_RETRY_MS);
136533
+ embeddingRetryTimer.unref?.();
136534
+ }
136535
+ function stopRetryTimer() {
136536
+ if (embeddingRetryTimer !== void 0) {
136537
+ clearInterval(embeddingRetryTimer);
136538
+ embeddingRetryTimer = void 0;
136539
+ }
136540
+ }
136541
+ /**
136542
+ * Wait for the embedding model to become ready.
136543
+ * Returns the current status. Callers can compare against 'ready'.
136544
+ * On failure the cached promise is cleared so subsequent calls retry.
136545
+ */
136546
+ async function waitForEmbedding() {
136547
+ if (loadPromise !== void 0) await loadPromise;
136548
+ return embeddingStatus;
136549
+ }
136550
+ function ensureEmbeddingReady() {
136551
+ if (loadPromise === void 0) loadPromise = getKnowledgeStore().then(() => triggerEmbeddingLoad());
136552
+ }
136499
136553
  //#endregion
136500
136554
  //#region src/tui/commands/knowledge-web.ts
136501
136555
  /**
@@ -136519,7 +136573,7 @@ const HTML = `<!doctype html>
136519
136573
  <head>
136520
136574
  <meta charset="utf-8">
136521
136575
  <meta name="viewport" content="width=device-width,initial-scale=1">
136522
- <title>__MSG_kw_title__</title>
136576
+ <title data-msg="kw_title">__MSG_kw_title__</title>
136523
136577
  <style>
136524
136578
  :root{
136525
136579
  --bg:#fafafa;--bg-soft:#f0f0f0;
@@ -136543,7 +136597,7 @@ body{background:var(--bg)}
136543
136597
  transition:color .2s;
136544
136598
  }
136545
136599
  .label-3d.root{color:var(--ink);font-weight:600;font-size:11px}
136546
- .label-3d.selected{color:var(--accent);font-weight:600;background:rgba(255,255,255,.95)}
136600
+ .label-3d.selected{color:#0d7a3e;font-weight:600;background:rgba(255,255,255,.95)}
136547
136601
  .label-3d.hover{color:var(--ink);background:rgba(255,255,255,.95)}
136548
136602
 
136549
136603
  #toolbar{
@@ -136653,27 +136707,43 @@ body{background:var(--bg)}
136653
136707
  <canvas id="scene"></canvas>
136654
136708
  <div id="labels"></div>
136655
136709
  <div id="toolbar">
136656
- <span class="chip">__MSG_kw_entity__<b id="stat-ent">0</b></span>
136657
- <span class="chip">__MSG_kw_event__<b id="stat-evt">0</b></span>
136658
- <span class="chip">__MSG_kw_relation__<b id="stat-edg">0</b></span>
136710
+ <span class="chip"><span data-msg="kw_entity">__MSG_kw_entity__</span><b id="stat-ent">0</b></span>
136711
+ <span class="chip"><span data-msg="kw_event">__MSG_kw_event__</span><b id="stat-evt">0</b></span>
136712
+ <span class="chip"><span data-msg="kw_relation">__MSG_kw_relation__</span><b id="stat-edg">0</b></span>
136659
136713
  <span class="sep"></span>
136660
136714
  <div id="search-wrap">
136661
136715
  <svg id="search-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
136662
136716
  <input id="search-input" type="text" placeholder="__MSG_kw_search_placeholder__" autocomplete="off" spellcheck="false">
136663
136717
  </div>
136664
136718
  <span class="sep"></span>
136665
- <button id="btn-reset">__MSG_kw_btn_reset__</button>
136666
- <button id="btn-expand">__MSG_kw_btn_expand__</button>
136719
+ <button id="btn-reset" data-msg="kw_btn_reset">__MSG_kw_btn_reset__</button>
136720
+ <button id="btn-expand" data-msg="kw_btn_expand">__MSG_kw_btn_expand__</button>
136721
+ <span class="sep"></span>
136722
+ <button id="btn-lang">__MSG_kw_lang_toggle__</button>
136667
136723
  </div>
136668
- <div id="hint"><b>__MSG_kw_hint_drag__</b></div>
136724
+ <div id="hint"><b data-msg="kw_hint_drag">__MSG_kw_hint_drag__</b></div>
136669
136725
  <div id="tooltip"></div>
136670
136726
  <div id="minimap"><canvas id="minimap-canvas"></canvas></div>
136671
136727
  <div id="modal-mask"></div>
136672
136728
  <div id="modal"><button class="close" id="btn-close">&times;</button><div id="modal-body"></div></div>
136673
- <div id="loading"><span class="dot"></span><span class="dot"></span><span class="dot"></span>__MSG_kw_loading__</div>
136729
+ <div id="loading"><span class="dot"></span><span class="dot"></span><span class="dot"></span><span data-msg="kw_loading">__MSG_kw_loading__</span></div>
136674
136730
  <div id="error-msg"></div>
136675
136731
 
136676
136732
  <script>
136733
+ var DICT=__DICT_INJECT__;
136734
+ var curLang='__LOCALE_INJECT__';
136735
+ function M(k){return(DICT[curLang]&&DICT[curLang][k])||k}
136736
+ function applyLang(){
136737
+ document.title=M('kw_title');
136738
+ document.querySelectorAll('[data-msg]').forEach(function(el){el.textContent=M(el.dataset.msg)});
136739
+ var ph=document.getElementById('search-input');if(ph)ph.placeholder=M('kw_search_placeholder');
136740
+ document.getElementById('btn-lang').textContent=M('kw_lang_toggle');
136741
+ }
136742
+ function toggleLang(){
136743
+ curLang=curLang==='zh'?'en':'zh';
136744
+ applyLang();
136745
+ if(typeof render==='function')render();
136746
+ }
136677
136747
  (function(){
136678
136748
  'use strict';
136679
136749
 
@@ -136682,7 +136752,7 @@ var TYPE_COLORS={
136682
136752
  product:'#db2777',metric:'#9333ea',action:'#dc2626',work:'#7c3aed',
136683
136753
  group:'#4f46e5',subject:'#0d9488',tags:'#666'
136684
136754
  };
136685
- var INK='#1a1a1a',ACCENT='#0066ff',EVENT='#9333ea';
136755
+ var INK='#1a1a1a',ACCENT='#0066ff',EVENT='#9333ea',SELECTED='#0d7a3e';
136686
136756
 
136687
136757
  // ─── Canvas ──────────────────────────────────────────
136688
136758
  var canvas=document.getElementById('scene');
@@ -136701,7 +136771,7 @@ window.addEventListener('resize',resize);
136701
136771
 
136702
136772
  // 相机
136703
136773
  var camRotX=0.25,camRotY=0.4;
136704
- var camDist=700;
136774
+ var camDist=500;
136705
136775
  var camTargetX=0,camTargetY=0,camTargetZ=0;
136706
136776
  var fov=600;
136707
136777
 
@@ -136891,10 +136961,10 @@ function drawEdges(projMap,connSet){
136891
136961
  var inConn=!connSet||connSet.has(e.entityId)&&connSet.has(e.eventId);
136892
136962
  var opacity;
136893
136963
  if(isDir)opacity=0.9;
136894
- else if(connSet&&!inConn)opacity=0.03;
136895
- else opacity=0.18;
136964
+ else if(connSet&&!inConn)opacity=0.08;
136965
+ else opacity=0.35;
136896
136966
  ctx.strokeStyle='rgba(0,0,0,'+opacity+')';
136897
- ctx.lineWidth=isDir?1.2:0.6;
136967
+ ctx.lineWidth=isDir?1.5:0.8;
136898
136968
  ctx.beginPath();
136899
136969
  ctx.moveTo(pa.x,pa.y);
136900
136970
  ctx.lineTo(pb.x,pb.y);
@@ -136909,21 +136979,22 @@ function drawNode(p,color,radius,isRoot,isSelected,isHover,isDimmed,isMatch){
136909
136979
  if(r<1){r=1;}
136910
136980
  var alpha=isDimmed?0.2:1;
136911
136981
 
136982
+ var nodeColor=isSelected?SELECTED:color;
136983
+
136912
136984
  if(isRoot){
136913
- // root 节点稍大,带细环
136914
- ctx.fillStyle='rgba(0,0,0,'+alpha+')';
136985
+ ctx.fillStyle=isSelected?'rgba(13,122,62,'+alpha+')':'rgba(0,0,0,'+alpha+')';
136915
136986
  ctx.beginPath();ctx.arc(p.x,p.y,r,0,Math.PI*2);ctx.fill();
136916
- ctx.strokeStyle='rgba(0,0,0,'+(0.3*alpha)+')';
136987
+ ctx.strokeStyle=isSelected?'rgba(13,122,62,'+(0.5*alpha)+')':'rgba(0,0,0,'+(0.3*alpha)+')';
136917
136988
  ctx.lineWidth=0.8;
136918
136989
  ctx.beginPath();ctx.arc(p.x,p.y,r+4,0,Math.PI*2);ctx.stroke();
136919
136990
  }else{
136920
- ctx.fillStyle='rgba(0,0,0,'+(0.7*alpha)+')';
136991
+ ctx.fillStyle=isSelected?'rgba(13,122,62,'+(0.9*alpha)+')':'rgba(0,0,0,'+(0.7*alpha)+')';
136921
136992
  ctx.beginPath();ctx.arc(p.x,p.y,r,0,Math.PI*2);ctx.fill();
136922
136993
  }
136923
136994
 
136924
- // 选中:蓝色细环
136995
+ // 选中:深绿色环
136925
136996
  if(isSelected){
136926
- ctx.strokeStyle=ACCENT;
136997
+ ctx.strokeStyle=SELECTED;
136927
136998
  ctx.lineWidth=1.2;
136928
136999
  ctx.beginPath();ctx.arc(p.x,p.y,r+5,0,Math.PI*2);ctx.stroke();
136929
137000
  }
@@ -136965,7 +137036,7 @@ function drawNodes(projMap,connSet){
136965
137036
  if(it.type==='entity'){
136966
137037
  var ent=it.data;
136967
137038
  var color=TYPE_COLORS[ent.type]||INK;
136968
- var radius=ent.isRoot?5:2.5+Math.min(2.5,(ent.eventCount||0)*0.3);
137039
+ var radius=ent.isRoot?6:3+Math.min(4,(ent.eventCount||0)*0.5);
136969
137040
  var isSel=selId===ent.id;
136970
137041
  var isHov=hoveredId===ent.id;
136971
137042
  var isDim=(connSet&&!connSet.has(ent.id))||(searchMatches&&!searchMatches.has(ent.id)&&ent.id!==selId);
@@ -136977,7 +137048,7 @@ function drawNodes(projMap,connSet){
136977
137048
  var isHov=hoveredId===ev.id;
136978
137049
  var isDim=(connSet&&!connSet.has(ev.id))||(searchMatches&&!searchMatches.has(ev.id)&&ev.id!==selId);
136979
137050
  var isMatch=searchMatches&&searchMatches.has(ev.id);
136980
- drawNode(it.p,EVENT,3,false,isSel,isHov,isDim,isMatch);
137051
+ drawNode(it.p,EVENT,4,false,isSel,isHov,isDim,isMatch);
136981
137052
  }
136982
137053
  }
136983
137054
  }
@@ -137089,7 +137160,7 @@ function showTooltip(sx,sy,id){
137089
137160
  if(data.kind==='entity'){
137090
137161
  var e=eById[id];if(!e)return;
137091
137162
  html+='<div class="tt-name">'+esc(e.name)+'</div>';
137092
- html+='<div class="tt-meta">'+esc(e.type)+' · '+(e.eventCount||0)+' __MSG_kw_event__</div>';
137163
+ html+='<div class="tt-meta">'+esc(e.type)+' · '+(e.eventCount||0)+' '+M('kw_event')+'</div>';
137093
137164
  }else{
137094
137165
  var ev=evById[id];if(!ev)return;
137095
137166
  html+='<div class="tt-name">'+esc(ev.title)+'</div>';
@@ -137132,6 +137203,7 @@ function pickNode(sx,sy){
137132
137203
  }
137133
137204
 
137134
137205
  canvas.addEventListener('mousedown',function(e){
137206
+ stopAutoRotate();
137135
137207
  mouseDownPos={x:e.clientX,y:e.clientY};
137136
137208
  isDragging=false;
137137
137209
  dragStart={x:e.clientX,y:e.clientY,rotX:camRotX,rotY:camRotY,panX:camTargetX,panY:camTargetY};
@@ -137165,18 +137237,26 @@ canvas.addEventListener('mousemove',function(e){
137165
137237
  }
137166
137238
  });
137167
137239
 
137240
+ var clickTimer=null,dblClickGuard=false;
137168
137241
  canvas.addEventListener('mouseup',function(e){
137169
137242
  if(isPanning){isPanning=false;canvas.style.cursor='grab';return;}
137170
137243
  if(isDragging){startInertia();canvas.style.cursor='grab';return;}
137244
+ if(dblClickGuard)return;
137171
137245
  var dx=e.clientX-mouseDownPos.x,dy=e.clientY-mouseDownPos.y;
137172
137246
  if(dx*dx+dy*dy>25)return;
137173
137247
  var id=pickNode(e.clientX,e.clientY);
137174
137248
  if(id){
137175
- var data=nodeData.find(function(n){return n.id===id});
137176
- if(data)toggleNode(id,data.kind);
137177
- selId=id;navStack=[];
137178
- focusOn(id);rebuildLabels();
137179
- if(data)showModal(id,data.kind);
137249
+ if(clickTimer){clearTimeout(clickTimer);clickTimer=null;return;}
137250
+ clickTimer=setTimeout(function(){
137251
+ clickTimer=null;
137252
+ var data=nodeData.find(function(n){return n.id===id});
137253
+ if(data){
137254
+ if(data.kind==='entity'&&!expEnt.has(id))expEnt.add(id);
137255
+ if(data.kind==='event'&&!expEv.has(id))expEv.add(id);
137256
+ }
137257
+ selId=id;navStack=[];
137258
+ focusOn(id);rebuildLabels();
137259
+ },250);
137180
137260
  }else{
137181
137261
  selId=null;rebuildLabels();closeModal();
137182
137262
  }
@@ -137185,8 +137265,19 @@ canvas.addEventListener('mouseup',function(e){
137185
137265
  canvas.addEventListener('contextmenu',function(e){e.preventDefault();});
137186
137266
  canvas.addEventListener('dblclick',function(e){
137187
137267
  e.preventDefault();
137268
+ if(clickTimer){clearTimeout(clickTimer);clickTimer=null;}
137269
+ dblClickGuard=true;
137270
+ setTimeout(function(){dblClickGuard=false;},300);
137188
137271
  var id=pickNode(e.clientX,e.clientY);
137189
- if(!id){
137272
+ if(id){
137273
+ var data=nodeData.find(function(n){return n.id===id});
137274
+ if(data){
137275
+ if(!expEnt.has(id)&&!expEv.has(id)){expEnt.add(id);}
137276
+ selId=id;navStack=[];
137277
+ focusOn(id);rebuildLabels();
137278
+ showModal(id,data.kind);
137279
+ }
137280
+ }else{
137190
137281
  expEnt.clear();expEv.clear();selId=null;
137191
137282
  if(graphData)graphData.entities.forEach(function(en){expEnt.add(en.id)});
137192
137283
  closeModal();rebuildLabels();fitView();
@@ -137194,6 +137285,7 @@ canvas.addEventListener('dblclick',function(e){
137194
137285
  });
137195
137286
 
137196
137287
  canvas.addEventListener('wheel',function(e){
137288
+ stopAutoRotate();
137197
137289
  e.preventDefault();
137198
137290
  var factor=e.deltaY>0?1.12:0.89;
137199
137291
  var newDist=Math.max(100,Math.min(2500,camDist*factor));
@@ -137240,9 +137332,41 @@ function fitView(){
137240
137332
  ids.forEach(function(id){var p=nodePositions[id];if(!p)return;if(p.x<x0)x0=p.x;if(p.x>x1)x1=p.x;if(p.y<y0)y0=p.y;if(p.y>y1)y1=p.y;if(p.z<z0)z0=p.z;if(p.z>z1)z1=p.z});
137241
137333
  var cx=(x0+x1)/2,cy=(y0+y1)/2,cz=(z0+z1)/2;
137242
137334
  var span=Math.max(x1-x0,y1-y0,z1-z0);
137243
- camTargetX=cx;camTargetY=cy;camTargetZ=cz;
137244
- camDist=Math.max(span*1.6,350);
137335
+ var endTx=cx,endTy=cy,endTz=cz;
137336
+ var endDist=Math.max(span*1.6,350);
137337
+ var startTx=camTargetX,startTy=camTargetY,startTz=camTargetZ,startDist=camDist;
137338
+ var startRotX=camRotX,startRotY=camRotY;
137339
+ var endRotX=0.25,endRotY=0.4;
137340
+ var startTime=performance.now();
137341
+ if(focusAnim)cancelAnimationFrame(focusAnim);
137342
+ function step(now){
137343
+ var t=Math.min(1,(now-startTime)/800);
137344
+ var e=t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2;
137345
+ camTargetX=startTx+(endTx-startTx)*e;
137346
+ camTargetY=startTy+(endTy-startTy)*e;
137347
+ camTargetZ=startTz+(endTz-startTz)*e;
137348
+ camDist=startDist+(endDist-startDist)*e;
137349
+ camRotX=startRotX+(endRotX-startRotX)*e;
137350
+ camRotY=startRotY+(endRotY-startRotY)*e;
137351
+ if(t<1)focusAnim=requestAnimationFrame(step);
137352
+ }
137353
+ focusAnim=requestAnimationFrame(step);
137354
+ }
137355
+
137356
+ var autoRotRAF=null;
137357
+ function startAutoRotate(){
137358
+ var duration=5000,startTime=performance.now();
137359
+ var speed=0.008;
137360
+ function step(now){
137361
+ var elapsed=now-startTime;
137362
+ var t=Math.min(1,elapsed/duration);
137363
+ var fade=1-t;
137364
+ camRotY+=speed*fade;
137365
+ if(t<1)autoRotRAF=requestAnimationFrame(step);
137366
+ }
137367
+ autoRotRAF=requestAnimationFrame(step);
137245
137368
  }
137369
+ function stopAutoRotate(){if(autoRotRAF){cancelAnimationFrame(autoRotRAF);autoRotRAF=null;}}
137246
137370
 
137247
137371
  // ─── 模态详情 ────────────────────────────────────────
137248
137372
  function showModal(id,kind,pushNav){
@@ -137251,23 +137375,24 @@ function showModal(id,kind,pushNav){
137251
137375
  var mask=document.getElementById('modal-mask');
137252
137376
  var body=document.getElementById('modal-body');
137253
137377
  var html='';
137254
- if(navStack.length>1)html+='<button class="back-btn" id="btn-back">← __MSG_kw_back__</button>';
137378
+ if(navStack.length>1)html+='<button class="back-btn" id="btn-back">← '+M('kw_back')+'</button>';
137255
137379
  if(kind==='entity'){
137256
137380
  var e=eById[id];
137257
137381
  html+='<div class="type-tag">'+esc(e.type)+'</div>';
137258
137382
  html+='<h3>'+esc(e.name)+'</h3>';
137259
- html+='<div class="field"><div class="label">__MSG_kw_detail_related__</div><div class="value">'+(e.eventCount||0)+'</div></div>';
137383
+ if(e.description)html+='<div class="field"><div class="label">'+M('kw_detail_description')+'</div><div class="value">'+esc(e.description)+'</div></div>';
137384
+ html+='<div class="field"><div class="label">'+M('kw_detail_related')+'</div><div class="value">'+(e.eventCount||0)+'</div></div>';
137260
137385
  var ce=evByEnt[id]||[];
137261
- if(ce.length){html+='<div class="divider"></div><div class="field"><div class="label">__MSG_kw_event__</div>';ce.forEach(function(eid){var ev=evById[eid];if(ev)html+='<div class="conn-item" data-id="'+eid+'" data-kind="event"><span>'+esc(ev.title)+'</span></div>'});html+='</div>'}
137386
+ if(ce.length){html+='<div class="divider"></div><div class="field"><div class="label">'+M('kw_event')+'</div>';ce.forEach(function(eid){var ev=evById[eid];if(ev)html+='<div class="conn-item" data-id="'+eid+'" data-kind="event"><span>'+esc(ev.title)+'</span></div>'});html+='</div>'}
137262
137387
  }else{
137263
137388
  var ev=evById[id];
137264
137389
  html+='<div class="type-tag event">EVENT</div>';
137265
137390
  html+='<h3>'+esc(ev.title)+'</h3>';
137266
- if(ev.summary)html+='<div class="field"><div class="label">__MSG_kw_detail_description__</div><div class="value">'+esc(ev.summary)+'</div></div>';
137267
- if(ev.category)html+='<div class="field"><div class="label">__MSG_kw_detail_category__</div><div class="value">'+esc(ev.category)+'</div></div>';
137268
- if(ev.keywords&&ev.keywords.length)html+='<div class="field"><div class="label">__MSG_kw_detail_keywords__</div><div class="value">'+ev.keywords.map(esc).join(' · ')+'</div></div>';
137391
+ if(ev.summary)html+='<div class="field"><div class="label">'+M('kw_detail_description')+'</div><div class="value">'+esc(ev.summary)+'</div></div>';
137392
+ if(ev.category)html+='<div class="field"><div class="label">'+M('kw_detail_category')+'</div><div class="value">'+esc(ev.category)+'</div></div>';
137393
+ if(ev.keywords&&ev.keywords.length)html+='<div class="field"><div class="label">'+M('kw_detail_keywords')+'</div><div class="value">'+ev.keywords.map(esc).join(' · ')+'</div></div>';
137269
137394
  var ce2=entByEv[id]||[];
137270
- if(ce2.length){html+='<div class="divider"></div><div class="field"><div class="label">__MSG_kw_detail_related__</div>';ce2.forEach(function(eid){var e=eById[eid];if(e)html+='<div class="conn-item" data-id="'+eid+'" data-kind="entity"><span>'+esc(e.name)+'</span><span class="badge">'+esc(e.type)+'</span></div>'});html+='</div>'}
137395
+ if(ce2.length){html+='<div class="divider"></div><div class="field"><div class="label">'+M('kw_detail_related')+'</div>';ce2.forEach(function(eid){var e=eById[eid];if(e)html+='<div class="conn-item" data-id="'+eid+'" data-kind="entity"><span>'+esc(e.name)+'</span><span class="badge">'+esc(e.type)+'</span></div>'});html+='</div>'}
137271
137396
  }
137272
137397
  body.innerHTML=html;
137273
137398
  modal.classList.add('open');mask.classList.add('open');
@@ -137502,7 +137627,7 @@ setTimeout(function(){
137502
137627
  if(document.getElementById('loading').style.display!=='none'){
137503
137628
  document.getElementById('loading').style.display='none';
137504
137629
  errorMsg.style.display='block';
137505
- errorMsg.innerHTML='<div style="font-size:14px;font-weight:600;margin-bottom:8px;">__MSG_kw_loading__</div><div style="color:#666;font-size:12px;">__MSG_kw_loading_timeout__</div>';
137630
+ errorMsg.innerHTML='<div style="font-size:14px;font-weight:600;margin-bottom:8px;">'+M('kw_loading')+'</div><div style="color:#666;font-size:12px;">'+M('kw_loading_timeout')+'</div>';
137506
137631
  }
137507
137632
  },8000);
137508
137633
 
@@ -137545,12 +137670,16 @@ fetch('/api/graph').then(function(r){return r.json()}).then(function(data){
137545
137670
  rebuildLabels();
137546
137671
  fitView();
137547
137672
  animate();
137673
+ startAutoRotate();
137548
137674
  }).catch(function(err){
137549
137675
  document.getElementById('loading').style.display='none';
137550
137676
  errorMsg.style.display='block';
137551
- errorMsg.innerHTML='<div style="font-size:14px;font-weight:600;margin-bottom:8px;">__MSG_kw_no_data__</div><div style="color:#666;font-size:12px;margin-bottom:12px;">'+esc(err.message)+'</div><div style="color:#999;font-size:11px;">__MSG_kw_no_data_hint__</div>';
137677
+ errorMsg.innerHTML='<div style="font-size:14px;font-weight:600;margin-bottom:8px;">'+M('kw_no_data')+'</div><div style="color:#666;font-size:12px;margin-bottom:12px;">'+esc(err.message)+'</div><div style="color:#999;font-size:11px;">'+M('kw_no_data_hint')+'</div>';
137552
137678
  });
137553
137679
 
137680
+ applyLang();
137681
+ document.getElementById('btn-lang').addEventListener('click',toggleLang);
137682
+
137554
137683
  })();
137555
137684
  <\/script>
137556
137685
  </body>
@@ -137570,13 +137699,14 @@ async function serveGraphJSON(store, res) {
137570
137699
  eventEntityMap.set(edge.eventId, list);
137571
137700
  }
137572
137701
  const data = {
137573
- entities: entities.map(({ id, sourceId, type, name, normalizedName, eventCount }) => ({
137702
+ entities: entities.map(({ id, sourceId, type, name, normalizedName, eventCount, description }) => ({
137574
137703
  id,
137575
137704
  sourceId,
137576
137705
  type,
137577
137706
  name,
137578
137707
  normalizedName,
137579
- eventCount
137708
+ eventCount,
137709
+ description
137580
137710
  })),
137581
137711
  events: events.map(({ id, sourceId, documentId, title, rank, summary, category, keywords }) => ({
137582
137712
  id,
@@ -137605,13 +137735,55 @@ async function serveGraphJSON(store, res) {
137605
137735
  res.end(JSON.stringify({ error: String(error) }));
137606
137736
  }
137607
137737
  }
137608
- function serveHTML(res) {
137738
+ function serveHTML(res, locale) {
137609
137739
  res.writeHead(200, {
137610
137740
  "Content-Type": "text/html; charset=utf-8",
137611
137741
  "Cache-Control": "no-store"
137612
137742
  });
137613
- const html = HTML.replace(/__MSG_([a-z0-9_]+)__/g, (_, key) => t(key));
137614
- res.end(html);
137743
+ const dictJson = JSON.stringify({
137744
+ zh: {
137745
+ kw_title: "知识图谱",
137746
+ kw_entity: "实体 ",
137747
+ kw_event: "事件 ",
137748
+ kw_relation: "关系 ",
137749
+ kw_search_placeholder: "搜索节点…",
137750
+ kw_btn_reset: "重置",
137751
+ kw_btn_expand: "展开",
137752
+ kw_hint_drag: "拖拽平移 · 滚轮缩放 · 单击展开 · 双击查看详情",
137753
+ kw_loading: "加载中…",
137754
+ kw_back: "返回",
137755
+ kw_detail_related: "关联",
137756
+ kw_detail_description: "描述",
137757
+ kw_detail_category: "分类",
137758
+ kw_detail_keywords: "关键词",
137759
+ kw_loading_timeout: "加载超时",
137760
+ kw_no_data: "暂无数据",
137761
+ kw_no_data_hint: "请先用 /knowledge 导入文档",
137762
+ kw_lang_toggle: "English"
137763
+ },
137764
+ en: {
137765
+ kw_title: "Knowledge Graph",
137766
+ kw_entity: "Entities ",
137767
+ kw_event: "Events ",
137768
+ kw_relation: "Relations ",
137769
+ kw_search_placeholder: "Search nodes…",
137770
+ kw_btn_reset: "Reset",
137771
+ kw_btn_expand: "Expand",
137772
+ kw_hint_drag: "Drag to pan · Scroll to zoom · Click to expand · Double-click for details",
137773
+ kw_loading: "Loading…",
137774
+ kw_back: "Back",
137775
+ kw_detail_related: "Related",
137776
+ kw_detail_description: "Description",
137777
+ kw_detail_category: "Category",
137778
+ kw_detail_keywords: "Keywords",
137779
+ kw_loading_timeout: "Loading timed out",
137780
+ kw_no_data: "No data",
137781
+ kw_no_data_hint: "Please ingest documents with /knowledge first",
137782
+ kw_lang_toggle: "中文"
137783
+ }
137784
+ });
137785
+ const injected = HTML.replace("__DICT_INJECT__", dictJson).replace("__LOCALE_INJECT__", locale);
137786
+ res.end(injected);
137615
137787
  }
137616
137788
  async function handleWeb(host) {
137617
137789
  const store = await getKnowledgeStore();
@@ -137622,7 +137794,7 @@ async function handleWeb(host) {
137622
137794
  serveGraphJSON(store, res);
137623
137795
  return;
137624
137796
  }
137625
- serveHTML(res);
137797
+ serveHTML(res, getLocale());
137626
137798
  });
137627
137799
  registerServer(server);
137628
137800
  await new Promise((resolve, reject) => {
@@ -138324,10 +138496,18 @@ async function handleKnowledgeCommand(host, _args) {
138324
138496
  description: t("knowledge.web_desc")
138325
138497
  }
138326
138498
  ];
138499
+ const formatEmbeddingHint = (status) => {
138500
+ switch (status) {
138501
+ case "ready": return "";
138502
+ case "loading": return " · " + t("kw.embedding_downloading");
138503
+ case "failed": return " · " + t("kw.embedding_failed");
138504
+ }
138505
+ };
138327
138506
  const showMenu = () => {
138507
+ const status = getEmbeddingStatus();
138328
138508
  const picker = new ChoicePickerComponent({
138329
138509
  title: t("knowledge.menu_title"),
138330
- hint: t("knowledge.menu_hint"),
138510
+ hint: t("knowledge.menu_hint") + formatEmbeddingHint(status),
138331
138511
  options,
138332
138512
  colors: host.state.theme.colors,
138333
138513
  onSelect: (value) => {
@@ -138352,6 +138532,15 @@ async function handleKnowledgeCommand(host, _args) {
138352
138532
  }
138353
138533
  });
138354
138534
  host.mountEditorReplacement(picker);
138535
+ if (status !== "ready") {
138536
+ ensureEmbeddingReady();
138537
+ waitForEmbedding().then((finalStatus) => {
138538
+ if (finalStatus === "ready") {
138539
+ host.showStatus(t("kw.embedding_ready"));
138540
+ showMenu();
138541
+ }
138542
+ });
138543
+ }
138355
138544
  };
138356
138545
  showMenu();
138357
138546
  }
@@ -145173,10 +145362,10 @@ var ErrorBannerComponent = class {
145173
145362
  };
145174
145363
  //#endregion
145175
145364
  //#region src/tui/components/chrome/plan-mode-banner.ts
145176
- const PLAN_LABEL = {
145177
- plan: t("planmode.plan"),
145178
- fusionplan: t("planmode.fusionplan")
145179
- };
145365
+ function getPlanLabel(mode) {
145366
+ if (mode === "fusionplan") return t("planmode.fusionplan");
145367
+ return t("planmode.plan");
145368
+ }
145180
145369
  var PlanModeBannerComponent = class {
145181
145370
  mode = "off";
145182
145371
  planPath;
@@ -145196,7 +145385,7 @@ var PlanModeBannerComponent = class {
145196
145385
  render(width) {
145197
145386
  if (this.mode === "off") return [];
145198
145387
  const tone = this.mode === "fusionplan" ? this.colors.fusionPlanMode : this.colors.planMode;
145199
- const label = PLAN_LABEL[this.mode];
145388
+ const label = getPlanLabel(this.mode);
145200
145389
  const prefix = `${chalk.hex(tone)(STATUS_BULLET)}${chalk.hex(tone).bold(label)}`;
145201
145390
  const basename = this.planPath !== void 0 && this.planPath.length > 0 ? path$1.basename(this.planPath) : void 0;
145202
145391
  if (basename === void 0 || basename.length === 0) return [truncateToWidth(prefix, width)];
@@ -146042,35 +146231,39 @@ function sessionRowsForPicker(sessions, currentSessionId, currentSessionHasConte
146042
146231
  }
146043
146232
  //#endregion
146044
146233
  //#region src/tui/reverse-rpc/approval/adapter.ts
146045
- const DEFAULT_APPROVAL_CHOICES = [
146046
- {
146047
- label: t("approval.allow_once"),
146048
- response: "approved"
146049
- },
146050
- {
146051
- label: t("approval.allow_session"),
146052
- response: "approved_for_session"
146053
- },
146054
- {
146234
+ function getDefaultApprovalChoices() {
146235
+ return [
146236
+ {
146237
+ label: t("approval.allow_once"),
146238
+ response: "approved"
146239
+ },
146240
+ {
146241
+ label: t("approval.allow_session"),
146242
+ response: "approved_for_session"
146243
+ },
146244
+ {
146245
+ label: t("approval.deny"),
146246
+ response: "rejected"
146247
+ },
146248
+ {
146249
+ label: t("approval.deny_feedback"),
146250
+ response: "rejected",
146251
+ requires_feedback: true
146252
+ }
146253
+ ];
146254
+ }
146255
+ function getPlanRejectChoices() {
146256
+ return [{
146055
146257
  label: t("approval.deny"),
146056
- response: "rejected"
146057
- },
146058
- {
146059
- label: t("approval.deny_feedback"),
146060
146258
  response: "rejected",
146259
+ selected_label: t("approval.deny")
146260
+ }, {
146261
+ label: t("approval.revise"),
146262
+ response: "rejected",
146263
+ selected_label: t("approval.revise"),
146061
146264
  requires_feedback: true
146062
- }
146063
- ];
146064
- const PLAN_REJECT_CHOICES = [{
146065
- label: t("approval.deny"),
146066
- response: "rejected",
146067
- selected_label: t("approval.deny")
146068
- }, {
146069
- label: t("approval.revise"),
146070
- response: "rejected",
146071
- selected_label: t("approval.revise"),
146072
- requires_feedback: true
146073
- }];
146265
+ }];
146266
+ }
146074
146267
  function adaptApprovalRequest(event) {
146075
146268
  const resolved = resolveDisplay(event.toolName, event.display, event.action);
146076
146269
  return {
@@ -146215,42 +146408,44 @@ function describeApproval(display, action) {
146215
146408
  default: return action;
146216
146409
  }
146217
146410
  }
146218
- const DANGER_PATTERNS = [
146219
- {
146220
- pattern: /\brm\s+(-[a-zA-Z]*[rRfF][a-zA-Z]*|--recursive|--force)/i,
146221
- label: t("approval.danger.recursive_delete")
146222
- },
146223
- {
146224
- pattern: /\bsudo\b/i,
146225
- label: "sudo"
146226
- },
146227
- {
146228
- pattern: /\b(curl|wget)\b[^|]*\|\s*(sh|bash|zsh)\b/i,
146229
- label: t("approval.danger.pipe_to_shell")
146230
- },
146231
- {
146232
- pattern: /\bdd\b[^|]*\bof=/i,
146233
- label: t("approval.danger.dd_write")
146234
- },
146235
- {
146236
- pattern: /\bmkfs\b/i,
146237
- label: "mkfs"
146238
- },
146239
- {
146240
- pattern: />\s*\/dev\/(sd|nvme|disk|hd)/i,
146241
- label: t("approval.danger.raw_device")
146242
- },
146243
- {
146244
- pattern: /\bchmod\s+-R?\s*777\b/i,
146245
- label: "chmod 777"
146246
- },
146247
- {
146248
- pattern: /:\(\)\s*\{\s*:\|:&\s*\}/i,
146249
- label: t("approval.danger.fork_bomb")
146250
- }
146251
- ];
146411
+ function getDangerPatterns() {
146412
+ return [
146413
+ {
146414
+ pattern: /\brm\s+(-[a-zA-Z]*[rRfF][a-zA-Z]*|--recursive|--force)/i,
146415
+ label: t("approval.danger.recursive_delete")
146416
+ },
146417
+ {
146418
+ pattern: /\bsudo\b/i,
146419
+ label: "sudo"
146420
+ },
146421
+ {
146422
+ pattern: /\b(curl|wget)\b[^|]*\|\s*(sh|bash|zsh)\b/i,
146423
+ label: t("approval.danger.pipe_to_shell")
146424
+ },
146425
+ {
146426
+ pattern: /\bdd\b[^|]*\bof=/i,
146427
+ label: t("approval.danger.dd_write")
146428
+ },
146429
+ {
146430
+ pattern: /\bmkfs\b/i,
146431
+ label: "mkfs"
146432
+ },
146433
+ {
146434
+ pattern: />\s*\/dev\/(sd|nvme|disk|hd)/i,
146435
+ label: t("approval.danger.raw_device")
146436
+ },
146437
+ {
146438
+ pattern: /\bchmod\s+-R?\s*777\b/i,
146439
+ label: "chmod 777"
146440
+ },
146441
+ {
146442
+ pattern: /:\(\)\s*\{\s*:\|:&\s*\}/i,
146443
+ label: t("approval.danger.fork_bomb")
146444
+ }
146445
+ ];
146446
+ }
146252
146447
  function detectDanger(command) {
146253
- for (const { pattern, label } of DANGER_PATTERNS) if (pattern.test(command)) return label;
146448
+ for (const { pattern, label } of getDangerPatterns()) if (pattern.test(command)) return label;
146254
146449
  }
146255
146450
  function adaptDisplay(display) {
146256
146451
  switch (display.kind) {
@@ -146327,7 +146522,7 @@ function adaptDisplay(display) {
146327
146522
  }
146328
146523
  function adaptChoices(toolName, display) {
146329
146524
  if (toolName === "ExitPlanMode" || display.kind === "plan_review") return adaptPlanReviewChoices(display);
146330
- return DEFAULT_APPROVAL_CHOICES.map((choice) => cloneChoice(choice));
146525
+ return getDefaultApprovalChoices().map((choice) => cloneChoice(choice));
146331
146526
  }
146332
146527
  function adaptPlanReviewChoices(display) {
146333
146528
  return [...display.kind === "plan_review" && display.options !== void 0 && display.options.length >= 2 ? display.options.map((option) => ({
@@ -146338,7 +146533,7 @@ function adaptPlanReviewChoices(display) {
146338
146533
  label: t("approval.approve"),
146339
146534
  response: "approved",
146340
146535
  selected_label: t("approval.approve")
146341
- }], ...PLAN_REJECT_CHOICES].map((choice) => cloneChoice(choice));
146536
+ }], ...getPlanRejectChoices()].map((choice) => cloneChoice(choice));
146342
146537
  }
146343
146538
  function cloneChoice(choice) {
146344
146539
  return { ...choice };
package/dist/main.mjs CHANGED
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
6
6
  import "./suppress-sqlite-warning-C2VB0doZ.mjs";
7
7
  //#region src/main.ts
8
8
  try {
9
- (await import("./app-DKYKW1st.mjs")).main();
9
+ (await import("./app-lrfUI96b.mjs")).main();
10
10
  } catch (error) {
11
11
  process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
12
12
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "A terminal-native AI agent for builders",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",