dsh-mnemon-source-memory-spaces 0.5.20 → 0.5.22

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/lib/client.js CHANGED
@@ -4,8 +4,31 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
7
29
  let react = require("react");
8
30
  let dsh_mnemon_client = require("dsh-mnemon/client");
31
+ dsh_mnemon_client = __toESM(dsh_mnemon_client, 1);
9
32
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
33
  let react_jsx_runtime = require("react/jsx-runtime");
11
34
  //#region presentation/locales.json
@@ -375,7 +398,129 @@ window.__ModuleLoader__.load({
375
398
  "overview.rediscoveryFailed": "{provider} 无法完成发现:{error}",
376
399
  "overview.rediscoveryTimedOut": "{provider} 没有按时响应,稍后可以再次发现。",
377
400
  "overview.rediscoveryDismiss": "知道了",
378
- "overview.newSpace": "新发现"
401
+ "overview.newSpace": "新发现",
402
+ "common.copyId": "复制 ID",
403
+ "common.readOnly": "只读模式",
404
+ "common.activationOnly": "仅可切换激活状态",
405
+ "common.active": "已激活",
406
+ "common.category": "分类",
407
+ "common.importanceLabel": "重要性",
408
+ "common.importance": "重要性 {value}",
409
+ "common.hops": "{count} 跳",
410
+ "common.allCategories": "全部分类",
411
+ "common.memories": "{count} 条记忆",
412
+ "common.edges": "{count} 条连接",
413
+ "card.confirmText": "软删除这条记忆?",
414
+ "card.processing": "处理中…",
415
+ "card.confirmForget": "确认忘记",
416
+ "card.related": "查看关联",
417
+ "card.clone": "基于此新建",
418
+ "card.forget": "忘记",
419
+ "readSources.all": "全部 Provider",
420
+ "readSources.mode.search": "原生检索",
421
+ "readSources.mode.graph": "真实关系图",
422
+ "readSources.mode.projection": "内容投影",
423
+ "readSources.mode.enumerable": "可枚举内容",
424
+ "readSources.mode.query-only": "仅查询",
425
+ "readSources.mode.entities": "实体索引",
426
+ "readSources.mode.unsupported": "不支持",
427
+ "readSources.status.ready": "{count} 条可观察",
428
+ "readSources.status.empty": "已连接 · 暂无内容",
429
+ "readSources.status.query-required": "输入查询后读取",
430
+ "readSources.status.unsupported": "当前表面不可用",
431
+ "readSources.status.unavailable": "连接不可用",
432
+ "readSources.edges": "{count} 条真实关系",
433
+ "readSources.model.mnemon-native": "事实、实体与类型关系",
434
+ "readSources.model.openviking": "目录与分层内容",
435
+ "readSources.model.honcho": "Peer 结论与画像",
436
+ "readSources.model.mem0": "提炼后的语义记忆",
437
+ "readSources.model.hindsight": "记忆单元与知识图",
438
+ "readSources.model.holographic": "可信事实与实体",
439
+ "readSources.model.retaindb": "画像与类型化事实",
440
+ "readSources.model.byterover": "知识树查询",
441
+ "readSources.model.supermemory": "记忆与摄取文档",
442
+ "common.inactive": "未激活",
443
+ "config.providerSecretShow": "显示凭证",
444
+ "config.providerSecretHide": "隐藏凭证",
445
+ "config.providerSecretStoredValue": "已保存凭证",
446
+ "config.providersSpacesOffTitle": "“记忆空间”已关闭",
447
+ "config.providersSpacesOffDetail": "已保存的连接会保留",
448
+ "config.providersSpacesOn": "开启“记忆空间”",
449
+ "config.providersReadOnlyTitle": "dsh-mnemon 当前为只读",
450
+ "config.providersReadOnlyDetail": "writeEnabled 为 false 时,不能启用或停用 Provider。",
451
+ "spaces.offNote": "开启后可配置 Provider 与嵌入",
452
+ "config.providersTitle": "记忆 Provider",
453
+ "config.providersDescription": "Provider 为记忆空间提供存储。启用或保存会同步其中已有的记忆空间;关闭只移除本地映射,不会删除第三方数据。",
454
+ "config.nativeSummary": "官方原生长期记忆与完整关系图",
455
+ "config.officialNative": "官方原生",
456
+ "config.nativeCliMissing": "未安装 CLI(可选)",
457
+ "config.embeddingTitle": "本地向量嵌入",
458
+ "config.embeddingDescription": "让 DSH Host 为每次 Mnemon CLI 调用注入嵌入 Endpoint 与模型;Endpoint 以 /v1 结尾时 Mnemon 自动使用 OpenAI 兼容协议(/v1/embeddings + Bearer 认证),否则使用 Ollama 协议;不以 /v1 结尾的兼容端点可在“协议”下拉中显式指定。",
459
+ "config.embeddingManaged": "由 DSH 管理嵌入配置",
460
+ "config.embeddingManagedHint": "开启后以这里保存的值覆盖 Mnemon 子进程环境;关闭后继续沿用 Host 环境与 Mnemon 默认值。",
461
+ "config.embeddingEndpoint": "嵌入 Endpoint",
462
+ "config.embeddingModel": "嵌入模型",
463
+ "config.embeddingApiKey": "API Key(可选,OpenAI 兼容服务)",
464
+ "config.embeddingApiKeyInvalid": "API Key 不能包含控制字符,且长度不超过 2048。",
465
+ "config.embeddingProtocol": "协议",
466
+ "config.embeddingProtocolAuto": "自动(按 /v1 探测)",
467
+ "config.embeddingProtocolOllama": "Ollama",
468
+ "config.embeddingProtocolOpenai": "OpenAI 兼容",
469
+ "config.embeddingProtocolInvalid": "协议必须是 自动 / Ollama / OpenAI 兼容 之一。",
470
+ "config.embeddingEndpointInvalid": "嵌入 Endpoint 必须是不含凭据、查询参数或片段的 HTTP(S) 绝对 URL。",
471
+ "config.embeddingModelInvalid": "嵌入模型必须包含 1–200 个字符,且不能包含控制字符。",
472
+ "config.embeddingSecurity": "Mnemon 会把记忆与查询正文发送到该 Endpoint;API Key 与其他设置一样保存在 DSH 设置文件中。远程 HTTP 会明文传输,请仅使用受信任的本地地址,或为远程服务配置 HTTPS。",
473
+ "config.embeddingTest": "测试状态",
474
+ "config.embeddingNotTested": "尚未检查嵌入服务的连接与各 Mnemon Native 空间的覆盖率。",
475
+ "config.embeddingTesting": "正在通过 Mnemon 检查嵌入服务与覆盖率…",
476
+ "config.embeddingSaveBeforeTest": "请先保存嵌入配置,再测试实际运行值。",
477
+ "config.embeddingTestUnavailable": "当前 DSH Host 不提供嵌入状态检查。",
478
+ "config.embeddingCliMissing": "测试需要 Mnemon CLI;向量设置只作用于 Mnemon Native。",
479
+ "config.embeddingStatusAvailable": "嵌入服务可用 · {model} · 已嵌入 {embedded}/{total}({coverage})",
480
+ "config.embeddingStatusAvailableWithProtocol": "嵌入服务可用 · {model} · 协议 {protocol} · 已嵌入 {embedded}/{total}({coverage})",
481
+ "config.embeddingStatusUnavailable": "嵌入服务不可达 · {model} · 已嵌入 {embedded}/{total}({coverage})",
482
+ "config.embeddingStatusUnavailableWithProtocol": "嵌入服务不可达 · {model} · 协议 {protocol} · 已嵌入 {embedded}/{total}({coverage})",
483
+ "config.embeddingStatusFailed": "嵌入状态检查失败:{error}",
484
+ "config.embeddingSpaces": "各 Mnemon Native 空间",
485
+ "config.embeddingSpaceCounts": "已嵌入 {embedded}/{total}({coverage})",
486
+ "config.embeddingSpaceFailed": "无法读取:{error}",
487
+ "config.embeddingMissing": "没有向量的记忆不参与语义匹配。",
488
+ "config.embeddingMissingFill": "没有向量的记忆不参与语义匹配;点空间旁的「补齐」即可生成缺少的向量。",
489
+ "config.embeddingMissingOffline": "没有向量的记忆不参与语义匹配;嵌入服务可用后,可以在这里补齐。",
490
+ "config.embeddingSpacesUnread": "无法读取的空间没有计入合计。",
491
+ "config.embeddingFill": "补齐",
492
+ "config.embeddingFilling": "补齐中…",
493
+ "config.embeddingFillLabel": "补齐「{name}」的向量",
494
+ "config.embeddingFillingLabel": "正在补齐「{name}」的向量",
495
+ "config.embeddingFillDone": "已为「{name}」补齐 {filled} 条向量。",
496
+ "config.embeddingFillMore": "已为「{name}」补齐 {filled} 条向量,还缺 {remaining} 条,再点「补齐」继续。",
497
+ "config.embeddingFillPartly": "已为「{name}」补齐 {filled} 条向量;其余 {remaining} 条嵌入服务没有返回向量,可以稍后再点「补齐」。",
498
+ "config.embeddingFillRefused": "嵌入服务没有为「{name}」返回向量,请确认它在运行并提供模型 {model}。",
499
+ "config.embeddingFillFailed": "「{name}」的向量没有补齐:{error}",
500
+ "config.providerGlobalLocation": "全局数据位置",
501
+ "config.providerGlobalLocationHint": "{provider} 默认使用全局范围目录,也可以指定一个自定义位置。",
502
+ "config.providerGlobalLocationWorkspaceHint": "当前使用工作区默认位置;切换到全局范围后可指定自定义位置。",
503
+ "config.providerDefaultLocation": "默认(跟随范围)",
504
+ "config.providerSaveFailed": "配置保存失败:{error}",
505
+ "config.providerServiceTitle": "服务配置",
506
+ "config.providerServiceHint": "供该 Provider 的所有记忆空间复用;启用或保存时会刷新记忆空间目录中的映射与元信息。",
507
+ "config.providerEnableHint": "填写服务配置并保存后,Provider 会启用并同步所有可见记忆空间。",
508
+ "config.providerEnabled": "已启用",
509
+ "config.providerDisabled": "未启用",
510
+ "config.providerDisabledConfigured": "已关闭 · 配置已保留",
511
+ "config.providerNeedsConfiguration": "需要完成配置",
512
+ "config.providerToggleAria": "启用 {provider}",
513
+ "config.providerToggleFailed": "切换失败:{error}",
514
+ "config.enableProvider": "保存并启用",
515
+ "config.providerServiceSaved": "服务配置已保存,记忆空间目录已同步",
516
+ "config.saveProviderService": "保存服务配置",
517
+ "config.providerUnavailable": "当前 DSH 主机不支持 Provider 服务配置。",
518
+ "config.saveScopeBeforeProviders": "存储范围有未保存修改。请先保存范围,再配置对应目录中的 Provider。",
519
+ "config.providerTargetWorkspace": "当前工作区:{workspace};标记“工作区”的 Provider 配置与记忆空间使用此范围。",
520
+ "config.loadingProviders": "正在读取 Provider 配置…",
521
+ "config.providerLoadFailed": "读取 Provider 配置失败:{error}",
522
+ "config.retryProviders": "重试",
523
+ "config.saving": "保存中…"
379
524
  };
380
525
  var en = {
381
526
  "term.space": "Memory Space",
@@ -743,7 +888,129 @@ window.__ModuleLoader__.load({
743
888
  "overview.rediscoveryFailed": "{provider} could not finish discovery: {error}",
744
889
  "overview.rediscoveryTimedOut": "{provider} did not answer in time; try Rediscover later.",
745
890
  "overview.rediscoveryDismiss": "Dismiss",
746
- "overview.newSpace": "New"
891
+ "overview.newSpace": "New",
892
+ "common.copyId": "Copy ID",
893
+ "common.readOnly": "Read only",
894
+ "common.activationOnly": "Activation control only",
895
+ "common.active": "Active",
896
+ "common.category": "Category",
897
+ "common.importanceLabel": "Importance",
898
+ "common.importance": "Importance {value}",
899
+ "common.hops": "{count} hops",
900
+ "common.allCategories": "All categories",
901
+ "common.memories": "{count} memories",
902
+ "common.edges": "{count} edges",
903
+ "card.confirmText": "Soft-delete this memory?",
904
+ "card.processing": "Processing…",
905
+ "card.confirmForget": "Confirm forget",
906
+ "card.related": "View related",
907
+ "card.clone": "Create from this",
908
+ "card.forget": "Forget",
909
+ "readSources.all": "All providers",
910
+ "readSources.mode.search": "Native search",
911
+ "readSources.mode.graph": "True relation graph",
912
+ "readSources.mode.projection": "Content projection",
913
+ "readSources.mode.enumerable": "Enumerable content",
914
+ "readSources.mode.query-only": "Query only",
915
+ "readSources.mode.entities": "Entity index",
916
+ "readSources.mode.unsupported": "Unsupported",
917
+ "readSources.status.ready": "{count} observable",
918
+ "readSources.status.empty": "Connected · no content",
919
+ "readSources.status.query-required": "Read after a query",
920
+ "readSources.status.unsupported": "Unavailable on this surface",
921
+ "readSources.status.unavailable": "Connection unavailable",
922
+ "readSources.edges": "{count} true relations",
923
+ "readSources.model.mnemon-native": "Facts, entities, and typed relations",
924
+ "readSources.model.openviking": "Hierarchy and tiered content",
925
+ "readSources.model.honcho": "Peer conclusions and profiles",
926
+ "readSources.model.mem0": "Extracted semantic memories",
927
+ "readSources.model.hindsight": "Memory units and knowledge graph",
928
+ "readSources.model.holographic": "Trusted facts and entities",
929
+ "readSources.model.retaindb": "Profiles and typed facts",
930
+ "readSources.model.byterover": "Knowledge-tree queries",
931
+ "readSources.model.supermemory": "Memories and ingested documents",
932
+ "common.inactive": "Inactive",
933
+ "config.providerSecretShow": "Show credential",
934
+ "config.providerSecretHide": "Hide credential",
935
+ "config.providerSecretStoredValue": "Saved credential",
936
+ "config.providersSpacesOffTitle": "Memory Spaces is off",
937
+ "config.providersSpacesOffDetail": "Saved connections are kept",
938
+ "config.providersSpacesOn": "Turn on “Memory Spaces”",
939
+ "config.providersReadOnlyTitle": "dsh-mnemon is read-only",
940
+ "config.providersReadOnlyDetail": "With writeEnabled false, Providers cannot be switched on or off.",
941
+ "spaces.offNote": "Turn it on to configure Providers and embedding",
942
+ "config.providersTitle": "Memory providers",
943
+ "config.providersDescription": "Providers store memory spaces. Enabling or saving one synchronizes its existing spaces; turning it off removes only the local mapping, never third-party data.",
944
+ "config.nativeSummary": "Official native long-term memory with a complete relation graph",
945
+ "config.officialNative": "Official native",
946
+ "config.nativeCliMissing": "CLI not installed (optional)",
947
+ "config.embeddingTitle": "Local vector embeddings",
948
+ "config.embeddingDescription": "Have the DSH Host inject the embedding endpoint and model into every Mnemon CLI call; an endpoint ending in /v1 automatically uses the OpenAI-compatible protocol (/v1/embeddings with Bearer auth), otherwise the Ollama protocol. Compatible endpoints that do not end in /v1 can set the protocol explicitly.",
949
+ "config.embeddingManaged": "Manage embedding settings in DSH",
950
+ "config.embeddingManagedHint": "When enabled, saved values override the Mnemon child-process environment. When off, Mnemon keeps the Host environment and its built-in defaults.",
951
+ "config.embeddingEndpoint": "Embedding endpoint",
952
+ "config.embeddingModel": "Embedding model",
953
+ "config.embeddingApiKey": "API key (optional, OpenAI-compatible servers)",
954
+ "config.embeddingApiKeyInvalid": "The API key must contain no control characters and at most 2048 characters.",
955
+ "config.embeddingProtocol": "Protocol",
956
+ "config.embeddingProtocolAuto": "Auto (detect via /v1)",
957
+ "config.embeddingProtocolOllama": "Ollama",
958
+ "config.embeddingProtocolOpenai": "OpenAI-compatible",
959
+ "config.embeddingProtocolInvalid": "The protocol must be one of Auto / Ollama / OpenAI-compatible.",
960
+ "config.embeddingEndpointInvalid": "The embedding endpoint must be an absolute HTTP(S) URL without credentials, a query, or a fragment.",
961
+ "config.embeddingModelInvalid": "The embedding model must contain 1–200 characters and no control characters.",
962
+ "config.embeddingSecurity": "Mnemon sends memory and query text to this endpoint; the API key is stored in the DSH settings file like other settings. Remote HTTP is unencrypted; use a trusted local address or HTTPS for a remote service.",
963
+ "config.embeddingTest": "Test status",
964
+ "config.embeddingNotTested": "The embedding connection and the coverage of each Mnemon Native space have not been checked.",
965
+ "config.embeddingTesting": "Checking the embedding server and coverage through Mnemon…",
966
+ "config.embeddingSaveBeforeTest": "Save the embedding settings before testing their effective runtime values.",
967
+ "config.embeddingTestUnavailable": "This DSH Host does not provide embedding status checks.",
968
+ "config.embeddingCliMissing": "Testing needs the Mnemon CLI; these embedding settings only apply to Mnemon Native.",
969
+ "config.embeddingStatusAvailable": "Embedding server available · {model} · {embedded}/{total} embedded ({coverage})",
970
+ "config.embeddingStatusAvailableWithProtocol": "Embedding server available · {model} · protocol {protocol} · {embedded}/{total} embedded ({coverage})",
971
+ "config.embeddingStatusUnavailable": "Embedding server unreachable · {model} · {embedded}/{total} embedded ({coverage})",
972
+ "config.embeddingStatusUnavailableWithProtocol": "Embedding server unreachable · {model} · protocol {protocol} · {embedded}/{total} embedded ({coverage})",
973
+ "config.embeddingStatusFailed": "Embedding status check failed: {error}",
974
+ "config.embeddingSpaces": "Each Mnemon Native space",
975
+ "config.embeddingSpaceCounts": "{embedded}/{total} embedded ({coverage})",
976
+ "config.embeddingSpaceFailed": "Could not read: {error}",
977
+ "config.embeddingMissing": "Memories without a vector are left out of semantic matching.",
978
+ "config.embeddingMissingFill": "Memories without a vector are left out of semantic matching; Fill in beside a space creates its missing vectors.",
979
+ "config.embeddingMissingOffline": "Memories without a vector are left out of semantic matching; once the embedding service answers, their vectors can be filled in here.",
980
+ "config.embeddingSpacesUnread": "Spaces that could not be read are left out of the total.",
981
+ "config.embeddingFill": "Fill in",
982
+ "config.embeddingFilling": "Filling in…",
983
+ "config.embeddingFillLabel": "Fill in the vectors of {name}",
984
+ "config.embeddingFillingLabel": "Filling in the vectors of {name}",
985
+ "config.embeddingFillDone": "Filled in {filled} vectors for {name}.",
986
+ "config.embeddingFillMore": "Filled in {filled} vectors for {name}; {remaining} are still missing. Press Fill in to go on.",
987
+ "config.embeddingFillPartly": "Filled in {filled} vectors for {name}; the embedding service returned none for the other {remaining}. Press Fill in later to try again.",
988
+ "config.embeddingFillRefused": "The embedding service returned no vectors for {name}. Check that it is running and serves the model {model}.",
989
+ "config.embeddingFillFailed": "The vectors of {name} were not filled in: {error}",
990
+ "config.providerGlobalLocation": "Global data location",
991
+ "config.providerGlobalLocationHint": "{provider} uses the global scope directory by default, or you can choose a custom location.",
992
+ "config.providerGlobalLocationWorkspaceHint": "The workspace default is active. Switch to Global to choose a custom location.",
993
+ "config.providerDefaultLocation": "Default (follows scope)",
994
+ "config.providerSaveFailed": "Could not save configuration: {error}",
995
+ "config.providerServiceTitle": "Service configuration",
996
+ "config.providerServiceHint": "Shared by this provider’s Memory Spaces; enabling or saving refreshes their directory mappings and metadata.",
997
+ "config.providerEnableHint": "Complete and save the service configuration to enable the provider and synchronize every visible namespace.",
998
+ "config.providerEnabled": "Enabled",
999
+ "config.providerDisabled": "Not enabled",
1000
+ "config.providerDisabledConfigured": "Off · configuration kept",
1001
+ "config.providerNeedsConfiguration": "Configuration required",
1002
+ "config.providerToggleAria": "Enable {provider}",
1003
+ "config.providerToggleFailed": "Could not change provider state: {error}",
1004
+ "config.enableProvider": "Save and enable",
1005
+ "config.providerServiceSaved": "Service configuration saved and Memory Spaces synchronized",
1006
+ "config.saveProviderService": "Save service configuration",
1007
+ "config.providerUnavailable": "This DSH host does not support provider service configuration.",
1008
+ "config.saveScopeBeforeProviders": "The storage scope has unsaved changes. Save the scope before configuring providers in that directory.",
1009
+ "config.providerTargetWorkspace": "Current workspace: {workspace}. Providers tagged Workspace use this scope for configuration and Memory Spaces.",
1010
+ "config.loadingProviders": "Loading provider configurations…",
1011
+ "config.providerLoadFailed": "Could not load provider configurations: {error}",
1012
+ "config.retryProviders": "Retry",
1013
+ "config.saving": "Saving…"
747
1014
  };
748
1015
  //#endregion
749
1016
  //#region \0source-css:/home/runner/work/dsh-mnemon/dsh-mnemon/plugins/dsh-mnemon-source-memory-spaces/presentation/page.module.css.mjs
@@ -942,18 +1209,61 @@ window.__ModuleLoader__.load({
942
1209
  ...dsh_mnemon_client.memorySidebarStyles,
943
1210
  ...sidebar_module_css_default
944
1211
  };
1212
+ const TranslationOverride = (0, react.createContext)(void 0);
1213
+ const SourceTranslation = TranslationOverride.Provider;
1214
+ function interpolate(text, params) {
1215
+ return params === void 0 ? text : text.replace(/\{(\w+)\}/g, (match, name) => name in params ? String(params[name]) : match);
1216
+ }
945
1217
  function useT() {
1218
+ const override = (0, react.useContext)(TranslationOverride);
946
1219
  const fallback = (0, dsh_mnemon_client.useT)();
947
1220
  const locale = (0, dsh_mnemon_client.useLocale)();
948
- return (0, react.useMemo)(() => (key, params) => {
1221
+ return (0, react.useMemo)(() => override ?? ((key, params) => {
949
1222
  const dictionary = locale.startsWith("en") ? en : zh;
950
1223
  if (!Object.hasOwn(dictionary, key)) return fallback(key, params);
951
- const text = dictionary[key];
952
- return params === void 0 ? text : text.replace(/\{(\w+)\}/g, (match, name) => name in params ? String(params[name]) : match);
953
- }, [locale, fallback]);
1224
+ return interpolate(dictionary[key], params);
1225
+ }), [
1226
+ override,
1227
+ locale,
1228
+ fallback
1229
+ ]);
1230
+ }
1231
+ /** The languages DSH asks for a key: the active one, then each one's fallback. */
1232
+ function languageChain(snapshot) {
1233
+ const fallbacks = new Map(snapshot.locales.map((locale) => [locale.id, locale.fallback]));
1234
+ const chain = [];
1235
+ for (let id = snapshot.active; id !== void 0 && !chain.includes(id); id = fallbacks.get(id)) chain.push(id);
1236
+ return chain;
1237
+ }
1238
+ /**
1239
+ * Translate as dsh-mnemon drew these settings, through DSH's language chain
1240
+ * and the `mnemon` namespace it registers this copy in. This copy answers in
1241
+ * the first of zh and en the chain reaches; a language pack ahead of that one
1242
+ * is asked first, through the namespace, as dsh-mnemon asked it; a key this
1243
+ * copy lacks goes to the namespace too. Without DSH's chain the page's
1244
+ * language picks the copy, as the page frame does.
1245
+ */
1246
+ function settingsTranslate(locale, chain, language) {
1247
+ const bound = locale.bind("mnemon");
1248
+ const head = chain === void 0 ? language.startsWith("en") ? "en" : "zh" : chain.find((id) => id === "zh" || id === "en") ?? "en";
1249
+ const own = head === "en" ? en : zh;
1250
+ const packFirst = chain !== void 0 && chain.length > 0 && chain[0] !== head;
1251
+ return (key, params) => {
1252
+ if (packFirst) {
1253
+ const text = bound(key, params);
1254
+ if (text !== key) return text;
1255
+ }
1256
+ return Object.hasOwn(own, key) ? interpolate(own[key], params) : bound(key, params);
1257
+ };
954
1258
  }
955
1259
  //#endregion
956
1260
  //#region src/contracts.ts
1261
+ /**
1262
+ * The Mnemon Native Provider's id. Its package names its descriptor and driver
1263
+ * with it, the Starter installs it under it, and a stored space that names no
1264
+ * Provider belongs to it.
1265
+ */
1266
+ const NATIVE_PROVIDER_ID = "mnemon-native";
957
1267
  const CATEGORIES = [
958
1268
  "preference",
959
1269
  "decision",
@@ -969,6 +1279,14 @@ window.__ModuleLoader__.load({
969
1279
  function normalizeEntityKey(entity) {
970
1280
  return entity.normalize("NFKC").trim().toLocaleLowerCase();
971
1281
  }
1282
+ /** Wire protocols accepted by the embedding protocol override; single source for schema, resolver, and UI validation. */
1283
+ const MNEMON_EMBEDDING_PROTOCOLS = [
1284
+ "auto",
1285
+ "ollama",
1286
+ "openai"
1287
+ ];
1288
+ /** The most characters a space's routing description holds. */
1289
+ const MEMORY_SPACE_DESCRIPTION_MAX_LENGTH = 1e3;
972
1290
  //#endregion
973
1291
  //#region src/client/ProviderIcon.tsx
974
1292
  function GenericProviderMark() {
@@ -1034,7 +1352,165 @@ window.__ModuleLoader__.load({
1034
1352
  return typeof localized !== "string" || localized.length === 0 || localized === option.i18nKey ? option.label : localized;
1035
1353
  }
1036
1354
  //#endregion
1037
- //#region src/client/pages.tsx
1355
+ //#region src/client/provider-field.tsx
1356
+ const SAVED_SECRET_MASK = "••••••••••••";
1357
+ function inputType(field, secretVisible) {
1358
+ return field.input === "secret" ? secretVisible ? "text" : "password" : field.input === "number" ? "number" : field.input === "url" ? "url" : "text";
1359
+ }
1360
+ function SecretVisibilityIcon({ visible }) {
1361
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1362
+ viewBox: "0 0 20 20",
1363
+ fill: "none",
1364
+ "aria-hidden": "true",
1365
+ children: [
1366
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1367
+ d: "M2.3 10s2.8-4.5 7.7-4.5 7.7 4.5 7.7 4.5-2.8 4.5-7.7 4.5S2.3 10 2.3 10Z",
1368
+ stroke: "currentColor",
1369
+ strokeWidth: "1.4",
1370
+ strokeLinecap: "round",
1371
+ strokeLinejoin: "round"
1372
+ }),
1373
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1374
+ cx: "10",
1375
+ cy: "10",
1376
+ r: "2.1",
1377
+ stroke: "currentColor",
1378
+ strokeWidth: "1.4"
1379
+ }),
1380
+ visible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1381
+ d: "m3.5 3.5 13 13",
1382
+ stroke: "currentColor",
1383
+ strokeWidth: "1.4",
1384
+ strokeLinecap: "round"
1385
+ })
1386
+ ]
1387
+ });
1388
+ }
1389
+ /** One field of a Provider descriptor, wherever it is edited. */
1390
+ function ProviderField(props) {
1391
+ return props.layout === "settings" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsField, { ...props }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DialogField, { ...props });
1392
+ }
1393
+ function SettingsField(props) {
1394
+ const t = useT();
1395
+ const settings = dsh_mnemon_client.memorySettingsStyles;
1396
+ const [secretVisible, setSecretVisible] = (0, react.useState)(false);
1397
+ const { field } = props;
1398
+ const label = providerFieldLabel(t, field);
1399
+ const disabled = props.disabled === true;
1400
+ const required = field.required && !props.saved;
1401
+ const secret = field.input === "secret";
1402
+ const fieldValue = String(props.value ?? "");
1403
+ const showingSavedMask = secret && props.saved && fieldValue === "";
1404
+ const displayValue = showingSavedMask ? secretVisible ? t("config.providerSecretStoredValue") : SAVED_SECRET_MASK : fieldValue;
1405
+ const input = field.input === "boolean" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1406
+ className: settings.providerBoolean,
1407
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1408
+ "aria-label": label,
1409
+ type: "checkbox",
1410
+ checked: Boolean(props.value),
1411
+ disabled,
1412
+ onChange: (event) => props.onChange(event.target.checked)
1413
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
1414
+ }) : field.input === "select" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
1415
+ label,
1416
+ value: String(props.value ?? ""),
1417
+ disabled,
1418
+ options: (field.options ?? []).map((option) => ({
1419
+ value: option.value,
1420
+ label: providerOptionLabel(t, option)
1421
+ })),
1422
+ onChange: (next) => props.onChange(next)
1423
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [label, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1424
+ className: secret ? settings.providerSecretInput : void 0,
1425
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1426
+ "aria-label": label,
1427
+ type: inputType(field, secretVisible),
1428
+ value: displayValue,
1429
+ required,
1430
+ disabled,
1431
+ autoComplete: secret ? "new-password" : void 0,
1432
+ placeholder: field.placeholder ?? (secret ? t("overview.providerApiKeyOptional") : void 0),
1433
+ maxLength: field.maxLength ?? (secret ? 8e3 : 2e3),
1434
+ min: field.min,
1435
+ max: field.max,
1436
+ pattern: field.pattern,
1437
+ step: field.input === "number" ? "any" : void 0,
1438
+ onFocus: (event) => {
1439
+ if (showingSavedMask) event.currentTarget.select();
1440
+ },
1441
+ onClick: (event) => {
1442
+ if (showingSavedMask) event.currentTarget.select();
1443
+ },
1444
+ onChange: (event) => {
1445
+ const value = showingSavedMask ? event.target.value.replace(SAVED_SECRET_MASK, "").replace(t("config.providerSecretStoredValue"), "") : event.target.value;
1446
+ props.onChange(value);
1447
+ }
1448
+ }), secret && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1449
+ type: "button",
1450
+ className: settings.providerSecretVisibility,
1451
+ "aria-label": t(secretVisible ? "config.providerSecretHide" : "config.providerSecretShow"),
1452
+ title: t(secretVisible ? "config.providerSecretHide" : "config.providerSecretShow"),
1453
+ "aria-pressed": secretVisible,
1454
+ disabled,
1455
+ onClick: () => setSecretVisible((value) => !value),
1456
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretVisibilityIcon, { visible: secretVisible })
1457
+ })]
1458
+ })] });
1459
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1460
+ className: settings.providerFieldControl,
1461
+ "data-input": field.input,
1462
+ children: input
1463
+ });
1464
+ }
1465
+ function DialogField(props) {
1466
+ const t = useT();
1467
+ const { field } = props;
1468
+ const label = providerFieldLabel(t, field);
1469
+ const value = props.value ?? "";
1470
+ const clearing = props.clearing === true;
1471
+ const required = field.required && (!props.saved || clearing);
1472
+ const input = field.input === "boolean" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1473
+ "aria-label": label,
1474
+ type: "checkbox",
1475
+ checked: Boolean(value),
1476
+ onChange: (event) => props.onChange(event.target.checked)
1477
+ }) : field.input === "select" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
1478
+ hideLabel: true,
1479
+ label,
1480
+ value: String(value),
1481
+ options: (field.options ?? []).map((option) => ({
1482
+ value: option.value,
1483
+ label: providerOptionLabel(t, option)
1484
+ })),
1485
+ onChange: (next) => props.onChange(next)
1486
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1487
+ "aria-label": label,
1488
+ type: inputType(field, false),
1489
+ value: String(value),
1490
+ required,
1491
+ autoComplete: field.input === "secret" ? "new-password" : void 0,
1492
+ placeholder: props.saved ? t("overview.providerApiKeyKeep") : field.placeholder ?? (field.input === "secret" ? t("overview.providerApiKeyOptional") : void 0),
1493
+ maxLength: field.maxLength ?? (field.input === "secret" ? 8e3 : 2e3),
1494
+ min: field.min,
1495
+ max: field.max,
1496
+ pattern: field.pattern,
1497
+ step: field.input === "number" ? "any" : void 0,
1498
+ onChange: (event) => props.onChange(event.target.value)
1499
+ });
1500
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1501
+ className: css.providerFieldControl,
1502
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [label, input] }), field.input === "secret" && props.saved && props.onClearChange !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1503
+ className: css.providerSecretClear,
1504
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1505
+ type: "checkbox",
1506
+ checked: clearing,
1507
+ onChange: (event) => props.onClearChange(event.target.checked)
1508
+ }), t("overview.providerSecretClear")]
1509
+ })]
1510
+ });
1511
+ }
1512
+ //#endregion
1513
+ //#region src/client/widgets.tsx
1038
1514
  function memoryProviderFields(provider) {
1039
1515
  return provider.fields.filter((field) => field.scope !== "service");
1040
1516
  }
@@ -1092,49 +1568,16 @@ window.__ModuleLoader__.load({
1092
1568
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1093
1569
  className: css.providerAdvancedGrid,
1094
1570
  children: memoryProviderFields(props.provider).map((field) => {
1095
- const label = providerFieldLabel(t, field);
1096
- const value = props.connection[field.key] ?? "";
1097
- const savedSecret = props.body?.provider.configuredSecrets.includes(field.key) === true;
1098
- const clearingSecret = props.clearSecrets?.includes(field.key) === true;
1099
- const required = field.required && (!savedSecret || clearingSecret);
1100
- const input = field.input === "boolean" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1101
- "aria-label": label,
1102
- type: "checkbox",
1103
- checked: Boolean(value),
1104
- onChange: (event) => props.onChange(field.key, event.target.checked)
1105
- }) : field.input === "select" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
1106
- hideLabel: true,
1107
- label,
1108
- value: String(value),
1109
- options: (field.options ?? []).map((option) => ({
1110
- value: option.value,
1111
- label: providerOptionLabel(t, option)
1112
- })),
1113
- onChange: (next) => props.onChange(field.key, next)
1114
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1115
- "aria-label": label,
1116
- type: field.input === "secret" ? "password" : field.input === "number" ? "number" : field.input === "url" ? "url" : "text",
1117
- value: String(value),
1118
- required,
1119
- autoComplete: field.input === "secret" ? "new-password" : void 0,
1120
- placeholder: savedSecret ? t("overview.providerApiKeyKeep") : field.placeholder ?? (field.input === "secret" ? t("overview.providerApiKeyOptional") : void 0),
1121
- maxLength: field.maxLength ?? (field.input === "secret" ? 8e3 : 2e3),
1122
- min: field.min,
1123
- max: field.max,
1124
- pattern: field.pattern,
1125
- step: field.input === "number" ? "any" : void 0,
1126
- onChange: (event) => props.onChange(field.key, event.target.value)
1127
- });
1128
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1129
- className: css.providerFieldControl,
1130
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [label, input] }), props.body !== void 0 && field.input === "secret" && savedSecret && props.onClearSecretsChange !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1131
- className: css.providerSecretClear,
1132
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1133
- type: "checkbox",
1134
- checked: clearingSecret,
1135
- onChange: (event) => props.onClearSecretsChange(event.target.checked ? [.../* @__PURE__ */ new Set([...props.clearSecrets ?? [], field.key])] : (props.clearSecrets ?? []).filter((key) => key !== field.key))
1136
- }), t("overview.providerSecretClear")]
1137
- })]
1571
+ const saved = props.body?.provider.configuredSecrets.includes(field.key) === true;
1572
+ const clearSecrets = props.clearSecrets ?? [];
1573
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderField, {
1574
+ field,
1575
+ value: props.connection[field.key],
1576
+ layout: "dialog",
1577
+ saved,
1578
+ clearing: clearSecrets.includes(field.key),
1579
+ onChange: (value) => props.onChange(field.key, value),
1580
+ ...props.body === void 0 || props.onClearSecretsChange === void 0 ? {} : { onClearChange: (clearing) => props.onClearSecretsChange(clearing ? [.../* @__PURE__ */ new Set([...clearSecrets, field.key])] : clearSecrets.filter((key) => key !== field.key)) }
1138
1581
  }, field.key);
1139
1582
  })
1140
1583
  }),
@@ -1224,24 +1667,6 @@ window.__ModuleLoader__.load({
1224
1667
  }, source.memoryBodyId)) })]
1225
1668
  });
1226
1669
  }
1227
- /** Full-text popup for a selected graph node whose inspector preview is clamped. */
1228
- function ContentPreview(props) {
1229
- const t = useT();
1230
- const meta = [
1231
- props.kind,
1232
- props.node.id,
1233
- props.node.memoryBodyName
1234
- ].filter((entry) => entry !== void 0).join(" · ");
1235
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SidebarModal, {
1236
- title: t("overview.previewTitle"),
1237
- description: meta,
1238
- onClose: props.onClose,
1239
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1240
- className: css.previewContent,
1241
- children: props.node.content
1242
- })
1243
- });
1244
- }
1245
1670
  function InsightCard(props) {
1246
1671
  const t = useT();
1247
1672
  const [confirming, setConfirming] = (0, react.useState)(false);
@@ -1359,6 +1784,10 @@ window.__ModuleLoader__.load({
1359
1784
  })
1360
1785
  })] });
1361
1786
  }
1787
+ /** @deprecated Use nativeSpaceProvider. */
1788
+ const nativeBodyProvider = nativeSpaceProvider;
1789
+ //#endregion
1790
+ //#region src/client/memory-graph.tsx
1362
1791
  const GRAPH_WIDTH = 930;
1363
1792
  const GRAPH_HEIGHT = 520;
1364
1793
  const GRAPH_MARGIN_X = 58;
@@ -1967,6 +2396,26 @@ window.__ModuleLoader__.load({
1967
2396
  ]
1968
2397
  })] });
1969
2398
  }
2399
+ //#endregion
2400
+ //#region src/client/overview-page.tsx
2401
+ /** Full-text popup for a selected graph node whose inspector preview is clamped. */
2402
+ function ContentPreview(props) {
2403
+ const t = useT();
2404
+ const meta = [
2405
+ props.kind,
2406
+ props.node.id,
2407
+ props.node.memoryBodyName
2408
+ ].filter((entry) => entry !== void 0).join(" · ");
2409
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SidebarModal, {
2410
+ title: t("overview.previewTitle"),
2411
+ description: meta,
2412
+ onClose: props.onClose,
2413
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2414
+ className: css.previewContent,
2415
+ children: props.node.content
2416
+ })
2417
+ });
2418
+ }
1970
2419
  function OverviewPage(props) {
1971
2420
  const t = useT();
1972
2421
  const locale = (0, dsh_mnemon_client.useLocale)();
@@ -1985,7 +2434,7 @@ window.__ModuleLoader__.load({
1985
2434
  const [creatingSpaceOpen, setCreatingSpaceOpen] = (0, react.useState)(false);
1986
2435
  const [spaceName, setSpaceName] = (0, react.useState)("");
1987
2436
  const [spaceDescription, setSpaceDescription] = (0, react.useState)("");
1988
- const [spaceProviderId, setSpaceProviderId] = (0, react.useState)("mnemon-native");
2437
+ const [spaceProviderId, setSpaceProviderId] = (0, react.useState)(NATIVE_PROVIDER_ID);
1989
2438
  const [providerDrafts, setProviderDrafts] = (0, react.useState)({});
1990
2439
  const [catalogUnavailable, setCatalogUnavailable] = (0, react.useState)(false);
1991
2440
  const [editingSpace, setEditingSpace] = (0, react.useState)(null);
@@ -2386,7 +2835,7 @@ window.__ModuleLoader__.load({
2386
2835
  value: editDescription,
2387
2836
  onChange: (event) => setEditDescription(event.target.value),
2388
2837
  rows: 4,
2389
- maxLength: 1e3
2838
+ maxLength: MEMORY_SPACE_DESCRIPTION_MAX_LENGTH
2390
2839
  })] }),
2391
2840
  !nativeSpaceProvider(body.provider) && (() => {
2392
2841
  const descriptor = providers.find((provider) => provider.id === body.provider.id);
@@ -2429,7 +2878,7 @@ window.__ModuleLoader__.load({
2429
2878
  onChange: (event) => setSpaceDescription(event.target.value),
2430
2879
  placeholder: t("overview.createDescriptionPlaceholder"),
2431
2880
  rows: 3,
2432
- maxLength: 1e3,
2881
+ maxLength: MEMORY_SPACE_DESCRIPTION_MAX_LENGTH,
2433
2882
  required: true
2434
2883
  })] })]
2435
2884
  })]
@@ -3072,6 +3521,24 @@ window.__ModuleLoader__.load({
3072
3521
  ]
3073
3522
  });
3074
3523
  }
3524
+ /** The rediscovery a person last dismissed on this browser, so the same news is not shown twice. */
3525
+ const REDISCOVERY_SEEN_KEY = "dsh-mnemon.memory-spaces.rediscovery-seen";
3526
+ /** How often an open page looks again while the Host asks the Providers. */
3527
+ const REDISCOVERY_POLL_MS = 2e3;
3528
+ function readSeenRediscovery() {
3529
+ try {
3530
+ return globalThis.localStorage?.getItem(REDISCOVERY_SEEN_KEY) ?? null;
3531
+ } catch {
3532
+ return null;
3533
+ }
3534
+ }
3535
+ function writeSeenRediscovery(at) {
3536
+ try {
3537
+ globalThis.localStorage?.setItem(REDISCOVERY_SEEN_KEY, at);
3538
+ } catch {}
3539
+ }
3540
+ //#endregion
3541
+ //#region src/client/explore-page.tsx
3075
3542
  function ExplorePage(props) {
3076
3543
  const t = useT();
3077
3544
  const pageSize = 6;
@@ -3384,22 +3851,8 @@ window.__ModuleLoader__.load({
3384
3851
  ]
3385
3852
  });
3386
3853
  }
3387
- /** The rediscovery a person last dismissed on this browser, so the same news is not shown twice. */
3388
- const REDISCOVERY_SEEN_KEY = "dsh-mnemon.memory-spaces.rediscovery-seen";
3389
- /** How often an open page looks again while the Host asks the Providers. */
3390
- const REDISCOVERY_POLL_MS = 2e3;
3391
- function readSeenRediscovery() {
3392
- try {
3393
- return globalThis.localStorage?.getItem(REDISCOVERY_SEEN_KEY) ?? null;
3394
- } catch {
3395
- return null;
3396
- }
3397
- }
3398
- function writeSeenRediscovery(at) {
3399
- try {
3400
- globalThis.localStorage?.setItem(REDISCOVERY_SEEN_KEY, at);
3401
- } catch {}
3402
- }
3854
+ //#endregion
3855
+ //#region src/client/entities-page.tsx
3403
3856
  /** Show a loading placeholder only when a read outlasts this, so a quick read never flashes one. */
3404
3857
  const ENTITY_PLACEHOLDER_DELAY_MS = 160;
3405
3858
  const ENTITY_RAIL_PAGE = 10;
@@ -3895,6 +4348,8 @@ window.__ModuleLoader__.load({
3895
4348
  ]
3896
4349
  });
3897
4350
  }
4351
+ //#endregion
4352
+ //#region src/client/persistence-strategy-dialog.tsx
3898
4353
  function PersistenceStrategyDialog(props) {
3899
4354
  const t = useT();
3900
4355
  const strategyFormId = (0, react.useId)();
@@ -4225,6 +4680,9 @@ window.__ModuleLoader__.load({
4225
4680
  })
4226
4681
  });
4227
4682
  }
4683
+ //#endregion
4684
+ //#region src/client/remember-page.tsx
4685
+ /** `embeddingManaged`, from this Source's status, words a memory saved without a vector; left out, the receipt keeps the caution. */
4228
4686
  function RememberPage(props) {
4229
4687
  const t = useT();
4230
4688
  const rememberFormId = (0, react.useId)();
@@ -4259,7 +4717,8 @@ window.__ModuleLoader__.load({
4259
4717
  content: candidate,
4260
4718
  action: response.action,
4261
4719
  summary: response.summary,
4262
- unembedded: (response.unembedded ?? []).length > 0
4720
+ unembedded: (response.unembedded ?? []).length > 0,
4721
+ embeddingManaged: props.embeddingManaged
4263
4722
  });
4264
4723
  props.onMutate();
4265
4724
  } catch (reason) {
@@ -4290,7 +4749,8 @@ window.__ModuleLoader__.load({
4290
4749
  content: candidate,
4291
4750
  action: typeof response.action === "string" ? response.action : "stored",
4292
4751
  summary: typeof response.summary === "string" ? response.summary : "",
4293
- unembedded: response.embedded === false
4752
+ unembedded: response.embedded === false,
4753
+ embeddingManaged: props.embeddingManaged
4294
4754
  });
4295
4755
  props.onMutate();
4296
4756
  } catch (reason) {
@@ -4333,6 +4793,7 @@ window.__ModuleLoader__.load({
4333
4793
  summary: outcome.summary,
4334
4794
  error: outcome.error,
4335
4795
  unembedded: outcome.unembedded,
4796
+ embeddingManaged: outcome.embeddingManaged,
4336
4797
  onView: props.onView
4337
4798
  })
4338
4799
  ]
@@ -4441,6 +4902,8 @@ window.__ModuleLoader__.load({
4441
4902
  })
4442
4903
  });
4443
4904
  }
4905
+ //#endregion
4906
+ //#region src/client/list-page.tsx
4444
4907
  function ListPage(props) {
4445
4908
  const t = useT();
4446
4909
  const pageSize = 12;
@@ -4579,8 +5042,1020 @@ window.__ModuleLoader__.load({
4579
5042
  ]
4580
5043
  });
4581
5044
  }
4582
- /** @deprecated Use nativeSpaceProvider. */
4583
- const nativeBodyProvider = nativeSpaceProvider;
5045
+ //#endregion
5046
+ //#region src/client/provider-settings.tsx
5047
+ const EMPTY_PROVIDER_CATALOG = {
5048
+ providers: [],
5049
+ items: [],
5050
+ generatedAt: ""
5051
+ };
5052
+ const RETAINED_PROVIDERS = "provider-services";
5053
+ const retainedCatalog = (retained) => retained.get(RETAINED_PROVIDERS);
5054
+ function stabilizeProviderCard(element) {
5055
+ const view = element.ownerDocument.defaultView;
5056
+ let scrollContainer;
5057
+ for (let ancestor = element.parentElement; ancestor !== null; ancestor = ancestor.parentElement) {
5058
+ const overflowY = view?.getComputedStyle(ancestor).overflowY ?? ancestor.style.overflowY;
5059
+ if (scrollContainer !== void 0 && overflowY === "hidden" && ancestor.scrollTop !== 0) ancestor.scrollTop = 0;
5060
+ if (scrollContainer === void 0 && (overflowY === "auto" || overflowY === "scroll") && ancestor.scrollHeight > ancestor.clientHeight) scrollContainer = ancestor;
5061
+ if (ancestor.getAttribute("role") === "dialog") break;
5062
+ }
5063
+ if (scrollContainer === void 0) return;
5064
+ const headerRect = (element.firstElementChild instanceof HTMLElement ? element.firstElementChild : element).getBoundingClientRect();
5065
+ const containerRect = scrollContainer.getBoundingClientRect();
5066
+ if (headerRect.top < containerRect.top) scrollContainer.scrollTop -= containerRect.top - headerRect.top;
5067
+ else if (headerRect.bottom > containerRect.bottom) scrollContainer.scrollTop += headerRect.bottom - containerRect.bottom;
5068
+ }
5069
+ function serviceFields(provider) {
5070
+ return provider.fields.filter((field) => field.scope === "service");
5071
+ }
5072
+ function globalLocationFields(provider) {
5073
+ return serviceFields(provider).filter((field) => field.role === "global-location");
5074
+ }
5075
+ function serviceDefaults(provider) {
5076
+ return Object.fromEntries(serviceFields(provider).flatMap((field) => field.defaultValue === void 0 ? [] : [[field.key, field.defaultValue]]));
5077
+ }
5078
+ function draftFor(provider, service) {
5079
+ return { settings: {
5080
+ ...serviceDefaults(provider),
5081
+ ...service.settings,
5082
+ ...service.secretValues
5083
+ } };
5084
+ }
5085
+ function configurationComplete(provider, draft, service) {
5086
+ return serviceFields(provider).every((field) => {
5087
+ if (!field.required) return true;
5088
+ if (field.input === "secret" && service.configuredSecrets.includes(field.key)) return true;
5089
+ const value = draft.settings[field.key];
5090
+ return field.input === "boolean" ? typeof value === "boolean" : String(value ?? "").trim() !== "";
5091
+ });
5092
+ }
5093
+ function ProviderServiceForm(props) {
5094
+ const t = useT();
5095
+ const css = dsh_mnemon_client.memorySettingsStyles;
5096
+ const [draft, setDraft] = (0, react.useState)(() => draftFor(props.provider, props.service));
5097
+ const [customLocations, setCustomLocations] = (0, react.useState)(() => new Set(globalLocationFields(props.provider).filter((field) => String(props.service.settings[field.key] ?? "").trim() !== "").map((field) => field.key)));
5098
+ const [saving, setSaving] = (0, react.useState)(false);
5099
+ const [failed, setFailed] = (0, react.useState)(null);
5100
+ const [saved, setSaved] = (0, react.useState)(false);
5101
+ const formRef = (0, react.useRef)(null);
5102
+ const stabilizeAfterLocationLayout = (0, react.useRef)(false);
5103
+ (0, react.useEffect)(() => {
5104
+ setDraft(draftFor(props.provider, props.service));
5105
+ setCustomLocations(new Set(globalLocationFields(props.provider).filter((field) => String(props.service.settings[field.key] ?? "").trim() !== "").map((field) => field.key)));
5106
+ }, [props.provider, props.service]);
5107
+ (0, react.useLayoutEffect)(() => {
5108
+ if (!stabilizeAfterLocationLayout.current || formRef.current === null) return;
5109
+ stabilizeAfterLocationLayout.current = false;
5110
+ stabilizeProviderCard(formRef.current.closest("[data-provider]") ?? formRef.current);
5111
+ }, [customLocations]);
5112
+ const submit = async (event) => {
5113
+ event.preventDefault();
5114
+ const locationsComplete = props.activeScope === "workspace" || globalLocationFields(props.provider).every((field) => !customLocations.has(field.key) || String(draft.settings[field.key] ?? "").trim() !== "");
5115
+ if (!configurationComplete(props.provider, draft, props.service) || !locationsComplete || saving || props.disabled) return;
5116
+ setSaving(true);
5117
+ setFailed(null);
5118
+ setSaved(false);
5119
+ const settings = { ...draft.settings };
5120
+ for (const field of globalLocationFields(props.provider)) if (props.activeScope === "workspace" || !customLocations.has(field.key)) settings[field.key] = "";
5121
+ try {
5122
+ await props.onSave(props.provider, { settings });
5123
+ setSaved(true);
5124
+ } catch (reason) {
5125
+ setFailed((0, dsh_mnemon_client.message)(reason));
5126
+ } finally {
5127
+ setSaving(false);
5128
+ }
5129
+ };
5130
+ const update = (key, value) => {
5131
+ setDraft((current) => ({
5132
+ ...current,
5133
+ settings: {
5134
+ ...current.settings,
5135
+ [key]: value
5136
+ }
5137
+ }));
5138
+ setFailed(null);
5139
+ setSaved(false);
5140
+ };
5141
+ const useCustomLocation = (field, custom) => {
5142
+ stabilizeAfterLocationLayout.current = true;
5143
+ setCustomLocations((current) => {
5144
+ const next = new Set(current);
5145
+ if (custom) next.add(field.key);
5146
+ else next.delete(field.key);
5147
+ return next;
5148
+ });
5149
+ setFailed(null);
5150
+ setSaved(false);
5151
+ };
5152
+ const stabilizeLocationCard = () => {
5153
+ if (formRef.current === null) return;
5154
+ stabilizeProviderCard(formRef.current.closest("[data-provider]") ?? formRef.current);
5155
+ };
5156
+ const locations = globalLocationFields(props.provider);
5157
+ const regularFields = serviceFields(props.provider).filter((field) => field.role !== "global-location");
5158
+ const locationsComplete = props.activeScope === "workspace" || locations.every((field) => !customLocations.has(field.key) || String(draft.settings[field.key] ?? "").trim() !== "");
5159
+ const formComplete = configurationComplete(props.provider, draft, props.service) && locationsComplete;
5160
+ const field = (descriptor) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderField, {
5161
+ field: descriptor,
5162
+ value: draft.settings[descriptor.key],
5163
+ layout: "settings",
5164
+ saved: props.service.configuredSecrets.includes(descriptor.key),
5165
+ disabled: props.disabled || saving,
5166
+ onChange: (value) => update(descriptor.key, value)
5167
+ }, descriptor.key);
5168
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
5169
+ ref: formRef,
5170
+ className: css.providerServiceForm,
5171
+ onSubmit: (event) => void submit(event),
5172
+ "data-provider": props.provider.id,
5173
+ children: [
5174
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5175
+ className: css.providerServicePrompt,
5176
+ children: t(props.service.configured ? "config.providerServiceHint" : "config.providerEnableHint")
5177
+ }),
5178
+ locations.map((location) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.GlobalLocationSetting, {
5179
+ className: css.providerServiceLocation,
5180
+ name: `${props.provider.id}-${location.key}-location`,
5181
+ ariaLabel: `${props.provider.label} ${t("config.providerGlobalLocation")}`,
5182
+ label: t("config.providerGlobalLocation"),
5183
+ hint: t(props.activeScope === "workspace" ? "config.providerGlobalLocationWorkspaceHint" : "config.providerGlobalLocationHint", { provider: props.provider.label }),
5184
+ defaultLabel: t("config.providerDefaultLocation"),
5185
+ customLabel: t("config.custom"),
5186
+ custom: customLocations.has(location.key),
5187
+ workspace: props.activeScope === "workspace",
5188
+ disabled: props.disabled || saving,
5189
+ onInteract: stabilizeLocationCard,
5190
+ onChange: (custom) => useCustomLocation(location, custom),
5191
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5192
+ className: css.providerLocationField,
5193
+ children: field(location)
5194
+ })
5195
+ }, location.key)),
5196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5197
+ className: css.providerSettingsGrid,
5198
+ children: regularFields.map(field)
5199
+ }),
5200
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5201
+ className: `${css.memoryConfigFooter} ${css.providerServiceFooter}`,
5202
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5203
+ className: css.configFeedback,
5204
+ "aria-live": "polite",
5205
+ children: [failed !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5206
+ className: css.error,
5207
+ children: t("config.providerSaveFailed", { error: failed })
5208
+ }), saved && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5209
+ className: css.packSuccess,
5210
+ children: t("config.providerServiceSaved")
5211
+ })]
5212
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5213
+ type: "submit",
5214
+ variant: "primary",
5215
+ size: "sm",
5216
+ disabled: props.disabled || saving || !formComplete,
5217
+ children: saving ? t("config.saving") : t(props.service.configured ? "config.saveProviderService" : "config.enableProvider")
5218
+ })]
5219
+ })
5220
+ ]
5221
+ });
5222
+ }
5223
+ function ProviderPanel(props) {
5224
+ const t = useT();
5225
+ const css = dsh_mnemon_client.memorySettingsStyles;
5226
+ const [enabled, setEnabled] = (0, react.useState)(props.service.enabled);
5227
+ const [expanded, setExpanded] = (0, react.useState)(props.service.enabled && !props.service.configured);
5228
+ const [toggling, setToggling] = (0, react.useState)(false);
5229
+ const [failed, setFailed] = (0, react.useState)(null);
5230
+ const rowRef = (0, react.useRef)(null);
5231
+ const stabilizeAfterLayout = (0, react.useRef)(false);
5232
+ (0, react.useLayoutEffect)(() => {
5233
+ if (!stabilizeAfterLayout.current || rowRef.current === null) return;
5234
+ stabilizeAfterLayout.current = false;
5235
+ stabilizeProviderCard(rowRef.current);
5236
+ }, [enabled, expanded]);
5237
+ (0, react.useEffect)(() => {
5238
+ if (toggling) return;
5239
+ setEnabled(props.service.enabled);
5240
+ if (!props.service.enabled) setExpanded(false);
5241
+ }, [props.service.enabled, toggling]);
5242
+ const toggle = async (next) => {
5243
+ setFailed(null);
5244
+ stabilizeAfterLayout.current = true;
5245
+ if (next && !props.service.configured) {
5246
+ setEnabled(true);
5247
+ setExpanded(true);
5248
+ return;
5249
+ }
5250
+ if (!next && !props.service.enabled) {
5251
+ setEnabled(false);
5252
+ setExpanded(false);
5253
+ return;
5254
+ }
5255
+ const restoreEnabled = enabled;
5256
+ const restoreExpanded = expanded;
5257
+ setEnabled(next);
5258
+ if (!next && expanded) setExpanded(false);
5259
+ setToggling(true);
5260
+ try {
5261
+ const updated = await props.onToggle(props.provider, next);
5262
+ setEnabled(updated.enabled);
5263
+ if (!next) setExpanded(false);
5264
+ } catch (reason) {
5265
+ setEnabled(restoreEnabled);
5266
+ if (restoreExpanded) setExpanded(true);
5267
+ setFailed((0, dsh_mnemon_client.message)(reason));
5268
+ } finally {
5269
+ setToggling(false);
5270
+ }
5271
+ };
5272
+ const stateKey = enabled ? props.service.configured ? "config.providerEnabled" : "config.providerNeedsConfiguration" : props.service.configured ? "config.providerDisabledConfigured" : "config.providerDisabled";
5273
+ const providerScope = props.provider.workspaceBinding === "provider-global" ? "global" : props.activeScope;
5274
+ const controlDisabled = props.disabled || toggling;
5275
+ const toggleExpanded = () => {
5276
+ stabilizeAfterLayout.current = true;
5277
+ setExpanded((value) => !value);
5278
+ };
5279
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5280
+ ref: rowRef,
5281
+ className: css.providerRow,
5282
+ "data-provider": props.provider.id,
5283
+ "data-enabled": enabled || void 0,
5284
+ "data-expanded": expanded || void 0,
5285
+ role: "group",
5286
+ "aria-label": `${props.provider.label} ${t("config.providerServiceTitle")}`,
5287
+ children: [
5288
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5289
+ className: css.providerRowHeader,
5290
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5291
+ type: "button",
5292
+ className: css.providerDisclosure,
5293
+ "aria-expanded": expanded,
5294
+ disabled: !enabled || controlDisabled,
5295
+ onClick: toggleExpanded,
5296
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5297
+ className: css.providerIdentity,
5298
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderIcon, {
5299
+ providerId: props.provider.id,
5300
+ icon: props.provider.icon,
5301
+ className: css.providerMark
5302
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: props.provider.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: providerSummary(t, props.provider) })] })]
5303
+ }), enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
5304
+ className: css.providerChevron,
5305
+ size: 14
5306
+ })]
5307
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5308
+ className: css.providerEnableControl,
5309
+ children: [
5310
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5311
+ className: css.providerScopeTag,
5312
+ "data-scope": providerScope,
5313
+ children: t(`config.${providerScope}`)
5314
+ }),
5315
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5316
+ className: css.providerState,
5317
+ "data-enabled": enabled || void 0,
5318
+ children: t(stateKey)
5319
+ }),
5320
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
5321
+ className: css.providerToggle,
5322
+ checked: enabled,
5323
+ label: t("config.providerToggleAria", { provider: props.provider.label }),
5324
+ disabled: controlDisabled,
5325
+ onChange: (next) => void toggle(next)
5326
+ })
5327
+ ]
5328
+ })]
5329
+ }),
5330
+ failed !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5331
+ className: css.providerToggleError,
5332
+ role: "alert",
5333
+ children: t("config.providerToggleFailed", { error: failed })
5334
+ }),
5335
+ enabled && expanded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5336
+ className: css.providerInlineBody,
5337
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderServiceForm, {
5338
+ provider: props.provider,
5339
+ service: props.service,
5340
+ activeScope: props.activeScope,
5341
+ disabled: controlDisabled,
5342
+ onSave: props.onSave
5343
+ })
5344
+ })
5345
+ ]
5346
+ });
5347
+ }
5348
+ /** The Providers that store Memory Spaces, one card each, with what their services need. */
5349
+ function ProviderSettingsSection(props) {
5350
+ const t = useT();
5351
+ const css = dsh_mnemon_client.memorySettingsStyles;
5352
+ const { client, retained } = props;
5353
+ const initialCatalog = client === void 0 ? void 0 : retainedCatalog(retained);
5354
+ const [catalog, setCatalog] = (0, react.useState)(() => initialCatalog ?? EMPTY_PROVIDER_CATALOG);
5355
+ const [loading, setLoading] = (0, react.useState)(client !== void 0 && initialCatalog === void 0);
5356
+ const [failed, setFailed] = (0, react.useState)(null);
5357
+ const loadRequests = (0, dsh_mnemon_client.useRequestVersion)();
5358
+ const load = (0, react.useCallback)(async (quiet = false) => {
5359
+ if (client === void 0) return;
5360
+ const request = loadRequests.begin();
5361
+ if (!quiet) setLoading(true);
5362
+ setFailed(null);
5363
+ try {
5364
+ const next = await client.providerServices();
5365
+ if (!loadRequests.isCurrent(request)) return;
5366
+ retained.set(RETAINED_PROVIDERS, next);
5367
+ setCatalog(next);
5368
+ } catch (reason) {
5369
+ if (!loadRequests.isCurrent(request)) return;
5370
+ setFailed((0, dsh_mnemon_client.message)(reason));
5371
+ } finally {
5372
+ if (!quiet && loadRequests.isCurrent(request)) setLoading(false);
5373
+ }
5374
+ }, [
5375
+ client,
5376
+ loadRequests,
5377
+ retained
5378
+ ]);
5379
+ const blocked = props.blocked !== void 0;
5380
+ const pending = props.pending === true;
5381
+ (0, react.useEffect)(() => {
5382
+ if (blocked || pending) {
5383
+ loadRequests.begin();
5384
+ setLoading(pending);
5385
+ setFailed(null);
5386
+ return;
5387
+ }
5388
+ const cached = client === void 0 ? void 0 : retainedCatalog(retained);
5389
+ setCatalog(cached ?? EMPTY_PROVIDER_CATALOG);
5390
+ setLoading(client !== void 0 && cached === void 0);
5391
+ load(cached !== void 0);
5392
+ }, [
5393
+ blocked,
5394
+ client,
5395
+ load,
5396
+ loadRequests,
5397
+ pending,
5398
+ props.refreshKey,
5399
+ retained
5400
+ ]);
5401
+ const acceptService = (0, react.useCallback)((service) => {
5402
+ setCatalog((current) => {
5403
+ const items = current.items.some((item) => item.providerId === service.providerId) ? current.items.map((item) => item.providerId === service.providerId ? service : item) : [...current.items, service];
5404
+ const next = {
5405
+ ...current,
5406
+ items,
5407
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
5408
+ };
5409
+ if (client !== void 0) retained.set(RETAINED_PROVIDERS, next);
5410
+ return next;
5411
+ });
5412
+ }, [client, retained]);
5413
+ const save = async (provider, draft) => {
5414
+ if (client === void 0) throw new Error(t("config.providerUnavailable"));
5415
+ const settings = Object.fromEntries(Object.entries(draft.settings).filter(([key, value]) => serviceFields(provider).find((field) => field.key === key)?.input !== "secret" || String(value).trim() !== ""));
5416
+ acceptService(await client.updateProviderService({
5417
+ providerId: provider.id,
5418
+ settings,
5419
+ enabled: true
5420
+ }));
5421
+ props.onChanged?.();
5422
+ };
5423
+ const toggle = async (provider, enabled) => {
5424
+ if (client === void 0) throw new Error(t("config.providerUnavailable"));
5425
+ const updated = await client.updateProviderService({
5426
+ providerId: provider.id,
5427
+ settings: {},
5428
+ enabled
5429
+ });
5430
+ acceptService(updated);
5431
+ props.onChanged?.();
5432
+ return updated;
5433
+ };
5434
+ const disabled = props.disabled || props.scopeChanging || client === void 0 || loading || catalog.generatedAt === "";
5435
+ if (blocked) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.Reveal, { children: props.blocked }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5436
+ className: css.providerList,
5437
+ children: props.leading
5438
+ })] });
5439
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5440
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.Reveal, { children: props.notice ?? null }),
5441
+ props.scopeChanging && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5442
+ className: css.scopeChanging,
5443
+ role: "status",
5444
+ children: t("config.saveScopeBeforeProviders")
5445
+ }),
5446
+ props.workspaceLabel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5447
+ className: css.providerTarget,
5448
+ children: t("config.providerTargetWorkspace", { workspace: props.workspaceLabel })
5449
+ }),
5450
+ loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5451
+ className: css.visuallyHidden,
5452
+ role: "status",
5453
+ children: t("config.loadingProviders")
5454
+ }),
5455
+ failed !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5456
+ className: css.providerLoadError,
5457
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5458
+ className: css.error,
5459
+ children: t("config.providerLoadFailed", { error: failed })
5460
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5461
+ variant: "ghost",
5462
+ size: "sm",
5463
+ onClick: () => void load(),
5464
+ children: t("config.retryProviders")
5465
+ })]
5466
+ }),
5467
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5468
+ className: css.providerList,
5469
+ "aria-busy": loading,
5470
+ children: [props.leading, catalog.providers.map((provider) => {
5471
+ const service = catalog.items.find((item) => item.providerId === provider.id) ?? {
5472
+ providerId: provider.id,
5473
+ enabled: false,
5474
+ configured: false,
5475
+ settings: {},
5476
+ configuredSecrets: []
5477
+ };
5478
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderPanel, {
5479
+ provider,
5480
+ service,
5481
+ disabled,
5482
+ activeScope: props.activeScope,
5483
+ onSave: save,
5484
+ onToggle: toggle
5485
+ }, provider.id);
5486
+ })]
5487
+ })
5488
+ ] });
5489
+ }
5490
+ //#endregion
5491
+ //#region src/client/settings-client.ts
5492
+ const clients = /* @__PURE__ */ new WeakMap();
5493
+ function memorySpacesSettingsClient(operations) {
5494
+ let client = clients.get(operations);
5495
+ if (client === void 0) {
5496
+ client = {
5497
+ statusSummary: () => operations.read("status-summary"),
5498
+ providerServices: () => operations.read("provider-services"),
5499
+ updateProviderService: (request) => operations.write("provider-service-update", JSON.parse(JSON.stringify(request))),
5500
+ embeddingStatus: () => operations.read("embedding-status"),
5501
+ fillEmbeddings: (memoryBodyId) => operations.write("embedding-fill", { memoryBodyId })
5502
+ };
5503
+ clients.set(operations, client);
5504
+ }
5505
+ return client;
5506
+ }
5507
+ //#endregion
5508
+ //#region src/client/settings.tsx
5509
+ /** The package these settings belong to, as Memory Spaces' plugin declaration names it. */
5510
+ const PACKAGE_NAME = "dsh-mnemon-source-memory-spaces";
5511
+ /**
5512
+ * Whether dsh-mnemon yields the settings it keeps for Memory Spaces to these.
5513
+ * One that exports the priority it keeps them at promises both that they do
5514
+ * not collide with these and that it lends these `host`. dsh-mnemon 0.5.31 and
5515
+ * earlier draw them itself and lend nothing, so registering them there would
5516
+ * show a second, unworkable copy.
5517
+ */
5518
+ function yieldsComponentSettings(client) {
5519
+ return typeof client.MNEMON_COMPONENT_FALLBACK_PRIORITY === "number";
5520
+ }
5521
+ /** Memory Spaces' own settings on its page under Plugins: its Providers and the embedding Mnemon Native reads. */
5522
+ function installMemorySpacesSettings(ctx) {
5523
+ const { locale } = ctx;
5524
+ return (0, dsh_mnemon_client.installMemoryComponentUI)(ctx, {
5525
+ packageName: PACKAGE_NAME,
5526
+ settings: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemorySpacesSettings, {
5527
+ ...props,
5528
+ ...locale === void 0 ? {} : { locale }
5529
+ })
5530
+ });
5531
+ }
5532
+ function embeddingDraft(value) {
5533
+ const embedding = value?.embedding;
5534
+ return {
5535
+ endpoint: embedding?.endpoint?.trim() || "http://localhost:11434",
5536
+ model: embedding?.model?.trim() || "nomic-embed-text",
5537
+ apiKey: embedding?.apiKey?.trim() ?? "",
5538
+ protocol: embedding?.protocol ?? "auto"
5539
+ };
5540
+ }
5541
+ function validEmbeddingEndpoint(value) {
5542
+ const endpoint = value.trim();
5543
+ if (endpoint === "" || endpoint.length > 2048) return false;
5544
+ try {
5545
+ const parsed = new URL(endpoint);
5546
+ return ["http:", "https:"].includes(parsed.protocol) && parsed.username === "" && parsed.password === "" && !endpoint.includes("?") && !endpoint.includes("#");
5547
+ } catch {
5548
+ return false;
5549
+ }
5550
+ }
5551
+ function validEmbeddingModel(value) {
5552
+ const model = value.trim();
5553
+ return model.length > 0 && model.length <= 200 && !/[\u0000-\u001f\u007f]/u.test(model);
5554
+ }
5555
+ function validEmbeddingApiKey(value) {
5556
+ const key = value.trim();
5557
+ return key.length <= 2048 && !/[\u0000-\u001f\u007f]/u.test(key);
5558
+ }
5559
+ const validProtocol = (protocol) => MNEMON_EMBEDDING_PROTOCOLS.includes(protocol);
5560
+ function embeddingProblem(draft, t) {
5561
+ if (!validEmbeddingEndpoint(draft.endpoint)) return t("config.embeddingEndpointInvalid");
5562
+ if (!validEmbeddingModel(draft.model)) return t("config.embeddingModelInvalid");
5563
+ if (!validEmbeddingApiKey(draft.apiKey)) return t("config.embeddingApiKeyInvalid");
5564
+ if (!validProtocol(draft.protocol)) return t("config.embeddingProtocolInvalid");
5565
+ return null;
5566
+ }
5567
+ /** The stored value: a switched-off override keeps only the fields that are valid. */
5568
+ function embeddingValue(enabled, draft) {
5569
+ const endpoint = draft.endpoint.trim().replace(/\/+$/u, "");
5570
+ if (enabled) return {
5571
+ enabled: true,
5572
+ endpoint,
5573
+ model: draft.model.trim(),
5574
+ protocol: draft.protocol,
5575
+ apiKey: draft.apiKey.trim()
5576
+ };
5577
+ return {
5578
+ enabled: false,
5579
+ ...validEmbeddingEndpoint(draft.endpoint) ? { endpoint } : {},
5580
+ ...validEmbeddingModel(draft.model) ? { model: draft.model.trim() } : {},
5581
+ ...validProtocol(draft.protocol) ? { protocol: draft.protocol } : {},
5582
+ ...validEmbeddingApiKey(draft.apiKey) ? { apiKey: draft.apiKey.trim() } : {}
5583
+ };
5584
+ }
5585
+ /**
5586
+ * Memory Spaces' own settings: the Providers that store its spaces, Mnemon
5587
+ * Native first with the embedding runtime only Native reads. They need what
5588
+ * dsh-mnemon lends them; without it they show nothing. With DSH's language
5589
+ * service they translate as dsh-mnemon drew them, through its language chain.
5590
+ */
5591
+ function MemorySpacesSettings(props) {
5592
+ if (props.host === void 0) return null;
5593
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.MemorySourcePageFrame, {
5594
+ locale: props.language,
5595
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsTranslation, {
5596
+ locale: props.locale,
5597
+ language: props.language,
5598
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SpacesSettings, {
5599
+ page: props,
5600
+ host: props.host
5601
+ })
5602
+ })
5603
+ });
5604
+ }
5605
+ const noLocaleChanges = () => () => {};
5606
+ function SettingsTranslation(props) {
5607
+ const { locale, language } = props;
5608
+ const subscribe = (0, react.useCallback)((listener) => locale?.subscribe?.(listener) ?? noLocaleChanges(), [locale]);
5609
+ const getChain = (0, react.useCallback)(() => {
5610
+ const snapshot = locale?.getSnapshot?.();
5611
+ return snapshot === void 0 ? "" : languageChain(snapshot).join("\n");
5612
+ }, [locale]);
5613
+ const chain = (0, react.useSyncExternalStore)(subscribe, getChain, getChain);
5614
+ const translate = (0, react.useMemo)(() => locale === void 0 ? void 0 : settingsTranslate(locale, chain === "" ? void 0 : chain.split("\n"), language), [
5615
+ locale,
5616
+ chain,
5617
+ language
5618
+ ]);
5619
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SourceTranslation, {
5620
+ value: translate,
5621
+ children: props.children
5622
+ });
5623
+ }
5624
+ const RETAINED_CLI = "status-summary";
5625
+ function SpacesSettings({ page, host }) {
5626
+ const t = useT();
5627
+ const css = dsh_mnemon_client.memorySettingsStyles;
5628
+ const { configuration, retained } = host;
5629
+ const snapshot = (0, react.useSyncExternalStore)(configuration.subscribe, configuration.getSnapshot, configuration.getSnapshot);
5630
+ const value = snapshot.value;
5631
+ const client = (0, react.useMemo)(() => host.operations === void 0 ? void 0 : memorySpacesSettingsClient(host.operations), [host.operations]);
5632
+ const saved = embeddingDraft(value);
5633
+ const managedSaved = value?.embedding?.enabled === true;
5634
+ const managed = (0, dsh_mnemon_client.useLive)(managedSaved, async (enabled) => {
5635
+ await configuration.set("embedding", embeddingValue(enabled, saved));
5636
+ });
5637
+ const form = (0, dsh_mnemon_client.useStaged)(saved, async (draft) => {
5638
+ await configuration.set("embedding", embeddingValue(managedSaved, draft));
5639
+ });
5640
+ const [nativeCliFound, setNativeCliFound] = (0, react.useState)(() => retained.get(RETAINED_CLI)?.commandFound);
5641
+ const [status, setStatus] = (0, react.useState)({ state: "idle" });
5642
+ const [fill, setFill] = (0, react.useState)(void 0);
5643
+ const statusRequest = (0, react.useRef)(0);
5644
+ const on = page.component.enabled;
5645
+ (0, react.useEffect)(() => {
5646
+ if (client === void 0 || !on) {
5647
+ setNativeCliFound(void 0);
5648
+ retained.delete(RETAINED_CLI);
5649
+ return;
5650
+ }
5651
+ let current = true;
5652
+ client.statusSummary().then((summary) => {
5653
+ if (!current) return;
5654
+ setNativeCliFound(summary.commandFound);
5655
+ retained.set(RETAINED_CLI, { commandFound: summary.commandFound });
5656
+ }, () => {
5657
+ if (current) {
5658
+ setNativeCliFound(void 0);
5659
+ retained.delete(RETAINED_CLI);
5660
+ }
5661
+ });
5662
+ return () => {
5663
+ current = false;
5664
+ };
5665
+ }, [
5666
+ client,
5667
+ on,
5668
+ retained,
5669
+ snapshot.revision
5670
+ ]);
5671
+ (0, react.useEffect)(() => () => {
5672
+ retained.delete(RETAINED_CLI);
5673
+ }, [retained]);
5674
+ (0, react.useEffect)(() => {
5675
+ statusRequest.current += 1;
5676
+ setStatus({ state: "idle" });
5677
+ setFill(void 0);
5678
+ }, [client, snapshot.revision]);
5679
+ if (!on) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5680
+ className: css.panelNote,
5681
+ children: t("spaces.offNote")
5682
+ });
5683
+ const test = () => {
5684
+ if (client === void 0) return;
5685
+ const request = statusRequest.current + 1;
5686
+ statusRequest.current = request;
5687
+ setStatus((previous) => ({
5688
+ state: "loading",
5689
+ ...previous.value === void 0 ? {} : { value: previous.value }
5690
+ }));
5691
+ client.embeddingStatus().then((value) => {
5692
+ if (statusRequest.current === request) setStatus({
5693
+ state: "ready",
5694
+ value
5695
+ });
5696
+ }, (reason) => {
5697
+ if (statusRequest.current === request) setStatus({
5698
+ state: "error",
5699
+ error: (0, dsh_mnemon_client.message)(reason)
5700
+ });
5701
+ });
5702
+ };
5703
+ const fillSpace = (space) => {
5704
+ if (client === void 0 || fill?.state === "running") return;
5705
+ const target = {
5706
+ memoryBodyId: space.memoryBodyId,
5707
+ name: space.name
5708
+ };
5709
+ setFill({
5710
+ ...target,
5711
+ state: "running"
5712
+ });
5713
+ client.fillEmbeddings(space.memoryBodyId).then((result) => {
5714
+ setFill({
5715
+ ...target,
5716
+ state: "done",
5717
+ result
5718
+ });
5719
+ test();
5720
+ }, (reason) => {
5721
+ setFill({
5722
+ ...target,
5723
+ state: "failed",
5724
+ error: (0, dsh_mnemon_client.message)(reason)
5725
+ });
5726
+ test();
5727
+ });
5728
+ };
5729
+ const activeScope = value?.storageScope === "workspace" || value?.storageScope === "workspaces" ? "workspace" : "global";
5730
+ const readOnly = value?.writeEnabled === false;
5731
+ const disabled = !page.writable || snapshot.status === "loading" || !snapshot.writable;
5732
+ const cliMissing = nativeCliFound === false;
5733
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5734
+ className: css.panelSection,
5735
+ "aria-labelledby": "mnemon-spaces-providers",
5736
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5737
+ className: css.panelHeading,
5738
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
5739
+ id: "mnemon-spaces-providers",
5740
+ children: t("config.providersTitle")
5741
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("config.providersDescription") })]
5742
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderSettingsSection, {
5743
+ client,
5744
+ retained,
5745
+ ...activeScope !== "workspace" || page.workspace?.label === void 0 ? {} : { workspaceLabel: page.workspace.label },
5746
+ activeScope,
5747
+ refreshKey: snapshot.revision ?? 0,
5748
+ disabled: disabled || readOnly,
5749
+ scopeChanging: false,
5750
+ onChanged: host.changed,
5751
+ ...readOnly ? { notice: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.Callout, {
5752
+ tone: "warning",
5753
+ className: css.groupCallout,
5754
+ title: t("config.providersReadOnlyTitle"),
5755
+ children: t("config.providersReadOnlyDetail")
5756
+ }) } : {},
5757
+ leading: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NativeProviderCard, {
5758
+ activeScope,
5759
+ cliMissing,
5760
+ t,
5761
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmbeddingEditor, {
5762
+ managed: managed.value,
5763
+ draft: form.draft,
5764
+ disabled,
5765
+ connectionAvailable: client !== void 0,
5766
+ cliMissing,
5767
+ changing: form.dirty,
5768
+ status,
5769
+ t,
5770
+ onEdit: form.edit,
5771
+ onTest: () => {
5772
+ setFill(void 0);
5773
+ test();
5774
+ },
5775
+ canFill: !disabled && !readOnly,
5776
+ fill,
5777
+ onFill: fillSpace,
5778
+ onManaged: (on) => {
5779
+ if (!on) form.discard();
5780
+ managed.set(on);
5781
+ },
5782
+ actions: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.WriteFailure, {
5783
+ error: managed.failed,
5784
+ t
5785
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.PanelActions, {
5786
+ dirty: form.dirty,
5787
+ saving: form.saving,
5788
+ invalid: embeddingProblem(form.draft, t),
5789
+ failed: form.failed,
5790
+ applied: form.applied,
5791
+ disabled,
5792
+ t,
5793
+ onDiscard: form.discard,
5794
+ onApply: () => {
5795
+ form.apply();
5796
+ }
5797
+ })] })
5798
+ })
5799
+ })
5800
+ })]
5801
+ });
5802
+ }
5803
+ /** Mnemon Native, listed first among the Providers; its body holds the settings only Native reads. */
5804
+ function NativeProviderCard(props) {
5805
+ const css = dsh_mnemon_client.memorySettingsStyles;
5806
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
5807
+ className: css.providerRow,
5808
+ "data-provider": NATIVE_PROVIDER_ID,
5809
+ "data-native": "",
5810
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
5811
+ className: css.providerRowHeader,
5812
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5813
+ className: css.providerIdentity,
5814
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderIcon, {
5815
+ providerId: NATIVE_PROVIDER_ID,
5816
+ icon: {
5817
+ kind: "brand",
5818
+ value: "mnemon"
5819
+ },
5820
+ className: css.providerMark
5821
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: props.t("config.nativeName") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: props.t("config.nativeSummary") })] })]
5822
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5823
+ className: css.providerEnableControl,
5824
+ children: [
5825
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5826
+ className: css.providerScopeTag,
5827
+ "data-scope": props.activeScope,
5828
+ children: props.t(`config.${props.activeScope}`)
5829
+ }),
5830
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5831
+ className: css.providerState,
5832
+ "data-enabled": props.cliMissing ? void 0 : "",
5833
+ children: props.t(props.cliMissing ? "config.nativeCliMissing" : "config.officialNative")
5834
+ }),
5835
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
5836
+ className: css.providerChevron,
5837
+ size: 14
5838
+ })
5839
+ ]
5840
+ })]
5841
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5842
+ className: css.providerInlineBody,
5843
+ children: props.children
5844
+ })]
5845
+ });
5846
+ }
5847
+ /** Reachability and coverage line; the protocol appears only when the Host reports one. */
5848
+ function embeddingStatusText(t, status) {
5849
+ const coverage = {
5850
+ embedded: status.embedded,
5851
+ total: status.totalInsights,
5852
+ coverage: status.coverage
5853
+ };
5854
+ return status.protocol === void 0 ? t(status.available ? "config.embeddingStatusAvailable" : "config.embeddingStatusUnavailable", {
5855
+ model: status.model,
5856
+ ...coverage
5857
+ }) : t(status.available ? "config.embeddingStatusAvailableWithProtocol" : "config.embeddingStatusUnavailableWithProtocol", {
5858
+ model: status.model,
5859
+ protocol: status.protocol,
5860
+ ...coverage
5861
+ });
5862
+ }
5863
+ /** The embedding runtime: the switch applies at once; the connection fields, shown while DSH manages it, wait for Apply. */
5864
+ function EmbeddingEditor(props) {
5865
+ const { draft, t, status } = props;
5866
+ const css = dsh_mnemon_client.memorySettingsStyles;
5867
+ const feedback = props.cliMissing ? t("config.embeddingCliMissing") : props.changing ? t("config.embeddingSaveBeforeTest") : status.state === "loading" ? t("config.embeddingTesting") : status.state === "error" ? t("config.embeddingStatusFailed", { error: status.error ?? "" }) : status.state === "ready" && status.value !== void 0 ? embeddingStatusText(t, status.value) : !props.connectionAvailable ? t("config.embeddingTestUnavailable") : t("config.embeddingNotTested");
5868
+ const text = (field, type, label, valid, placeholder) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [label, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5869
+ type,
5870
+ "aria-label": label,
5871
+ "aria-invalid": !valid,
5872
+ value: draft[field],
5873
+ disabled: props.disabled,
5874
+ autoComplete: "off",
5875
+ spellCheck: false,
5876
+ autoCapitalize: "none",
5877
+ autoCorrect: "off",
5878
+ placeholder,
5879
+ onChange: (event) => props.onEdit({ [field]: event.target.value })
5880
+ })] });
5881
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5882
+ className: css.editor,
5883
+ "aria-labelledby": "mnemon-embedding-heading",
5884
+ children: [
5885
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5886
+ className: css.editorHeading,
5887
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
5888
+ id: "mnemon-embedding-heading",
5889
+ children: t("config.embeddingTitle")
5890
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("config.embeddingDescription") })]
5891
+ }),
5892
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.ToggleRow, {
5893
+ id: "mnemon-embedding-managed",
5894
+ label: t("config.embeddingManaged"),
5895
+ hint: t("config.embeddingManagedHint"),
5896
+ checked: props.managed,
5897
+ disabled: props.disabled,
5898
+ onChange: props.onManaged
5899
+ }),
5900
+ props.managed && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5901
+ className: css.fieldGrid,
5902
+ children: [
5903
+ text("endpoint", "url", t("config.embeddingEndpoint"), validEmbeddingEndpoint(draft.endpoint), "http://localhost:11434"),
5904
+ text("model", "text", t("config.embeddingModel"), validEmbeddingModel(draft.model), "nomic-embed-text"),
5905
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
5906
+ label: t("config.embeddingProtocol"),
5907
+ value: draft.protocol,
5908
+ disabled: props.disabled,
5909
+ options: [
5910
+ {
5911
+ value: "auto",
5912
+ label: t("config.embeddingProtocolAuto")
5913
+ },
5914
+ {
5915
+ value: "ollama",
5916
+ label: t("config.embeddingProtocolOllama")
5917
+ },
5918
+ {
5919
+ value: "openai",
5920
+ label: t("config.embeddingProtocolOpenai")
5921
+ }
5922
+ ],
5923
+ onChange: (protocol) => props.onEdit({ protocol })
5924
+ }),
5925
+ text("apiKey", "password", t("config.embeddingApiKey"), validEmbeddingApiKey(draft.apiKey), "sk-…")
5926
+ ]
5927
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5928
+ className: css.editorNote,
5929
+ children: t("config.embeddingSecurity")
5930
+ })] }),
5931
+ props.actions,
5932
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5933
+ className: css.embeddingTest,
5934
+ "aria-live": "polite",
5935
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5936
+ className: status.state === "error" ? css.error : void 0,
5937
+ role: status.state === "error" ? "alert" : void 0,
5938
+ children: feedback
5939
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5940
+ variant: "outline",
5941
+ size: "sm",
5942
+ disabled: props.disabled || !props.connectionAvailable || props.cliMissing || props.changing || status.state === "loading" || props.fill?.state === "running",
5943
+ onClick: props.onTest,
5944
+ children: t("config.embeddingTest")
5945
+ })]
5946
+ }),
5947
+ !props.cliMissing && !props.changing && (status.state === "ready" || status.state === "loading") && (status.value?.spaces ?? []).length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmbeddingSpaces, {
5948
+ spaces: status.value.spaces,
5949
+ available: status.value.available,
5950
+ canFill: props.canFill,
5951
+ counting: status.state === "loading",
5952
+ fill: props.fill,
5953
+ onFill: props.onFill,
5954
+ t
5955
+ }),
5956
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmbeddingFillOutcome, {
5957
+ fill: props.fill,
5958
+ t
5959
+ })
5960
+ ]
5961
+ });
5962
+ }
5963
+ /**
5964
+ * Each Mnemon Native space's vectors under the status line. Mnemon counts one Store at a
5965
+ * time, so the total alone could read as every space's health while one lacked vectors (#392).
5966
+ * A space that lacks them can have them filled in here while the embedding service answers.
5967
+ */
5968
+ function EmbeddingSpaces(props) {
5969
+ const { t, fill } = props;
5970
+ const css = dsh_mnemon_client.memorySettingsStyles;
5971
+ const missing = (space) => space.error === void 0 && space.embedded < space.totalInsights;
5972
+ const fillable = props.available && props.canFill;
5973
+ const running = fill?.state === "running" ? fill.memoryBodyId : void 0;
5974
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5975
+ className: css.embeddingSpaces,
5976
+ children: [
5977
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
5978
+ id: "mnemon-embedding-spaces",
5979
+ children: t("config.embeddingSpaces")
5980
+ }),
5981
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5982
+ "aria-labelledby": "mnemon-embedding-spaces",
5983
+ children: props.spaces.map((space) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
5984
+ "data-missing": missing(space) ? "" : void 0,
5985
+ "data-failed": space.error === void 0 ? void 0 : "",
5986
+ children: [
5987
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5988
+ className: css.embeddingSpaceName,
5989
+ title: space.name,
5990
+ children: space.name
5991
+ }),
5992
+ !space.active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5993
+ className: css.embeddingSpaceState,
5994
+ children: t("common.inactive")
5995
+ }),
5996
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5997
+ className: css.embeddingSpaceCount,
5998
+ children: space.error === void 0 ? t("config.embeddingSpaceCounts", {
5999
+ embedded: space.embedded,
6000
+ total: space.totalInsights,
6001
+ coverage: space.coverage
6002
+ }) : t("config.embeddingSpaceFailed", { error: space.error })
6003
+ }),
6004
+ fillable && missing(space) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
6005
+ variant: "ghost",
6006
+ size: "sm",
6007
+ disabled: running !== void 0 || props.counting,
6008
+ "aria-busy": running === space.memoryBodyId,
6009
+ "aria-label": t(running === space.memoryBodyId ? "config.embeddingFillingLabel" : "config.embeddingFillLabel", { name: space.name }),
6010
+ onClick: () => props.onFill(space),
6011
+ children: running === space.memoryBodyId ? t("config.embeddingFilling") : t("config.embeddingFill")
6012
+ })
6013
+ ]
6014
+ }, space.memoryBodyId))
6015
+ }),
6016
+ props.spaces.some(missing) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(!props.canFill ? "config.embeddingMissing" : props.available ? "config.embeddingMissingFill" : "config.embeddingMissingOffline") }),
6017
+ props.spaces.some((space) => space.error !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("config.embeddingSpacesUnread") })
6018
+ ]
6019
+ });
6020
+ }
6021
+ /** What the last fill did. It stays while the counts are read again, and reads as a failure when it wrote no vector. */
6022
+ function EmbeddingFillOutcome(props) {
6023
+ const { fill, t } = props;
6024
+ const css = dsh_mnemon_client.memorySettingsStyles;
6025
+ if (fill === void 0 || fill.state === "running") return null;
6026
+ const failure = (text) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6027
+ className: `${css.embeddingFillOutcome} ${css.error}`,
6028
+ role: "alert",
6029
+ children: text
6030
+ });
6031
+ if (fill.state === "failed") return failure(t("config.embeddingFillFailed", {
6032
+ name: fill.name,
6033
+ error: fill.error
6034
+ }));
6035
+ const { filled, remaining, model, stopped } = fill.result;
6036
+ const name = fill.name;
6037
+ if (remaining > 0 && stopped === "refused" && filled === 0) return failure(t("config.embeddingFillRefused", {
6038
+ name,
6039
+ model
6040
+ }));
6041
+ const text = remaining === 0 ? filled > 0 ? t("config.embeddingFillDone", {
6042
+ name,
6043
+ filled
6044
+ }) : void 0 : stopped === "refused" ? t("config.embeddingFillPartly", {
6045
+ name,
6046
+ filled,
6047
+ remaining
6048
+ }) : t("config.embeddingFillMore", {
6049
+ name,
6050
+ filled,
6051
+ remaining
6052
+ });
6053
+ return text === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6054
+ className: css.embeddingFillOutcome,
6055
+ role: "status",
6056
+ children: text
6057
+ });
6058
+ }
4584
6059
  //#endregion
4585
6060
  //#region src/client/ui.tsx
4586
6061
  /** The adapter never gets a transport or chooses another Source instance. */
@@ -4820,6 +6295,7 @@ window.__ModuleLoader__.load({
4820
6295
  memoryBodies: bodies,
4821
6296
  writeEnabled: writable,
4822
6297
  seed,
6298
+ embeddingManaged: status?.embeddingManaged,
4823
6299
  onMutate: refresh,
4824
6300
  onClose: () => setRememberOpen(false),
4825
6301
  onView: () => {
@@ -4900,14 +6376,18 @@ window.__ModuleLoader__.load({
4900
6376
  const inject = ["slots", "locale"];
4901
6377
  function apply(ctx) {
4902
6378
  installMemorySpacesUI(ctx, ctx.locale.bind("mnemon"));
6379
+ if (yieldsComponentSettings(dsh_mnemon_client)) installMemorySpacesSettings(ctx);
4903
6380
  }
4904
6381
  //#endregion
4905
6382
  exports.EntitiesPage = EntitiesPage;
4906
6383
  exports.ExplorePage = ExplorePage;
4907
6384
  exports.ListPage = ListPage;
6385
+ exports.MemorySpacesSettings = MemorySpacesSettings;
4908
6386
  exports.MemorySpacesSourcePage = MemorySpacesSourcePage;
6387
+ exports.NATIVE_PROVIDER_ID = NATIVE_PROVIDER_ID;
4909
6388
  exports.OverviewPage = OverviewPage;
4910
6389
  exports.PersistenceStrategyDialog = PersistenceStrategyDialog;
6390
+ exports.ProviderIcon = ProviderIcon;
4911
6391
  exports.RememberPage = RememberPage;
4912
6392
  exports.apply = apply;
4913
6393
  exports.inject = inject;