beatsad_Vault2Dify/main.js

122 lines
121 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var N=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var oe=Object.prototype.hasOwnProperty;var le=(a,r)=>{for(var e in r)N(a,e,{get:r[e],enumerable:!0})},ce=(a,r,e,t)=>{if(r&&typeof r=="object"||typeof r=="function")for(let i of re(r))!oe.call(a,i)&&i!==e&&N(a,i,{get:()=>r[i],enumerable:!(t=ae(r,i))||t.enumerable});return a};var de=a=>ce(N({},"__esModule",{value:!0}),a);var Me={};le(Me,{default:()=>I});module.exports=de(Me);var p=require("obsidian");function E(a,r){return`${a}::${r}`}function F(a,r,e,t){let i=[];return a.forEach((n,s)=>{n.filePath===r&&i.push([s,{...n,filePath:e,remoteName:n.remoteName||t(r),deletedLocal:!1}])}),i.forEach(([n,s])=>{a.delete(n),a.set(E(s.datasetId,e),s)}),i.length>0}function B(a,r,e,t,i,n=new Date,s=3e4){let o=E(r,e);if(a.has(o))return!1;let c,l,d=-1;return a.forEach((u,h)=>{if(u.datasetId!==r||u.filePath===e||!u.documentId||!u.deletedLocal||u.hash!==t)return;let g=Date.parse(u.lastSyncedAt);if(!Number.isFinite(g))return;let y=n.getTime()-g;y<0||y>s||g<=d||(c=h,l=u,d=g)}),!c||!l?!1:(a.delete(c),a.set(o,{...l,filePath:e,remoteName:l.remoteName||i(l.filePath),deletedLocal:!1}),!0)}var J=require("obsidian");function _(a,r=""){let e=T(a,r),t=z(a);if(!t)throw new Error(j(e));return t.filter(i=>!!(i!=null&&i.id)).map(i=>({id:i.id,name:i.name||i.id,description:i.description}))}function V(a,r=""){if(!z(a))throw new Error(j(T(a,r)))}function T(a,r=""){let e=/^\s*</.test(r||""),t=Array.isArray(a)?"array":a===null?"null":typeof a,i=Q(a)?a:void 0,n=i==null?void 0:i.data;return{topLevelType:t,topLevelKeys:i?Object.keys(i).slice(0,12):[],dataIsArray:Array.isArray(n),dataLength:Array.isArray(n)?n.length:void 0,looksLikeHtml:e}}function z(a){return Array.isArray(a)?a:Q(a)&&Array.isArray(a.data)?a.data:null}function j(a){let r=a.looksLikeHtml?"received an HTML page":`top-level type ${a.topLevelType}`,e=a.topLevelKeys.length>0?`; top-level fields: ${a.topLevelKeys.join(", ")}`:"";return`Current address did not return a Dify knowledge base API response (${r}${e}).`}function Q(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)}function b(a){let r=(a||"").trim().replace(/\/+$/,"").replace(/\/v1\/datasets$/i,"").replace(/\/v1$/i,"");return r?/^https?:\/\//i.test(r)?r:`http://${r}`:""}function P(a){return(a||"").trim().replace(/^\/+|\/+$/g,"")}function pe(a,r){let e=P(r);return e===""?!0:e.toLowerCase().endsWith(".md")?a===e:a===e||a.startsWith(`${e}/`)}function A(a){if(!a)return{};try{return JSON.parse(a)}catch(r){return{}}}function f(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)}function S(a,r){let e=a[r];return typeof e=="string"?e:void 0}function k(a,r){let e=a[r];return typeof e=="number"?e:void 0}function D(a){return Array.from(new Set(a.map(r=>r.trim()).filter(Boolean)))}function W(a,r){let e=[];return r.filter(t=>t.enabled&&Array.isArray(t.datasetIds)&&t.datasetIds.length>0).forEach(t=>{pe(a,t.folder)&&e.push(...t.datasetIds)}),D(e)}function G(a,r){return a.filter(e=>e.id!==r)}function v(a,r,e,t){let i=Number(a);return Number.isFinite(i)?Math.min(e,Math.max(r,i)):t}var m=class extends Error{constructor(e,t,i,n){super(e);this.name="DifyApiError",this.status=t,this.responseText=i,this.reason=n,Object.setPrototypeOf(this,m.prototype)}get isTransient(){return!this.status||this.status===408||this.status===429||this.status>=500}get isPathMismatch(){return this.status===404||this.status===405}},M=class{constructor(r){this.activeBaseUrl="";this.runtimePathStyle=null;this.host=r}getActiveBaseUrl(){return this.activeBaseUrl}setActiveBaseUrl(r){let e=this.getCandidateBaseUrls(!1);r&&e.includes(r)&&(this.activeBaseUrl=r)}clearActiveBaseUrl(){this.activeBaseUrl=""}async probeConnection(){let r=this.getCandidateBaseUrls(!1),e=new Date().toISOString(),t=[],i=null,n=null;for(let s of r){let o=Date.now();try{let c=await this.listDatasetsFromBaseUrl(s),l=Date.now()-o;return this.activeBaseUrl=s,t.push({baseUrl:s,ok:!0,latencyMs:l,datasetCount:c.length}),{status:"connected",checkedAt:e,activeBaseUrl:s,lastSuccessfulBaseUrl:s,datasetCount:c.length,latencyMs:l,candidates:t,datasets:c}}catch(c){let l=this.toApiError(c),d=C(l);if(i=l,n={baseUrl:s,ok:!1,latencyMs:Date.now()-o,statusCode:l.status,error:l.message,reason:d},t.push(n),!this.shouldTryNextBase(l))break}}return{status:"failed",checkedAt:e,activeBaseUrl:"",datasetCount:0,latencyMs:t.reduce((s,o)=>s+o.latencyMs,0),candidates:t,error:(n==null?void 0:n.error)||(i==null?void 0:i.message)||"No Dify API URL is available.",reason:(n==null?void 0:n.reason)||(i?C(i):"unknown"),statusCode:n==null?void 0:n.statusCode,datasets:[]}}async listDatasets(){let r=[];for(let t=1;t<=50;t++){let i=await this.requestUnknown(`/datasets?page=${t}&limit=${100}`,{method:"GET"}),n=this.extractDatasets(i);if(r.push(...n),!H(i)&&n.length<100)break}return r}extractDatasets(r){return _(r)}async listDatasetsFromBaseUrl(r){let e=[];for(let i=1;i<=50;i++){let n=await this.requestOnce(r,`/datasets?page=${i}&limit=${100}`,{method:"GET"}),s=this.extractDatasets(n);if(e.push(...s),!H(n)&&s.length<100)break}return e}async listDocuments(r){let e=[];for(let i=1;i<=100;i++){let n=await this.requestUnknown(`/datasets/${encodeURIComponent(r)}/documents?page=${i}&limit=${100}`,{method:"GET"}),s=ue(n);if(s.forEach(o=>{e.push(o)}),!H(n)&&s.length<100)break}return e}async createDocumentByText(r,e,t){return this.mutateTextDocument(r,void 0,{name:e,text:t,indexing_technique:"high_quality",process_rule:{mode:"automatic"}})}async updateDocumentByText(r,e,t,i){return this.mutateTextDocument(r,e,{name:t,text:i,process_rule:{mode:"automatic"}})}async getIndexingStatus(r,e){return this.requestUnknown(`/datasets/${encodeURIComponent(r)}/documents/${encodeURIComponent(e)}/indexing-status`,{method:"GET"})}async mutateTextDocument(r,e,t){let i=this.getPathStyleCandidates(),n=null;for(let s of i){let o=e?`/datasets/${encodeURIComponent(r)}/documents/${encodeURIComponent(e)}/${s==="hyphen"?"update-by-text":"update_by_text"}`:`/datasets/${encodeURIComponent(r)}/document/${s==="hyphen"?"create-by-text":"create_by_text"}`;try{let c=await this.request(o,{method:"POST",body:t},he);return this.runtimePathStyle=s,c}catch(c){let l=this.toApiError(c);if(n=l,this.host.settings.apiPathStyle==="auto"&&l.isPathMismatch){this.host.debug(`Dify API path style ${s} failed, trying fallback`,l.message);continue}throw l}}throw n||new m("Unable to resolve Dify document API path.")}getPathStyleCandidates(){return this.host.settings.apiPathStyle==="hyphen"?["hyphen"]:this.host.settings.apiPathStyle==="underscore"?["underscore"]:this.runtimePathStyle?[this.runtimePathStyle,this.runtimePathStyle==="hyphen"?"underscore":"hyphen"]:["hyphen","underscore"]}async requestUnknown(r,e){return this.request(r,e,t=>!0)}async request(r,e,t){let i=this.getCandidateBaseUrls(),n=null;for(let s of i){let o=Math.max(1,this.host.settings.maxRetries+1);for(let c=1;c<=o;c++)try{let l=await this.requestOnce(s,r,e);if(this.activeBaseUrl=s,!t(l))throw new m("Dify returned an unexpected response shape.",void 0,JSON.stringify(l));return l}catch(l){let d=this.toApiError(l);if(n=d,!d.isTransient||c>=o)break;await fe(400*c)}if(n&&!this.shouldTryNextBase(n))throw n}throw n||new m("No Dify API URL is available.")}async requestOnce(r,e,t){let i=`${r}/v1${e}`;this.host.debug(`${t.method} ${i}`);let n=Math.max(5,this.host.settings.requestTimeoutSeconds)*1e3,s=null,o=new Promise((c,l)=>{s=window.setTimeout(()=>{l(new m(`Request timed out after ${this.host.settings.requestTimeoutSeconds}s`))},n)});try{let c={url:i,method:t.method,headers:{Authorization:`Bearer ${this.host.settings.difyApiKey}`,"Content-Type":"application/json"},body:t.body?JSON.stringify(t.body):void 0,throw:!1},l=(0,J.requestUrl)(c),d=await Promise.race([l,o]);if(s!==null&&window.clearTimeout(s),d.status<200||d.status>=300)throw new m(this.extractErrorMessage(d.text,d.status),d.status,d.text);let u=A(d.text);return this.logResponseDiagnostics(i,d.status,u,d.text),me(e)&&V(u,d.text),u}catch(c){throw s!==null&&window.clearTimeout(s),this.toApiError(c)}}getCandidateBaseUrls(r=!0){let e=this.host.settings,i=[b(e.difyApiUrl)],n=D(i.filter(Boolean));return r&&this.activeBaseUrl&&n.includes(this.activeBaseUrl)?[this.activeBaseUrl,...n.filter(s=>s!==this.activeBaseUrl)]:n}shouldTryNextBase(r){return!r.status||r.status===404||r.status>=500}extractErrorMessage(r,e){let t=A(r),i=f(t)?S(t,"message")||S(t,"error")||S(t,"detail")||r||"Unknown error":r||"Unknown error";return`HTTP ${e}: ${String(i).slice(0,300)}`}logResponseDiagnostics(r,e,t,i=""){let n=T(t,i);this.host.debug("Dify API response",{url:r,status:e,topLevelType:n.topLevelType,topLevelKeys:n.topLevelKeys,dataIsArray:n.dataIsArray,dataLength:n.dataLength,looksLikeHtml:n.looksLikeHtml})}toApiError(r){if(r instanceof m)return r;let e=ge(r),t=typeof e.status=="number"?e.status:void 0,i=typeof e.message=="string"?e.message:String(r),n=typeof e.text=="string"?e.text:typeof e.responseText=="string"?e.responseText:void 0,s=ye(e.reason)?e.reason:void 0;return new m(i,t,n,s)}};function H(a){return f(a)&&a.has_more===!0}function ue(a){return(Array.isArray(a)?a:f(a)&&Array.isArray(a.data)?a.data:[]).filter(U)}function U(a){return f(a)&&typeof a.id=="string"}function he(a){if(!f(a))return!1;let r=a.document,e=a.data;return(r===void 0||U(r))&&(e===void 0||U(e))}function ge(a){return f(a)?a:{}}function C(a){if(a.reason)return a.reason;let r=a.message.toLowerCase();return a.status===401?"auth_failed":a.status===403?"permission_denied":a.status===404?"not_found":a.status===405?"path_mismatch":a.status===429?"rate_limited":a.status&&a.status>=500?"server":r.includes("did not return a dify knowledge base api response")||r.includes("received an html page")?"unexpected_response":r.includes("timed out")||r.includes("timeout")?"timeout":r.includes("failed to fetch")||r.includes("network")||r.includes("econnrefused")||r.includes("enotfound")||r.includes("econnreset")?"network":"unknown"}function ye(a){return["missing_config","auth_failed","permission_denied","not_found","timeout","network","server","path_mismatch","rate_limited","unexpected_response","unknown"].includes(String(a))}function me(a){return a==="/datasets"||a.startsWith("/datasets?")}function fe(a){return new Promise(r=>window.setTimeout(r,a))}function Y(a){var t;let r=a.recentSyncResult,e=x(r==null?void 0:r.failed);return{metrics:[{key:"total",value:x(r==null?void 0:r.total),tone:"accent"},{key:"synced",value:x(r==null?void 0:r.synced),tone:"success"},{key:"skipped",value:x(r==null?void 0:r.skipped),tone:"warning"},{key:"failed",value:e,tone:"error"}],connectionTone:Se((t=a.connectionHealth)==null?void 0:t.status),hasRecentSync:!!r}}function Se(a){return a==="connected"?"success":a==="failed"?"error":a==="missing_config"?"warning":"muted"}function x(a){return typeof a=="number"&&Number.isFinite(a)&&a>0?Math.floor(a):0}var ve={schemaVersion:2,initialSetupCompleted:!1,language:"en",difyApiKey:"",difyApiUrl:"",lanApiUrl:"",publicApiUrl:"",endpointMode:"primary",apiPathStyle:"auto",difyKnowledgeId:"",obsidianFolders:[],mappings:[],knowledgeBases:[],lastDatasetRefresh:"",autoSyncEnabled:!1,eventSyncEnabled:!0,syncOnStartup:!0,periodicFullScanEnabled:!0,syncInterval:30,debounceSeconds:8,requestTimeoutSeconds:30,maxRetries:2,maxConcurrent:2,pollIndexStatus:!1,debugLogging:!1,lastSyncTime:"",connectionHealth:te(),recentSyncResult:void 0},K={"zh-CN":{pluginName:"Vault2Dify",ribbon:"\u540C\u6B65\u5230 Dify",commandManual:"Vault2Dify: \u540C\u6B65\u5230 Dify \u77E5\u8BC6\u5E93",commandToggleAuto:"\u5F00\u542F/\u5173\u95ED\u81EA\u52A8\u540C\u6B65",ready:"\u5C31\u7EEA",syncing:"\u6B63\u5728\u540C\u6B65...",syncQueued:"\u5DF2\u6709\u540C\u6B65\u6B63\u5728\u8FD0\u884C\uFF0C\u672C\u6B21\u53D8\u66F4\u5DF2\u52A0\u5165\u961F\u5217\u3002",syncNotice:"\u6B63\u5728\u540C\u6B65\u5230 Dify \u77E5\u8BC6\u5E93...",syncComplete:"\u540C\u6B65\u5B8C\u6210\uFF1A{synced} \u4E2A\u6210\u529F\uFF0C{skipped} \u4E2A\u8DF3\u8FC7\uFF0C{failed} \u4E2A\u5931\u8D25",syncNoChanges:"\u6CA1\u6709\u9700\u8981\u540C\u6B65\u7684\u53D8\u66F4\u3002",syncFailed:"\u540C\u6B65\u5931\u8D25\uFF1A{message}",syncFailedShort:"\u5931\u8D25",validationApiKey:"\u8BF7\u5148\u914D\u7F6E Dify API Key\u3002",validationApiUrl:"\u8BF7\u5148\u914D\u7F6E Dify \u670D\u52A1\u5730\u5740\u3002",validationMapping:"\u8BF7\u81F3\u5C11\u914D\u7F6E\u4E00\u6761\u8DEF\u5F84\u4E0E\u77E5\u8BC6\u5E93\u6620\u5C04\u3002",autoOn:"\u81EA\u52A8\u540C\u6B65\u5DF2\u5F00\u542F",autoOff:"\u81EA\u52A8\u540C\u6B65\u5DF2\u5173\u95ED",settingsTitle:"Vault2Dify",settingsSubtitle:"\u5C06 Obsidian \u7B14\u8BB0\u5E93\u540C\u6B65\u5230 Dify \u77E5\u8BC6\u5E93",settingsHelp:"\u5C06 Obsidian \u7B14\u8BB0\u5E93\u540C\u6B65\u5230 Dify \u77E5\u8BC6\u5E93\u3002",openGithub:"\u6253\u5F00 GitHub \u5F00\u6E90\u9879\u76EE",openHelp:"\u6253\u5F00\u5E2E\u52A9\u6587\u6863",helpModalTitle:"Vault2Dify \u5E2E\u52A9",helpQuickStartTitle:"\u5FEB\u901F\u5F00\u59CB",helpQuickStartBody:"Vault2Dify \u4F1A\u5C06 Obsidian \u7B14\u8BB0\u5E93\u540C\u6B65\u5230\u4F60\u914D\u7F6E\u7684 Dify \u77E5\u8BC6\u5E93\u3002",helpQuickStartList:`\u586B\u5199 Dify API Key\u3002
\u586B\u5199 Dify \u670D\u52A1\u5730\u5740\u3002
\u70B9\u51FB\u6D4B\u8BD5\u8FDE\u63A5\uFF0C\u63D2\u4EF6\u4F1A\u81EA\u52A8\u83B7\u53D6\u77E5\u8BC6\u5E93\u3002
\u65B0\u589E\u8DEF\u5F84\u6620\u5C04\u3002
\u6309\u9700\u70B9\u51FB\u7ACB\u5373\u540C\u6B65\uFF0C\u6216\u4FDD\u6301\u81EA\u52A8\u540C\u6B65\u5F00\u542F\u3002`,helpApiUrlTitle:"\u5730\u5740\u5982\u4F55\u586B\u5199",helpApiUrlBody:`Dify API Key\uFF1A\u5FC5\u586B\u9879\uFF0C\u7528\u4E8E\u8BBF\u95EE\u4F60\u7684 Dify \u77E5\u8BC6\u5E93\uFF0C\u8BF7\u4ECE Dify \u77E5\u8BC6\u5E93 API \u8BBE\u7F6E\u4E2D\u590D\u5236\u3002\u793A\u4F8B\uFF1Adataset-vtpB1fgqv************
Dify \u670D\u52A1\u5730\u5740\uFF1A\u5FC5\u586B\u9879\uFF0C\u662F\u63D2\u4EF6\u8FDE\u63A5 Dify \u7684\u4E3B\u5730\u5740\uFF0C\u9002\u7528\u4E8E Dify \u90E8\u7F72\u5728\u4E91\u670D\u52A1\u5668\u3001NAS\u3001\u672C\u5730 Docker \u7B49\u60C5\u51B5\u3002\u793A\u4F8B\uFF1Ahttp://dify-host.example.test:5000 \u6216 https://dify.example.com
\u5982\u679C\u4F60\u7684 Dify \u77E5\u8BC6\u5E93\u90E8\u7F72\u5728 NAS\uFF0C\u5E76\u5E0C\u671B\u5728\u5BB6\u4E2D\u3001\u516C\u53F8\u6216\u5916\u51FA\u65F6\u90FD\u80FD\u8BBF\u95EE\uFF0C\u53EF\u4EE5\u5728 NAS \u548C\u7B14\u8BB0\u672C\u4E0A\u5B89\u88C5\u5E76\u914D\u7F6E Tailscale\uFF0C\u7136\u540E\u586B\u5199\uFF1Ahttp://tailnet-device.example.test:Dify \u6620\u5C04\u7AEF\u53E3\u3002\u793A\u4F8B\uFF1Ahttp://tailnet-device.example.test:5000`,helpApiKeyTitle:"API Key \u8981\u6C42",helpApiKeyBody:"\u8BF7\u4F7F\u7528 Dify \u77E5\u8BC6\u5E93 API Key\uFF0C\u5E76\u786E\u8BA4\u5B83\u5177\u5907\u8BBF\u95EE\u77E5\u8BC6\u5E93\u3001\u67E5\u8BE2\u77E5\u8BC6\u5E93\u5217\u8868\u3001\u521B\u5EFA\u6587\u6863\u3001\u66F4\u65B0\u6587\u6863\u548C\u67E5\u8BE2\u6587\u6863\u5217\u8868\u6743\u9650\u3002\u5982\u679C\u6D4B\u8BD5\u8FDE\u63A5\u63D0\u793A\u6743\u9650\u4E0D\u8DB3\uFF0C\u8BF7\u68C0\u67E5 API Key \u662F\u5426\u6765\u81EA\u6B63\u786E\u7684 Dify \u5B9E\u4F8B\u3001\u5DE5\u4F5C\u533A\u548C\u77E5\u8BC6\u5E93\u3002",helpMappingTitle:"\u8DEF\u5F84\u6620\u5C04",helpMappingBody:"\u8DEF\u5F84\u6620\u5C04\u7528\u4E8E\u6307\u5B9A\u54EA\u4E9B Obsidian \u7B14\u8BB0\u540C\u6B65\u5230\u54EA\u4E9B Dify \u77E5\u8BC6\u5E93\u3002\u9009\u62E9\u5177\u4F53\u76EE\u5F55\u65F6\uFF0C\u4F1A\u540C\u6B65\u8BE5\u76EE\u5F55\u53CA\u5176\u5B50\u76EE\u5F55\u4E2D\u7684 Markdown \u6587\u4EF6\uFF1B\u9009\u62E9\u5355\u7BC7\u7B14\u8BB0\u65F6\uFF0C\u53EA\u540C\u6B65\u8FD9\u4E00\u7BC7\u3002\u6BCF\u6761\u6620\u5C04\u53EF\u4EE5\u5355\u72EC\u542F\u7528\u6216\u505C\u7528\u3002",helpMappingList:`\u4E00\u4E2A Obsidian \u76EE\u5F55\u6216\u7B14\u8BB0\u540C\u6B65\u5230\u4E00\u4E2A\u77E5\u8BC6\u5E93\u3002
\u4E00\u4E2A Obsidian \u76EE\u5F55\u6216\u7B14\u8BB0\u540C\u6B65\u5230\u591A\u4E2A\u77E5\u8BC6\u5E93\u3002
\u591A\u4E2A Obsidian \u8DEF\u5F84\u540C\u6B65\u5230\u540C\u4E00\u4E2A\u77E5\u8BC6\u5E93\u3002
\u9009\u62E9\u6574\u4E2A\u4ED3\u5E93\uFF0C\u540C\u6B65\u5168\u90E8 Markdown \u6587\u4EF6\u3002
\u505C\u7528\u6620\u5C04\u540E\uFF0C\u8BE5\u6620\u5C04\u4E0D\u4F1A\u53C2\u4E0E\u624B\u52A8\u540C\u6B65\u3001\u6587\u4EF6\u53D8\u66F4\u540C\u6B65\u3001\u542F\u52A8\u540E\u540C\u6B65\u6216\u5B9A\u65F6\u5168\u91CF\u6821\u9A8C\u3002`,helpSyncModesTitle:"\u540C\u6B65\u65B9\u5F0F",helpSyncModesList:`\u7ACB\u5373\u540C\u6B65\uFF1A\u624B\u52A8\u626B\u63CF\u5DF2\u542F\u7528\u6620\u5C04\u8303\u56F4\u5185\u7684 Markdown \u6587\u4EF6\u5E76\u540C\u6B65\u53D8\u66F4\u3002
\u6587\u4EF6\u53D8\u66F4\u540E\u540C\u6B65\uFF1A\u76D1\u542C\u65B0\u5EFA\u3001\u4FEE\u6539\u3001\u91CD\u547D\u540D\u4E8B\u4EF6\uFF0C\u7B49\u5F85\u9632\u6296\u65F6\u95F4\u7ED3\u675F\u540E\u540C\u6B65\u3002
\u542F\u52A8\u540E\u540C\u6B65\uFF1AObsidian \u542F\u52A8\u5E76\u5B8C\u6210\u52A0\u8F7D\u540E\u81EA\u52A8\u68C0\u67E5\u4E00\u6B21\u53D8\u66F4\u3002
\u5B9A\u65F6\u5168\u91CF\u6821\u9A8C\uFF1A\u6309\u56FA\u5B9A\u95F4\u9694\u626B\u63CF\u6240\u6709\u6620\u5C04\u8303\u56F4\u5185\u7684 Markdown \u6587\u4EF6\uFF0C\u4F5C\u4E3A\u4E8B\u4EF6\u540C\u6B65\u7684\u515C\u5E95\u3002`,helpSyncRecommendedTitle:"\u65E5\u5E38\u5EFA\u8BAE",helpSyncRecommendedList:`\u81EA\u52A8\u540C\u6B65\uFF1A\u5F00\u542F\u3002
\u542F\u52A8\u540E\u540C\u6B65\uFF1A\u5F00\u542F\u3002
\u5B9A\u65F6\u5168\u91CF\u6821\u9A8C\uFF1A\u5F00\u542F\u3002
\u540C\u6B65\u95F4\u9694\uFF1A30 \u5206\u949F\u3002
\u53D8\u66F4\u540E\u540C\u6B65\uFF1A8 \u5230 15 \u79D2\u3002
\u5E76\u53D1\u4E0A\u4F20\uFF1ANAS / Docker / \u5C0F\u578B\u81EA\u6258\u7BA1\u5EFA\u8BAE 1 \u5230 2\u3002`,helpSyncRulesTitle:"\u540C\u6B65\u89C4\u5219",helpSyncRulesBody:"\u63D2\u4EF6\u53EA\u540C\u6B65 .md \u6587\u4EF6\uFF0C\u4E0D\u4F1A\u4E0A\u4F20\u56FE\u7247\u3001PDF\u3001\u9644\u4EF6\u6216\u5176\u4ED6\u975E Markdown \u6587\u4EF6\u3002\u672C\u5730\u5220\u9664\u7B14\u8BB0\u65F6\uFF0C\u63D2\u4EF6\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664 Dify \u8FDC\u7AEF\u6587\u6863\u3002\u5220\u9664\u8DEF\u5F84\u6620\u5C04\u4E5F\u53EA\u4F1A\u5220\u9664\u672C\u5730\u914D\u7F6E\uFF0C\u4E0D\u4F1A\u5220\u9664 Obsidian \u6587\u4EF6\u6216 Dify \u8FDC\u7AEF\u6587\u6863\u3002",helpSyncRulesList:`\u6839\u636E\u8DEF\u5F84\u6620\u5C04\u627E\u5230\u76EE\u6807\u77E5\u8BC6\u5E93\u3002
\u5BF9\u6587\u4EF6\u5185\u5BB9\u8BA1\u7B97\u54C8\u5E0C\u3002
\u5185\u5BB9\u672A\u53D8\u5316\u65F6\u8DF3\u8FC7\u3002
\u4F18\u5148\u66F4\u65B0\u5DF2\u6709 Dify \u6587\u6863\u3002
\u627E\u4E0D\u5230\u5DF2\u6709\u6587\u6863\u65F6\u521B\u5EFA\u65B0\u6587\u6863\u3002
\u4F7F\u7528 Obsidian \u6587\u4EF6\u8DEF\u5F84\u4F5C\u4E3A Dify \u6587\u6863\u540D\uFF0C\u907F\u514D\u540C\u540D\u6587\u4EF6\u4E92\u76F8\u8986\u76D6\u3002`,helpTroubleshootingTitle:"\u8FDE\u63A5\u5931\u8D25\u6392\u67E5",helpTroubleshootingList:`\u786E\u8BA4 API Key \u5DF2\u586B\u5199\u5B8C\u6574\uFF0C\u6CA1\u6709\u591A\u4F59\u7A7A\u683C\u6216\u6362\u884C\u3002
\u786E\u8BA4 Dify \u670D\u52A1\u5730\u5740\u662F\u8FD0\u884C Obsidian \u7684\u5F53\u524D\u8BBE\u5907\u53EF\u4EE5\u8BBF\u95EE\u7684\u5730\u5740\u3002
\u5728\u6D4F\u89C8\u5668\u8BBF\u95EE \u4F60\u7684\u5730\u5740 + /v1/datasets\u3002
\u5982\u679C\u8FD4\u56DE JSON\uFF0C\u8BF4\u660E\u5730\u5740\u5927\u6982\u7387\u6B63\u786E\u3002
\u5982\u679C\u8FD4\u56DE HTML\uFF0C\u901A\u5E38\u8BF4\u660E\u5730\u5740\u6216\u7AEF\u53E3\u6307\u5411\u4E86\u7F51\u9875\u670D\u52A1\u3002
\u5982\u679C\u8FD4\u56DE 404\uFF0C\u68C0\u67E5 Dify \u670D\u52A1\u5730\u5740\u3001\u7AEF\u53E3\u6216\u53CD\u5411\u4EE3\u7406\u662F\u5426\u8F6C\u53D1 /v1\u3002
\u5982\u679C\u8FD4\u56DE 401\uFF0C\u8BF4\u660E\u53EF\u80FD\u5DF2\u8BBF\u95EE\u5230 Dify API\uFF0C\u4F46\u63D2\u4EF6\u91CC\u4ECD\u9700\u8981\u6B63\u786E API Key\u3002
\u5982\u679C\u8FD4\u56DE 403\uFF0C\u68C0\u67E5 Key \u6743\u9650\u548C\u5DE5\u4F5C\u533A\u3002
\u5982\u679C\u6253\u4E0D\u5F00\uFF0C\u68C0\u67E5 IP\u3001\u57DF\u540D\u3001\u7AEF\u53E3\u3001\u9632\u706B\u5899\u3001Docker \u6620\u5C04\u3001Tailscale \u548C\u53CD\u5411\u4EE3\u7406\u3002`,helpCommonErrorsTitle:"\u5E38\u89C1\u9519\u8BEF\u63D0\u793A",helpCommonErrorsList:`\u8BF7\u5148\u586B\u5199 Dify API Key \u548C Dify \u670D\u52A1\u5730\u5740\uFF1A\u8FDE\u63A5\u4FE1\u606F\u4E0D\u5B8C\u6574\u3002\u8BF7\u586B\u5199 API Key \u548C Dify \u670D\u52A1\u5730\u5740\u3002
API Key \u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u5BC6\u94A5\u662F\u5426\u6B63\u786E\uFF1ADify \u8FD4\u56DE 401\u3002\u8BF7\u91CD\u65B0\u590D\u5236 API Key\uFF0C\u786E\u8BA4\u6CA1\u6709\u591A\u4F59\u7A7A\u683C\u6216\u6362\u884C\u3002
API Key \u6CA1\u6709\u77E5\u8BC6\u5E93\u8BBF\u95EE\u6743\u9650\uFF1ADify \u8FD4\u56DE 403\u3002\u8BF7\u68C0\u67E5 Key \u6240\u5C5E\u5DE5\u4F5C\u533A\u548C\u77E5\u8BC6\u5E93\u6743\u9650\u3002
\u672A\u627E\u5230 Dify \u77E5\u8BC6\u5E93 API\uFF1ADify \u8FD4\u56DE 404\u3002\u8BF7\u786E\u8BA4 Dify \u670D\u52A1\u5730\u5740\u3001\u7AEF\u53E3\u548C\u53CD\u5411\u4EE3\u7406\u8F6C\u53D1\u6B63\u786E\u3002
\u5F53\u524D\u63A5\u53E3\u8DEF\u5F84\u4E0D\u517C\u5BB9\uFF1A\u8BF7\u786E\u8BA4\u63D2\u4EF6\u5DF2\u5347\u7EA7\u5230\u6700\u65B0\u6784\u5EFA\uFF0C\u91CD\u65B0\u70B9\u51FB\u6D4B\u8BD5\u8FDE\u63A5\u540E\u518D\u540C\u6B65\uFF1B\u4ECD\u5931\u8D25\u65F6\u5F00\u542F\u8C03\u8BD5\u65E5\u5FD7\u5E76\u53CD\u9988 Dify \u7248\u672C\u548C\u9519\u8BEF\u4FE1\u606F\u3002
\u5F53\u524D\u5730\u5740\u8FD4\u56DE\u7684\u4E0D\u662F Dify \u77E5\u8BC6\u5E93 API\uFF1A\u5730\u5740\u53EF\u80FD\u6307\u5411 NAS \u7BA1\u7406\u9875\u3001Dify \u524D\u7AEF\u9875\u9762\u3001\u767B\u5F55\u9875\u6216\u5176\u4ED6\u7F51\u9875\u670D\u52A1\u3002\u8BF7\u68C0\u67E5\u7AEF\u53E3\u548C\u53CD\u5411\u4EE3\u7406\u3002
\u8BF7\u6C42\u8D85\u65F6\uFF1A\u8BF7\u786E\u8BA4\u5F53\u524D\u8BBE\u5907\u80FD\u8BBF\u95EE Dify \u670D\u52A1\u5730\u5740\uFF1B\u68C0\u67E5 Dify \u670D\u52A1\u8D1F\u8F7D\u3001\u7AEF\u53E3\u3001\u9632\u706B\u5899\u3001Tailscale \u548C\u53CD\u5411\u4EE3\u7406\uFF1B\u540C\u6B65\u5927\u91CF\u6587\u4EF6\u65F6\u5148\u5C06\u5E76\u53D1\u4E0A\u4F20\u964D\u5230 1 \u6216 2\uFF0C\u6216\u5206\u6279\u540C\u6B65\u3002
\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25\uFF1A\u8BF7\u68C0\u67E5\u5730\u5740\u3001\u7AEF\u53E3\u3001\u9632\u706B\u5899\u3001Docker \u6620\u5C04\u3001NAS \u7F51\u7EDC\u3001Tailscale \u6216\u53CD\u5411\u4EE3\u7406\u3002
Dify \u8FD4\u56DE\u8BF7\u6C42\u8FC7\u591A\uFF1A\u53EF\u80FD\u89E6\u53D1\u9650\u6D41\u3002\u8BF7\u964D\u4F4E\u5E76\u53D1\u4E0A\u4F20\u6570\uFF0C\u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u5206\u6279\u540C\u6B65\u5927\u76EE\u5F55\u3002
Dify \u670D\u52A1\u5F02\u5E38\uFF1ADify \u8FD4\u56DE 5xx\u3002\u8BF7\u68C0\u67E5 Dify \u5BB9\u5668\u3001\u670D\u52A1\u65E5\u5FD7\u6216\u53CD\u5411\u4EE3\u7406 upstream \u914D\u7F6E\u3002`,helpDatasetsTitle:"\u83B7\u53D6\u4E0D\u5230\u77E5\u8BC6\u5E93",helpDatasetsList:`API Key \u6CA1\u6709\u77E5\u8BC6\u5E93\u6743\u9650\u3002
Key \u5C5E\u4E8E\u9519\u8BEF\u7684\u5DE5\u4F5C\u533A\u3002
\u5F53\u524D Dify \u5B9E\u4F8B\u6CA1\u6709\u53EF\u8BBF\u95EE\u7684\u77E5\u8BC6\u5E93\u3002
Dify \u670D\u52A1\u5730\u5740\u4E0D\u662F\u5F53\u524D\u8BBE\u5907\u53EF\u8BBF\u95EE\u7684 Dify \u670D\u52A1\u3002
\u53CD\u5411\u4EE3\u7406\u6CA1\u6709\u6B63\u786E\u8F6C\u53D1 /v1/datasets\u3002
\u8FD4\u56DE\u7684\u662F\u7F51\u9875\u3001\u767B\u5F55\u9875\u6216\u5176\u4ED6\u975E Dify API \u54CD\u5E94\u3002
\u5EFA\u8BAE\u5148\u70B9\u51FB\u6D4B\u8BD5\u8FDE\u63A5\uFF1B\u8FDE\u63A5\u6210\u529F\u540E\u63D2\u4EF6\u4F1A\u81EA\u52A8\u83B7\u53D6\u77E5\u8BC6\u5E93\u3002`,helpFilesNotSyncingTitle:"\u6587\u4EF6\u6CA1\u6709\u540C\u6B65",helpFilesNotSyncingList:`\u6587\u4EF6\u662F\u5426\u4E3A .md\u3002
\u6587\u4EF6\u8DEF\u5F84\u662F\u5426\u547D\u4E2D\u5DF2\u542F\u7528\u7684\u8DEF\u5F84\u6620\u5C04\u3002
\u6620\u5C04\u4E2D\u662F\u5426\u9009\u62E9\u4E86\u81F3\u5C11\u4E00\u4E2A Dify \u77E5\u8BC6\u5E93\u3002
\u81EA\u52A8\u540C\u6B65\u662F\u5426\u5F00\u542F\u3002
\u5982\u679C\u4F9D\u8D56\u4E8B\u4EF6\u89E6\u53D1\uFF0C\u786E\u8BA4\u6587\u4EF6\u53D8\u66F4\u540E\u540C\u6B65\u662F\u5426\u5F00\u542F\u3002
\u5C1D\u8BD5\u70B9\u51FB\u7ACB\u5373\u540C\u6B65\uFF0C\u5224\u65AD\u662F\u4E8B\u4EF6\u89E6\u53D1\u95EE\u9898\u8FD8\u662F\u8FDE\u63A5 / \u6620\u5C04\u95EE\u9898\u3002`,helpSlowSyncTitle:"\u540C\u6B65\u5F88\u6162",helpSlowSyncList:`\u5C06\u5E76\u53D1\u4E0A\u4F20\u6570\u8C03\u4E3A 1 \u6216 2\u3002
\u907F\u514D\u4E00\u6B21\u540C\u6B65\u8FC7\u5927\u7684\u76EE\u5F55\u3002
\u5BF9\u5927\u77E5\u8BC6\u5E93\u5206\u76EE\u5F55\u3001\u5206\u6279\u540C\u6B65\u3002
\u5982\u679C\u8FDE\u63A5\u4E5F\u4E0D\u7A33\u5B9A\uFF0C\u5148\u70B9\u51FB\u6D4B\u8BD5\u8FDE\u63A5\u5E76\u6309\u8FDE\u63A5\u5931\u8D25\u6392\u67E5\u5904\u7406\u3002`,helpDuplicateDocsTitle:"\u51FA\u73B0\u91CD\u590D\u6587\u6863",helpDuplicateDocsBody:"\u53EF\u80FD\u539F\u56E0\u5305\u62EC\u65E7\u7248\u540C\u6B65\u8BB0\u5F55\u7F3A\u5931\u3001Dify \u8FDC\u7AEF\u6587\u6863\u540D\u66FE\u88AB\u624B\u52A8\u4FEE\u6539\u3001\u672C\u5730\u540C\u6B65\u8BB0\u5F55\u88AB\u91CD\u7F6E\u6216\u4E22\u5931\u3001\u8FDC\u7AEF\u6587\u6863\u66FE\u88AB\u624B\u52A8\u5220\u9664\u540E\u91CD\u65B0\u540C\u6B65\u3002",helpDuplicateDocsList:`\u5148\u5728 Dify \u63A7\u5236\u53F0\u786E\u8BA4\u91CD\u590D\u6587\u6863\u3002
\u4FDD\u7559\u9700\u8981\u7684\u6587\u6863\uFF0C\u5220\u9664\u591A\u4F59\u6587\u6863\u3002
\u56DE\u5230\u63D2\u4EF6\u8BBE\u7F6E\u9875\uFF0C\u70B9\u51FB\u91CD\u7F6E\u540C\u6B65\u8BB0\u5F55\u3002
\u518D\u6267\u884C\u4E00\u6B21\u7ACB\u5373\u540C\u6B65\uFF0C\u8BA9\u63D2\u4EF6\u91CD\u65B0\u5EFA\u7ACB\u8BB0\u5F55\u3002`,helpDebugTitle:"\u8C03\u8BD5\u65E5\u5FD7",helpDebugBody:"\u9047\u5230\u901A\u7528\u8FDE\u63A5\u5931\u8D25\u3001\u6D4F\u89C8\u5668\u8BBF\u95EE\u6B63\u5E38\u4F46\u63D2\u4EF6\u4ECD\u5931\u8D25\u3001NAS / Docker / \u53CD\u5411\u4EE3\u7406\u94FE\u8DEF\u590D\u6742\uFF0C\u6216\u9700\u8981\u53CD\u9988\u95EE\u9898\u7ED9\u5F00\u53D1\u8005\u65F6\uFF0C\u5EFA\u8BAE\u4E34\u65F6\u5F00\u542F\u8C03\u8BD5\u65E5\u5FD7\u3002\u53CD\u9988\u65E5\u5FD7\u65F6\u4E0D\u8981\u516C\u5F00 API Key\u3001\u79C1\u6709\u5730\u5740\u3001\u7B14\u8BB0\u5185\u5BB9\u6216\u5176\u4ED6\u654F\u611F\u4FE1\u606F\u3002",helpPrivacyTitle:"\u9690\u79C1\u4E0E\u5B89\u5168",helpPrivacyBody:"\u63D2\u4EF6\u53EA\u8BFB\u53D6\u5F53\u524D Obsidian \u4ED3\u5E93\u4E2D\u547D\u4E2D\u8DEF\u5F84\u6620\u5C04\u7684 Markdown \u6587\u4EF6\uFF0C\u53EA\u4F1A\u628A\u9700\u8981\u540C\u6B65\u7684 Markdown \u5185\u5BB9\u53D1\u9001\u5230\u4F60\u914D\u7F6E\u7684 Dify \u670D\u52A1\u5730\u5740\uFF0C\u4E0D\u4F1A\u628A\u7B14\u8BB0\u5185\u5BB9\u53D1\u9001\u7ED9\u63D2\u4EF6\u4F5C\u8005\uFF0C\u4E5F\u4E0D\u4F1A\u53D1\u9001\u5230\u9664\u4F60\u914D\u7F6E\u7684 Dify \u670D\u52A1\u4EE5\u5916\u7684\u7B2C\u4E09\u65B9\u670D\u52A1\u3002Dify API Key \u4FDD\u5B58\u5728 Obsidian \u63D2\u4EF6\u672C\u5730\u6570\u636E\u4E2D\uFF0C\u8BF7\u4E0D\u8981\u628A\u5305\u542B\u63D2\u4EF6\u914D\u7F6E\u7684 {configDir} \u76EE\u5F55\u63D0\u4EA4\u5230\u516C\u5F00\u4ED3\u5E93\u3002",navAria:"Obsidian \u8BBE\u7F6E\u5BFC\u822A",navAbout:"\u5173\u4E8E",navEditor:"\u7F16\u8F91\u5668",navFiles:"\u6587\u4EF6\u4E0E\u94FE\u63A5",navAppearance:"\u5916\u89C2",navHotkeys:"\u5FEB\u6377\u952E",navPlugins:"\u7B2C\u4E09\u65B9\u63D2\u4EF6",clearConnectionConfig:"\u6E05\u7A7A\u914D\u7F6E",selectPlaceholder:"\u8BF7\u9009\u62E9",showApiKey:"\u663E\u793A API Key",hideApiKey:"\u9690\u85CF API Key",healthConnection:"\u8FDE\u63A5\u72B6\u6001",healthActiveUrl:"\u5F53\u524D\u5730\u5740",healthRecentSync:"\u6700\u8FD1\u540C\u6B65",connectionUnknown:"\u5C1A\u672A\u6D4B\u8BD5",connectionMissing:"\u5F85\u914D\u7F6E",connectionConnected:"\u5DF2\u8FDE\u63A5",connectionFailedState:"\u8FDE\u63A5\u5931\u8D25",recentSyncNone:"\u5C1A\u672A\u540C\u6B65",quickStepKey:"\u586B\u5199 Key",quickStepKeyDesc:"Dify \u77E5\u8BC6\u5E93 API Key",quickStepTest:"\u6D4B\u8BD5\u8FDE\u63A5",quickStepTestDesc:"\u81EA\u52A8\u8BC6\u522B\u53EF\u7528\u5730\u5740\u5E76\u83B7\u53D6\u77E5\u8BC6\u5E93",quickStepMapping:"\u65B0\u589E\u6620\u5C04",quickStepMappingDesc:"\u9009\u62E9\u8DEF\u5F84\u4E0E\u77E5\u8BC6\u5E93",sectionBasicConnection:"\u57FA\u7840\u8FDE\u63A5",settingsReviewConnectionTitle:"\u8FDE\u63A5\u914D\u7F6E",settingsReviewMappingTitle:"\u8DEF\u5F84\u6620\u5C04",settingsReviewSyncTitle:"\u540C\u6B65\u8BBE\u7F6E",pendingMappingsTitle:"\u65B0\u589E\u7684\u6620\u5C04\u5173\u7CFB",bulkSet:"\u6279\u91CF\u8BBE\u7F6E",enableAll:"\u5168\u90E8\u542F\u7528",pauseAll:"\u5168\u90E8\u6682\u505C",chooseFolderFirst:"\u8BF7\u5148\u9009\u62E9\u76EE\u5F55\u6216\u7B14\u8BB0",pendingEmptyDesc:"\u8BF7\u5148\u9009\u62E9\u5DE6\u4FA7 Obsidian \u76EE\u5F55\u6216\u7B14\u8BB0\uFF0C\u518D\u9009\u62E9\u53F3\u4FA7 Dify \u77E5\u8BC6\u5E93\u5E76\u70B9\u51FB\u65B0\u589E\u3002",pendingAdded:"\u6620\u5C04\u5173\u7CFB\u5DF2\u52A0\u5165\u4E0B\u65B9\u5217\u8868\u3002",selectFolderPlaceholder:"\u8BF7\u9009\u62E9\u76EE\u5F55\u6216\u7B14\u8BB0",datasetsDropdownEmpty:"\u8BF7\u5148\u83B7\u53D6 Dify \u77E5\u8BC6\u5E93",folderSearch:"\u641C\u7D22\u76EE\u5F55\u6216\u7B14\u8BB0",addPendingMapping:"\u65B0\u589E",saveMapping:"\u4FDD\u5B58\u6620\u5C04",syncAfterChange:"\u53D8\u66F4\u540E\u540C\u6B65",fullScanCheck:"\u5168\u91CF\u6821\u9A8C",startupSyncShort:"\u542F\u52A8\u540E\u540C\u6B65",concurrentUpload:"\u5E76\u53D1\u4E0A\u4F20",debounceOption8:"8 \u79D2",debounceOption15:"15 \u79D2",debounceOption30:"30 \u79D2",fullScanOption30:"\u6BCF 30 \u5206\u949F",fullScanOption60:"\u6BCF 60 \u5206\u949F",fullScanOptionOff:"\u5173\u95ED",concurrencyOption2:"2 \u4E2A\u6587\u4EF6",concurrencyOption4:"4 \u4E2A\u6587\u4EF6",optionOn:"\u5F00\u542F",optionOff:"\u5173\u95ED",settingsReviewLanUrlName:"\u5C40\u57DF\u7F51\u5730\u5740",settingsReviewLanUrlPlaceholder:"\u8BF7\u8F93\u5165NAS\u5C40\u57DF\u7F51\u5730\u5740",settingsReviewPublicUrlName:"\u516C\u7F51\u5730\u5740",settingsReviewPublicUrlPlaceholder:"\u8BF7\u8F93\u5165NAS\u516C\u7F51\u5730\u5740",basicConnectionDesc:"\u9996\u6B21\u914D\u7F6E\u53EA\u4FDD\u7559\u5FC5\u8981\u9879\uFF1B\u9AD8\u7EA7\u5730\u5740\u7B56\u7565\u9ED8\u8BA4\u6536\u8D77\u3002",apiUrlName:"Dify \u670D\u52A1\u5730\u5740",apiUrlDesc:"\u586B\u5199 Obsidian \u5F53\u524D\u8BBE\u5907\u53EF\u4EE5\u76F4\u63A5\u8BBF\u95EE\u7684 Dify \u670D\u52A1\u5730\u5740\uFF1B\u53EF\u4EE5\u7701\u7565 http://\uFF0C\u4E5F\u53EF\u4EE5\u7C98\u8D34\u5E26 /v1 \u6216 /v1/datasets \u7684\u5730\u5740\u3002",connectionNoteIdle:"\u586B\u5199 API Key \u548C Dify \u670D\u52A1\u5730\u5740\u540E\uFF0C\u70B9\u51FB\u6D4B\u8BD5\u8FDE\u63A5\u3002",connectionNoteMissing:"\u8BF7\u5148\u586B\u5199 API Key \u548C Dify \u670D\u52A1\u5730\u5740\u3002",connectionNoteSuccess:"\u8FDE\u63A5\u6210\u529F\uFF1A\u83B7\u53D6\u5230 {count} \u4E2A\u77E5\u8BC6\u5E93\u3002\u5F53\u524D\u4F7F\u7528 {url}\u3002",connectionNoteFailed:"\u8FDE\u63A5\u5931\u8D25\uFF1A{message}",advancedConnectionSummary:"\u9AD8\u7EA7\u8FDE\u63A5\u9009\u9879\uFF1A\u5C40\u57DF\u7F51/\u516C\u7F51\u5907\u7528\u5730\u5740\u3001\u63A5\u53E3\u8DEF\u5F84\u517C\u5BB9\u3001\u8BF7\u6C42\u8D85\u65F6\u3001\u5931\u8D25\u91CD\u8BD5",expand:"\u5C55\u5F00",collapse:"\u6536\u8D77",advancedSync:"\u8C03\u6574\u9AD8\u7EA7\u53C2\u6570",syncCadenceName:"\u540C\u6B65\u8282\u594F",syncCadenceDesc:"\u53D8\u66F4\u540E {debounce} \u79D2\u540C\u6B65\uFF1B\u6BCF {interval} \u5206\u949F\u505A\u4E00\u6B21\u5168\u91CF\u6821\u9A8C\u3002",syncCadenceEventOnly:"\u53D8\u66F4\u540E {debounce} \u79D2\u540C\u6B65\uFF1B\u5B9A\u65F6\u5168\u91CF\u6821\u9A8C\u5DF2\u5173\u95ED\u3002",syncCadenceIntervalOnly:"\u6587\u4EF6\u53D8\u66F4\u540C\u6B65\u5DF2\u5173\u95ED\uFF1B\u6BCF {interval} \u5206\u949F\u505A\u4E00\u6B21\u5168\u91CF\u6821\u9A8C\u3002",syncCadenceOff:"\u81EA\u52A8\u540C\u6B65\u5DF2\u5173\u95ED\uFF0C\u4ECD\u53EF\u624B\u52A8\u540C\u6B65\u3002",sectionDiagnostics:"\u540C\u6B65\u8BCA\u65AD",diagnosticsDesc:"\u628A\u957F\u72B6\u6001\u4ECE\u72B6\u6001\u680F\u79FB\u5230\u8BCA\u65AD\u5361\u7247\uFF0C\u72B6\u6001\u680F\u53EA\u4FDD\u7559\u77ED\u72B6\u6001\u3002",metricTotal:"\u6700\u8FD1\u4EFB\u52A1",metricSynced:"\u6210\u529F",metricSkipped:"\u8DF3\u8FC7",metricFailed:"\u5931\u8D25",mappingIndex:"\u5E8F\u53F7",mappingFolderColumn:"Obsidian \u8DEF\u5F84",mappingDatasetColumn:"Dify \u77E5\u8BC6\u5E93\u540D\u79F0",mappingStatusColumn:"\u72B6\u6001",mappingActionColumn:"\u64CD\u4F5C",lastError:"\u6700\u8FD1\u9519\u8BEF\uFF1A{message}",deleteMappingTitle:"\u5220\u9664\u6620\u5C04",deleteMappingDesc:"\u53EA\u4F1A\u5220\u9664\u540C\u6B65\u914D\u7F6E\uFF0C\u4E0D\u4F1A\u5220\u9664 Obsidian \u6587\u4EF6\u6216 Dify \u8FDC\u7AEF\u6587\u6863\u3002",deleteMappingConfirm:"\u5220\u9664\u6620\u5C04",mappingSaved:"\u6620\u5C04\u5DF2\u4FDD\u5B58\u3002",sectionLanguage:"\u8BED\u8A00",languageName:"\u754C\u9762\u8BED\u8A00",languageDesc:"\u5207\u6362\u63D2\u4EF6\u8BBE\u7F6E\u3001\u63D0\u793A\u548C\u72B6\u6001\u680F\u8BED\u8A00\u3002",languageChinese:"\u4E2D\u6587",languageEnglish:"English",sectionConnection:"\u8FDE\u63A5\u914D\u7F6E",apiKeyName:"Dify API Key",apiKeyDesc:"\u7528\u4E8E\u8BBF\u95EE Dify \u77E5\u8BC6\u5E93 API \u7684\u5BC6\u94A5\u3002",apiKeyPlaceholder:"\u8F93\u5165 Dify API Key",endpointModeName:"\u8FDE\u63A5\u5730\u5740\u7B56\u7565",endpointModeDesc:"\u53EF\u586B\u5199\u5C40\u57DF\u7F51\u3001\u516C\u7F51\u53CD\u5411\u4EE3\u7406\u6216\u4E91\u7AEF\u5730\u5740\uFF1B\u81EA\u52A8\u6A21\u5F0F\u4F1A\u6309\u987A\u5E8F\u5C1D\u8BD5\u53EF\u7528\u5730\u5740\u3002",endpointPrimary:"\u4E3B\u8981\u5730\u5740",endpointLan:"\u5C40\u57DF\u7F51\u5730\u5740",endpointPublic:"\u516C\u7F51\u5730\u5740",endpointAuto:"\u81EA\u52A8\u9009\u62E9",primaryUrlName:"\u4E3B\u8981 API \u5730\u5740",primaryUrlDesc:"\u53EF\u8BBF\u95EE\u7684 Dify \u670D\u52A1\u6839\u5730\u5740\uFF0C\u4F8B\u5982 http://dify-host.example.test:5000 \u6216 https://dify.example.com\u3002",lanUrlName:"\u5C40\u57DF\u7F51 API \u5730\u5740",lanUrlDesc:"\u8BBF\u95EE NAS/Docker\u3001\u672C\u673A Docker \u6216\u5C40\u57DF\u7F51\u670D\u52A1\u5668\u4E0A\u7684 Dify \u65F6\u4F7F\u7528\u3002\u5EFA\u8BAE\u586B\u5199\u5B8C\u6574\u5730\u5740\uFF0C\u4F8B\u5982 http://dify-host.example.test:5000\u3002",publicUrlName:"\u516C\u7F51 API \u5730\u5740",publicUrlDesc:"\u901A\u8FC7\u53CD\u5411\u4EE3\u7406\u3001\u57DF\u540D\u3001\u516C\u7F51\u7AEF\u53E3\u6216\u4E91\u7AEF Dify \u8BBF\u95EE\u65F6\u4F7F\u7528\u3002\u5E94\u6307\u5411 Dify \u670D\u52A1\uFF0C\u4E0D\u662F NAS/\u670D\u52A1\u5668\u7BA1\u7406\u9875\u3002",nasUrlHint:"\u90E8\u7F72\u5730\u5740\u63D0\u793A\uFF1A\u9002\u7528\u4E8E NAS/Docker\u3001\u672C\u673A Docker\u3001\u5C40\u57DF\u7F51\u670D\u52A1\u5668\u3001\u516C\u7F51\u53CD\u5411\u4EE3\u7406\u548C\u4E91\u7AEF Dify\u3002\u4E0D\u8981\u586B\u5199\u5BB9\u5668\u5185\u5730\u5740\u3001api:5001 \u6216\u8FD0\u884C Dify \u673A\u5668\u4E0A\u7684 localhost\uFF1B\u8BF7\u586B\u5199 Obsidian \u8BBE\u5907\u80FD\u76F4\u63A5\u8BBF\u95EE\u7684 Dify \u6839\u5730\u5740\u3002\u7F3A\u5C11 http:// \u65F6\u63D2\u4EF6\u4F1A\u6309 http:// \u81EA\u52A8\u5C1D\u8BD5\u3002",urlPlaceholder:"\u8BF7\u8F93\u5165 Dify \u670D\u52A1\u5730\u5740",apiPathStyleName:"Dify \u6587\u6863\u63A5\u53E3\u8DEF\u5F84",apiPathStyleDesc:"\u5EFA\u8BAE\u4FDD\u6301\u81EA\u52A8\uFF1B\u63D2\u4EF6\u4F1A\u517C\u5BB9\u65B0\u7248 create-by-text \u548C\u65E7\u7248 create_by_text\u3002",apiPathAuto:"\u81EA\u52A8\u517C\u5BB9",apiPathHyphen:"\u65B0\u7248\u8FDE\u5B57\u7B26",apiPathUnderscore:"\u65E7\u7248\u4E0B\u5212\u7EBF",timeoutName:"\u8BF7\u6C42\u8D85\u65F6",timeoutDesc:"\u5355\u4E2A Dify API \u8BF7\u6C42\u7684\u8D85\u65F6\u65F6\u95F4\uFF0C\u5355\u4F4D\u79D2\u3002",retriesName:"\u5931\u8D25\u91CD\u8BD5\u6B21\u6570",retriesDesc:"\u7F51\u7EDC\u6CE2\u52A8\u6216 5xx \u9519\u8BEF\u65F6\u7684\u91CD\u8BD5\u6B21\u6570\u3002",testConnection:"\u6D4B\u8BD5\u8FDE\u63A5",refreshDatasets:"\u5237\u65B0\u77E5\u8BC6\u5E93",connectionOk:"\u8FDE\u63A5\u6210\u529F\uFF0C\u5DF2\u83B7\u53D6 {count} \u4E2A\u77E5\u8BC6\u5E93\u3002\u5F53\u524D\u4F7F\u7528\u5730\u5740\uFF1A{url}",connectionFailed:"\u8FDE\u63A5\u5931\u8D25\uFF1A{message}",connectionErrorMissingConfig:"\u8BF7\u5148\u586B\u5199 Dify API Key \u548C Dify \u670D\u52A1\u5730\u5740\u3002",connectionErrorAuthFailed:"API Key \u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u5BC6\u94A5\u662F\u5426\u6B63\u786E\u3002",connectionErrorPermissionDenied:"API Key \u6CA1\u6709\u77E5\u8BC6\u5E93\u8BBF\u95EE\u6743\u9650\uFF0C\u8BF7\u68C0\u67E5 Dify \u6743\u9650\u914D\u7F6E\u3002",connectionErrorNotFound:"\u672A\u627E\u5230 Dify \u77E5\u8BC6\u5E93 API\uFF0C\u8BF7\u786E\u8BA4 Dify \u670D\u52A1\u5730\u5740\u3001\u7AEF\u53E3\u548C\u53CD\u5411\u4EE3\u7406\u8F6C\u53D1\u6B63\u786E\u3002",connectionErrorPathMismatch:"\u5F53\u524D\u63A5\u53E3\u8DEF\u5F84\u4E0D\u517C\u5BB9\uFF0C\u8BF7\u786E\u8BA4\u63D2\u4EF6\u5DF2\u5347\u7EA7\u5230\u6700\u65B0\u6784\u5EFA\uFF0C\u91CD\u65B0\u70B9\u51FB\u6D4B\u8BD5\u8FDE\u63A5\u540E\u518D\u540C\u6B65\u3002",connectionErrorRateLimited:"Dify \u8FD4\u56DE\u8BF7\u6C42\u8FC7\u591A\uFF0C\u8BF7\u964D\u4F4E\u5E76\u53D1\u4E0A\u4F20\u6570\u6216\u7A0D\u540E\u91CD\u8BD5\u3002",connectionErrorServer:"Dify \u670D\u52A1\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5 Dify \u5BB9\u5668\u3001\u670D\u52A1\u65E5\u5FD7\u6216\u53CD\u5411\u4EE3\u7406\u3002",connectionErrorTimeout:"\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u786E\u8BA4\u5F53\u524D\u8BBE\u5907\u80FD\u8BBF\u95EE Dify \u670D\u52A1\u5730\u5740\uFF0C\u5E76\u68C0\u67E5 Dify \u670D\u52A1\u8D1F\u8F7D\u3001\u7AEF\u53E3\u3001\u9632\u706B\u5899\u3001Tailscale \u548C\u53CD\u5411\u4EE3\u7406\u3002",connectionErrorNetwork:"\u7F51\u7EDC\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5730\u5740\u3001\u7AEF\u53E3\u3001\u9632\u706B\u5899\u3001Docker \u6620\u5C04\u6216\u53CD\u5411\u4EE3\u7406\u3002",connectionErrorUnexpectedResponse:"\u5F53\u524D\u5730\u5740\u8FD4\u56DE\u7684\u4E0D\u662F Dify \u77E5\u8BC6\u5E93 API\uFF0C\u8BF7\u68C0\u67E5\u5730\u5740\u548C\u7AEF\u53E3\u662F\u5426\u6307\u5411 Dify \u670D\u52A1\u3002",connectionErrorUnknown:"\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5 Dify \u914D\u7F6E\u540E\u91CD\u8BD5\u3002",datasetsRefreshed:"\u5DF2\u5237\u65B0 {count} \u4E2A\u77E5\u8BC6\u5E93\u3002",datasetsEmpty:"\u8FDE\u63A5\u6210\u529F\uFF0C\u4F46\u5F53\u524D Key \u672A\u8FD4\u56DE\u53EF\u8BBF\u95EE\u77E5\u8BC6\u5E93\u3002\u8BF7\u68C0\u67E5 Key \u6240\u5C5E\u5DE5\u4F5C\u533A\u3001\u77E5\u8BC6\u5E93\u6743\u9650\uFF0C\u6216\u786E\u8BA4 Dify \u670D\u52A1\u5730\u5740\u6307\u5411\u6B63\u786E\u7684 Dify \u5B9E\u4F8B\u3002",sectionMapping:"\u8DEF\u5F84\u4E0E\u77E5\u8BC6\u5E93\u6620\u5C04",mappingDesc:"\u4E00\u4E2A Obsidian \u76EE\u5F55\u6216\u7B14\u8BB0\u53EF\u540C\u6B65\u5230\u591A\u4E2A Dify \u77E5\u8BC6\u5E93\uFF0C\u591A\u4E2A\u8DEF\u5F84\u4E5F\u53EF\u6307\u5411\u540C\u4E00\u4E2A\u77E5\u8BC6\u5E93\u3002",addMapping:"\u65B0\u589E\u6620\u5C04",edit:"\u7F16\u8F91",delete:"\u5220\u9664",enabled:"\u542F\u7528",disabled:"\u505C\u7528",rootFolder:"\u6574\u4E2A\u4ED3\u5E93",noMappings:"\u6682\u65E0\u6620\u5C04\uFF0C\u8BF7\u65B0\u589E\u6620\u5C04\uFF0C\u5F00\u542F\u81EA\u52A8\u540C\u6B65",mappingPageInfoEmpty:"0-0 / 0",datasetMissing:"\u672A\u9009\u62E9\u77E5\u8BC6\u5E93",datasetUnknown:"\u672A\u77E5\u77E5\u8BC6\u5E93",mappingModalTitle:"\u7F16\u8F91\u8DEF\u5F84\u6620\u5C04",addMappingModalTitle:"\u65B0\u589E\u6620\u5C04",folderName:"Obsidian \u76EE\u5F55\u6216\u7B14\u8BB0",folderDesc:"\u9009\u62E9\u76EE\u5F55\u4F1A\u540C\u6B65\u5176\u4E0B\u6240\u6709 Markdown \u7B14\u8BB0\uFF1B\u9009\u62E9\u5355\u7BC7\u7B14\u8BB0\u53EA\u540C\u6B65\u8BE5\u7B14\u8BB0\u3002",selectFolder:"\u9009\u62E9\u76EE\u5F55",datasetName:"Dify \u77E5\u8BC6\u5E93",datasetDesc:"\u53EF\u591A\u9009\uFF1B\u5982\u679C\u5217\u8868\u4E3A\u7A7A\uFF0C\u8BF7\u5148\u5237\u65B0\u77E5\u8BC6\u5E93\u6216\u624B\u52A8\u8F93\u5165 ID\u3002",manualDatasetIds:"\u624B\u52A8\u8F93\u5165\u77E5\u8BC6\u5E93 ID",manualDatasetIdsDesc:"\u591A\u4E2A ID \u53EF\u7528\u9017\u53F7\u3001\u7A7A\u683C\u6216\u6362\u884C\u5206\u9694\u3002",save:"\u4FDD\u5B58",cancel:"\u53D6\u6D88",selectFolderTitle:"\u9009\u62E9 Obsidian \u76EE\u5F55\u6216\u7B14\u8BB0",choose:"\u9009\u62E9",sectionAuto:"\u81EA\u52A8\u540C\u6B65",autoSyncName:"\u542F\u7528\u81EA\u52A8\u540C\u6B65",autoSyncDesc:"\u603B\u5F00\u5173\uFF1B\u5173\u95ED\u540E\u4E8B\u4EF6\u89E6\u53D1\u548C\u5B9A\u65F6\u5168\u91CF\u540C\u6B65\u90FD\u4F1A\u6682\u505C\u3002",eventSyncName:"\u6587\u4EF6\u53D8\u66F4\u540E\u81EA\u52A8\u540C\u6B65",eventSyncDesc:"\u76D1\u542C Obsidian \u7684\u521B\u5EFA\u3001\u4FEE\u6539\u3001\u91CD\u547D\u540D\u4E8B\u4EF6\uFF0C\u9632\u6296\u540E\u81EA\u52A8\u4E0A\u4F20\u3002",startupSyncName:"\u542F\u52A8\u540E\u540C\u6B65",startupSyncDesc:"Obsidian \u542F\u52A8\u5E76\u5B8C\u6210\u52A0\u8F7D\u540E\u81EA\u52A8\u68C0\u67E5\u53D8\u66F4\u3002",periodicSyncName:"\u5B9A\u65F6\u5168\u91CF\u6821\u9A8C",periodicSyncDesc:"\u4F5C\u4E3A\u4E8B\u4EF6\u540C\u6B65\u7684\u515C\u5E95\uFF0C\u9002\u5408 NAS/Docker\u3001\u672C\u673A Docker\u3001\u5C40\u57DF\u7F51\u670D\u52A1\u5668\u3001\u4E91\u7AEF Dify \u6216\u8DE8\u8BBE\u5907\u573A\u666F\u3002",syncIntervalName:"\u540C\u6B65\u95F4\u9694",syncIntervalDesc:"\u5B9A\u65F6\u5168\u91CF\u6821\u9A8C\u7684\u95F4\u9694\uFF0C\u5355\u4F4D\u5206\u949F\u3002",debounceName:"\u53D8\u66F4\u9632\u6296",debounceDesc:"\u7F16\u8F91\u505C\u6B62\u540E\u7B49\u5F85\u591A\u5C11\u79D2\u518D\u540C\u6B65\uFF0C\u907F\u514D\u9891\u7E41\u4E0A\u4F20\u534A\u6210\u54C1\u3002",concurrencyName:"\u5E76\u53D1\u4E0A\u4F20\u6570",concurrencyDesc:"\u5EFA\u8BAE NAS/Docker\u3001\u672C\u673A Docker \u6216\u5C0F\u578B\u81EA\u6258\u7BA1\u573A\u666F\u4FDD\u6301 1-2\uFF0C\u907F\u514D Dify \u7D22\u5F15\u538B\u529B\u8FC7\u5927\uFF1B\u4E91\u7AEF Dify \u8BF7\u7ED3\u5408\u9650\u6D41\u60C5\u51B5\u8C03\u6574\u3002",pollIndexName:"\u68C0\u67E5\u7D22\u5F15\u72B6\u6001",pollIndexDesc:"\u4E0A\u4F20\u540E\u77ED\u6682\u67E5\u8BE2 Dify \u7D22\u5F15\u72B6\u6001\uFF1B\u5F00\u542F\u4F1A\u7A0D\u6162\u4F46\u53CD\u9988\u66F4\u51C6\u786E\u3002",sectionActions:"\u64CD\u4F5C\u4E0E\u8BCA\u65AD",manualSync:"\u7ACB\u5373\u540C\u6B65",manualSyncDesc:"\u7ACB\u523B\u626B\u63CF\u6620\u5C04\u8303\u56F4\u5185\u7684 Markdown \u6587\u4EF6\u5E76\u540C\u6B65\u53D8\u66F4\u3002",debugName:"\u8C03\u8BD5\u65E5\u5FD7",debugDesc:"\u5728\u5F00\u53D1\u8005\u63A7\u5236\u53F0\u8F93\u51FA\u8BE6\u7EC6\u540C\u6B65\u65E5\u5FD7\u3002",lastSync:"\u4E0A\u6B21\u540C\u6B65\uFF1A{time}",noLastSync:"\u5C1A\u672A\u5B8C\u6210\u540C\u6B65\u3002",lastSyncInitial:"\u4E0A\u6B21\u540C\u6B65\u65F6\u95F4\uFF1A--/\u2014/\u2014",activeEndpoint:"\u5F53\u524D\u4F7F\u7528\u5730\u5740\uFF1A{url}",noActiveEndpoint:"\u5F53\u524D\u4F7F\u7528\u5730\u5740\uFF1A\u5C1A\u672A\u8FDE\u63A5\u6210\u529F\u3002",recentSyncInitial:"\u6700\u8FD1\u540C\u6B65\uFF1A0 \u4EFB\u52A1\uFF0C\u8017\u65F6 0ms",recentSyncSummary:"\u6700\u8FD1\u540C\u6B65\uFF1A{source}\uFF0C\u5171 {total} \u4E2A\u4EFB\u52A1\uFF0C\u6210\u529F {synced}\uFF0C\u8DF3\u8FC7 {skipped}\uFF0C\u5931\u8D25 {failed}\uFF0C\u8017\u65F6 {elapsed}",recentSyncAddress:"\u6700\u8FD1\u540C\u6B65\u5730\u5740\uFF1A{url}",recentSyncError:"\u6700\u8FD1\u540C\u6B65\u9519\u8BEF\uFF1A{message}",recentSyncFailures:"\u6700\u8FD1\u5931\u8D25\u6587\u4EF6\uFF1A{items}",noRecentSync:"\u6682\u65E0\u6700\u8FD1\u540C\u6B65\u8BE6\u60C5\u3002",recordsCount:"\u5DF2\u8BB0\u5F55 {count} \u6761\u6587\u4EF6-\u77E5\u8BC6\u5E93\u540C\u6B65\u72B6\u6001\u3002",resetRecords:"\u91CD\u7F6E\u540C\u6B65\u8BB0\u5F55",resetRecordsDesc:"\u4E0D\u5220\u9664 Dify \u8FDC\u7AEF\u6587\u6863\uFF1B\u4E0B\u6B21\u540C\u6B65\u4F1A\u91CD\u65B0\u5BF9\u7167\u8FDC\u7AEF\u6587\u6863\u3002",resetRecordsDone:"\u540C\u6B65\u8BB0\u5F55\u5DF2\u91CD\u7F6E\u3002",hashMigrated:"\u5DF2\u8FC1\u79FB\u65E7\u7248\u540C\u6B65\u8BB0\u5F55\u3002",localDeleted:"\u5DF2\u8BB0\u5F55\u672C\u5730\u5220\u9664\uFF1A{path}",progress:"{current}/{total} \u6B63\u5728\u5904\u7406 {name}",folderPickerEmpty:"\u5F53\u524D\u4ED3\u5E93\u6CA1\u6709\u53EF\u6620\u5C04\u7684\u76EE\u5F55\u6216 Markdown \u7B14\u8BB0\u3002"},en:{pluginName:"Vault2Dify",ribbon:"Sync to Dify",commandManual:"Vault2Dify: Sync to Dify Knowledge Base",commandToggleAuto:"Toggle auto sync",ready:"Ready",syncing:"Syncing...",syncQueued:"A sync is already running. These changes were queued.",syncNotice:"Syncing to Dify knowledge bases...",syncComplete:"Sync complete: {synced} synced, {skipped} skipped, {failed} failed",syncNoChanges:"No changes to sync.",syncFailed:"Sync failed: {message}",syncFailedShort:"Failed",validationApiKey:"Configure your Dify API key first.",validationApiUrl:"Configure your Dify service URL first.",validationMapping:"Configure at least one path to knowledge base mapping.",autoOn:"Auto sync enabled",autoOff:"Auto sync disabled",settingsTitle:"Vault2Dify",settingsSubtitle:"Sync your Obsidian Vault to Dify Knowledge Base",settingsHelp:"Sync your Obsidian Vault to Dify Knowledge Base.",openGithub:"Open GitHub project",openHelp:"Open help",helpModalTitle:"Vault2Dify Help",helpQuickStartTitle:"Quick start",helpQuickStartBody:"Vault2Dify syncs your Obsidian Vault to your configured Dify Knowledge Base.",helpQuickStartList:`Enter your Dify API key.
Enter your Dify service URL.
Click Test connection to automatically load knowledge bases.
Add a path mapping.
Run Sync now when needed, or keep auto sync enabled.`,helpApiUrlTitle:"How to fill connection settings",helpApiUrlBody:`Dify API Key: required. It authorizes access to your Dify knowledge base. Copy it from the Dify knowledge base API settings. Example: dataset-vtpB1fgqv************
Dify service URL: required. This is the main address the plugin uses to connect to Dify. It works for Dify on a cloud server, NAS, local Docker, or another reachable host. Examples: http://dify-host.example.test:5000 or https://dify.example.com
If your Dify knowledge base runs on NAS and you want access from home, work, or outside networks, install and configure Tailscale on both the NAS and your laptop. Then enter: http://tailnet-device.example.test:Dify mapped port. Example: http://tailnet-device.example.test:5000`,helpApiKeyTitle:"API key requirements",helpApiKeyBody:"Use a Dify knowledge base API key with permission to access knowledge bases, list knowledge bases, create documents, update documents, and list documents. If the connection test reports insufficient permissions, check that the key belongs to the correct Dify instance, workspace, and knowledge base.",helpMappingTitle:"Path mappings",helpMappingBody:"Path mappings decide which Obsidian notes sync to which Dify knowledge bases. A folder syncs Markdown files in that folder and its subfolders; a note syncs only that note. Each mapping can be enabled or paused independently.",helpMappingList:`Sync one Obsidian folder or note to one knowledge base.
Sync one Obsidian folder or note to multiple knowledge bases.
Sync multiple Obsidian paths to the same knowledge base.
Choose the entire vault to sync all Markdown files.
Paused mappings do not participate in manual sync, file-change sync, startup sync, or periodic full checks.`,helpSyncModesTitle:"Sync modes",helpSyncModesList:`Sync now: manually scans mapped Markdown files and syncs changes.
Sync after file changes: listens for create, modify, and rename events, then syncs after the debounce period.
Sync after startup: checks changes once after Obsidian finishes loading.
Periodic full check: scans all mapped Markdown files at a fixed interval as a fallback for event sync.`,helpSyncRecommendedTitle:"Daily recommendations",helpSyncRecommendedList:`Auto sync: on.
Startup sync: on.
Periodic full check: on.
Sync interval: 30 minutes.
Sync after changes: 8 to 15 seconds.
Concurrent uploads: 1 to 2 for NAS / Docker / smaller self-hosted deployments.`,helpSyncRulesTitle:"Sync rules",helpSyncRulesBody:"The plugin only syncs .md files. It does not upload images, PDFs, attachments, or other non-Markdown files. Deleting a local note does not automatically delete the remote Dify document. Deleting a path mapping only removes local configuration and does not delete Obsidian files or remote Dify documents.",helpSyncRulesList:`Find target knowledge bases from path mappings.
Hash file content.
Skip unchanged content.
Prefer updating existing Dify documents.
Create a document when no existing match is found.
Use the Obsidian file path as the Dify document name to avoid same-name collisions.`,helpTroubleshootingTitle:"Connection troubleshooting",helpTroubleshootingList:`Confirm the API key is complete and has no extra spaces or newlines.
Confirm the Dify service URL is reachable from the device running Obsidian.
Open your URL + /v1/datasets in a browser.
JSON usually means the address is probably correct.
HTML usually means the address or port points to a web service.
404 usually means the Dify service URL, port, or reverse proxy /v1 forwarding is wrong.
401 can mean the request reached Dify API, but the plugin still needs a valid API key.
403 means you should check key permissions and workspace.
If it cannot open, check IP, domain, port, firewall, Docker mapping, Tailscale, and reverse proxy.`,helpCommonErrorsTitle:"Common error messages",helpCommonErrorsList:`Enter a Dify API key and service URL first: connection settings are incomplete.
The API key is invalid: Dify returned 401. Copy the key again and remove extra spaces or newlines.
The API key does not have knowledge base access: Dify returned 403. Check the key workspace and knowledge base permissions.
The Dify knowledge base API was not found: Dify returned 404. Check the Dify service URL, port, and reverse proxy forwarding.
The current API path is incompatible: confirm the plugin is on the latest build, retry Test connection, then sync; if it persists, enable debug logs and report the Dify version plus error details.
The current address did not return the Dify knowledge base API: it may point to a NAS admin page, Dify web page, login page, or another web service. Check the port and reverse proxy.
The request timed out: confirm this device can reach the Dify service URL; check Dify service load, ports, firewall, Tailscale, and reverse proxy; for large syncs, lower concurrent uploads to 1 or 2, or sync in batches.
Network connection failed: check the URL, port, firewall, Docker mapping, NAS network, Tailscale, or reverse proxy.
Dify returned too many requests: lower upload concurrency, try later, or sync large folders in batches.
Dify returned a server error: check the Dify container, service logs, or reverse proxy upstream.`,helpDatasetsTitle:"Knowledge bases do not appear",helpDatasetsList:`The API key lacks knowledge base permissions.
The key belongs to the wrong workspace.
The current Dify instance has no accessible knowledge bases.
The Dify service URL is not a Dify service reachable from this device.
The reverse proxy does not forward /v1/datasets correctly.
The response is a web page, login page, or other non-Dify API response.
Test the connection first, then get knowledge bases.`,helpFilesNotSyncingTitle:"Files do not sync",helpFilesNotSyncingList:`Confirm the file is .md.
Confirm the file path matches an enabled path mapping.
Confirm the mapping has at least one Dify knowledge base selected.
Confirm auto sync is enabled.
If relying on events, confirm sync after file changes is enabled.
Try Sync now to separate event-trigger issues from connection or mapping issues.`,helpSlowSyncTitle:"Sync is slow",helpSlowSyncList:`Set concurrent uploads to 1 or 2.
Avoid syncing very large folders all at once.
Split large knowledge bases by folder and sync in batches.
If the connection is also unstable, run Test connection and follow connection troubleshooting first.`,helpDuplicateDocsTitle:"Duplicate documents appear",helpDuplicateDocsBody:"Possible causes include missing legacy sync records, manually changed Dify document names, reset or lost local sync records, or remote documents that were manually deleted and then synced again.",helpDuplicateDocsList:`Confirm duplicate documents in the Dify console.
Keep the documents you need and delete extras.
Return to plugin settings and click Reset sync records.
Run Sync now again so the plugin rebuilds records.`,helpDebugTitle:"Debug logs",helpDebugBody:"Temporarily enable debug logs when the error stays generic, browser access works but the plugin still fails, NAS / Docker / reverse proxy routing is complex, or you need to report an issue. Do not share API keys, private addresses, note content, or other sensitive information in logs.",helpPrivacyTitle:"Privacy and safety",helpPrivacyBody:"The plugin only reads Markdown files in the current Obsidian vault that match enabled path mappings. It only sends required Markdown content to your configured Dify service URL. It does not send note content to the plugin author or any third-party service other than your configured Dify service. The Dify API key is stored in Obsidian plugin local data; do not commit a {configDir} directory containing plugin settings to a public repository.",navAria:"Obsidian settings navigation",navAbout:"About",navEditor:"Editor",navFiles:"Files and links",navAppearance:"Appearance",navHotkeys:"Hotkeys",navPlugins:"Third-party plugins",clearConnectionConfig:"Clear config",selectPlaceholder:"Please select",showApiKey:"Show API key",hideApiKey:"Hide API key",healthConnection:"Connection",healthActiveUrl:"Active URL",healthRecentSync:"Recent sync",connectionUnknown:"Not tested",connectionMissing:"Needs setup",connectionConnected:"Connected",connectionFailedState:"Failed",recentSyncNone:"No sync yet",quickStepKey:"Enter key",quickStepKeyDesc:"Dify knowledge API key",quickStepTest:"Test connection",quickStepTestDesc:"Find an endpoint and load bases",quickStepMapping:"Add mapping",quickStepMappingDesc:"Choose folder and bases",sectionBasicConnection:"Basic connection",settingsReviewConnectionTitle:"Connection",settingsReviewMappingTitle:"Directory mapping",settingsReviewSyncTitle:"Sync settings",pendingMappingsTitle:"New mappings",bulkSet:"Bulk set",enableAll:"Enable all",pauseAll:"Pause all",chooseFolderFirst:"Select a folder or note first",pendingEmptyDesc:"Select an Obsidian folder or note on the left, then choose Dify knowledge bases on the right and click Add.",pendingAdded:"Mapping added to the list below.",selectFolderPlaceholder:"Select a folder or note",datasetsDropdownEmpty:"Load Dify knowledge bases first",folderSearch:"Search folders or notes",addPendingMapping:"Add",saveMapping:"Save mapping",syncAfterChange:"After changes",fullScanCheck:"Full check",startupSyncShort:"Startup sync",concurrentUpload:"Concurrent uploads",debounceOption8:"8 seconds",debounceOption15:"15 seconds",debounceOption30:"30 seconds",fullScanOption30:"Every 30 minutes",fullScanOption60:"Every 60 minutes",fullScanOptionOff:"Off",concurrencyOption2:"2 files",concurrencyOption4:"4 files",optionOn:"On",optionOff:"Off",settingsReviewLanUrlName:"NAS LAN address",settingsReviewLanUrlPlaceholder:"Enter NAS LAN address",settingsReviewPublicUrlName:"NAS public address",settingsReviewPublicUrlPlaceholder:"Enter NAS public address",basicConnectionDesc:"First-time setup keeps only the essentials; advanced endpoint options are collapsed.",apiUrlName:"Dify service URL",apiUrlDesc:"Use the Dify service URL reachable from this Obsidian device. You may omit http:// or paste a URL ending in /v1 or /v1/datasets.",connectionNoteIdle:"Enter an API key and Dify service URL, then test the connection.",connectionNoteMissing:"Enter an API key and Dify service URL first.",connectionNoteSuccess:"Connected: {count} knowledge bases via {url}.",connectionNoteFailed:"Connection failed: {message}",advancedConnectionSummary:"Advanced connection: LAN/public fallback URLs, API path compatibility, timeout, retries",expand:"Expand",collapse:"Collapse",advancedSync:"Tune advanced options",syncCadenceName:"Sync cadence",syncCadenceDesc:"Sync {debounce}s after changes; run a full check every {interval} minutes.",syncCadenceEventOnly:"Sync {debounce}s after changes; periodic full checks are off.",syncCadenceIntervalOnly:"File change sync is off; run a full check every {interval} minutes.",syncCadenceOff:"Auto sync is off. Manual sync still works.",sectionDiagnostics:"Sync diagnostics",diagnosticsDesc:"Long status lives in diagnostics. The status bar stays short.",metricTotal:"Recent tasks",metricSynced:"Synced",metricSkipped:"Skipped",metricFailed:"Failed",mappingIndex:"#",mappingFolderColumn:"Obsidian path",mappingDatasetColumn:"Dify knowledge bases",mappingStatusColumn:"Status",mappingActionColumn:"Actions",lastError:"Recent error: {message}",deleteMappingTitle:"Delete mapping",deleteMappingDesc:"This only deletes the sync configuration. It will not delete Obsidian files or remote Dify documents.",deleteMappingConfirm:"Delete mapping",mappingSaved:"Mapping saved.",sectionLanguage:"Language",languageName:"Interface language",languageDesc:"Switch settings, notices, and status bar language.",languageChinese:"\u4E2D\u6587",languageEnglish:"English",sectionConnection:"Connection",apiKeyName:"Dify API Key",apiKeyDesc:"API key used to access Dify knowledge base APIs.",apiKeyPlaceholder:"Enter your Dify API key",endpointModeName:"Endpoint strategy",endpointModeDesc:"Fill LAN, public reverse proxy, or cloud URLs when needed. Auto mode tries available URLs in order.",endpointPrimary:"Primary URL",endpointLan:"LAN URL",endpointPublic:"Public URL",endpointAuto:"Auto",primaryUrlName:"Primary API URL",primaryUrlDesc:"Reachable Dify service root URL, for example http://dify-host.example.test:5000 or https://dify.example.com.",lanUrlName:"LAN API URL",lanUrlDesc:"Use this for Dify on NAS/Docker, local Docker, or a LAN server. Prefer a full URL such as http://dify-host.example.test:5000.",publicUrlName:"Public API URL",publicUrlDesc:"Use this for reverse proxy, domain, public port, or Dify Cloud access. It must point to Dify, not a NAS/server admin page.",nasUrlHint:"Deployment URL tip: supports NAS/Docker, local Docker, LAN servers, public reverse proxies, and Dify Cloud. Do not use container-only addresses, api:5001, or localhost on the machine running Dify. Use the Dify root URL reachable from this Obsidian device. If http:// is missing, the plugin will try http:// automatically.",urlPlaceholder:"Enter your Dify service URL",apiPathStyleName:"Dify document API path",apiPathStyleDesc:"Auto is recommended. The plugin supports new create-by-text and legacy create_by_text paths.",apiPathAuto:"Auto compatible",apiPathHyphen:"New hyphen path",apiPathUnderscore:"Legacy underscore path",timeoutName:"Request timeout",timeoutDesc:"Timeout for one Dify API request, in seconds.",retriesName:"Retry count",retriesDesc:"Retries for network failures or 5xx responses.",testConnection:"Test connection",refreshDatasets:"Refresh knowledge bases",connectionOk:"Connected and loaded {count} knowledge bases via {url}",connectionFailed:"Connection failed: {message}",connectionErrorMissingConfig:"Enter a Dify API key and service URL first.",connectionErrorAuthFailed:"The API key is invalid. Check that it is correct.",connectionErrorPermissionDenied:"The API key does not have knowledge base access. Check Dify permissions.",connectionErrorNotFound:"The Dify knowledge base API was not found. Check the Dify service URL, port, and reverse proxy forwarding.",connectionErrorPathMismatch:"The API path is incompatible. Confirm the plugin is on the latest build, retry Test connection, then sync.",connectionErrorRateLimited:"Dify returned too many requests. Lower upload concurrency or try again later.",connectionErrorServer:"Dify returned a server error. Check the Dify container, service logs, or reverse proxy.",connectionErrorTimeout:"The request timed out. Confirm this device can reach the Dify service URL, and check Dify service load, ports, firewall, Tailscale, and reverse proxy.",connectionErrorNetwork:"Network connection failed. Check the URL, port, firewall, Docker mapping, or reverse proxy.",connectionErrorUnexpectedResponse:"The current address did not return the Dify knowledge base API. Check that the URL and port point to Dify.",connectionErrorUnknown:"Connection failed. Check the Dify settings and try again.",datasetsRefreshed:"Refreshed {count} knowledge bases.",datasetsEmpty:"Connected, but this key returned no accessible knowledge bases. Check the key workspace, knowledge base permissions, or whether the Dify service URL points to the correct Dify instance.",sectionMapping:"Path mappings",mappingDesc:"One Obsidian folder or note can sync to multiple Dify knowledge bases, and many paths can share one knowledge base.",addMapping:"Add mapping",edit:"Edit",delete:"Delete",enabled:"Enabled",disabled:"Disabled",rootFolder:"Entire vault",noMappings:"No mappings yet. Add a mapping to enable automatic sync.",mappingPageInfoEmpty:"0-0 / 0",datasetMissing:"No knowledge base selected",datasetUnknown:"Unknown knowledge base",mappingModalTitle:"Edit path mapping",addMappingModalTitle:"Add mapping",folderName:"Obsidian folder or note",folderDesc:"Choose a folder to sync all Markdown notes under it, or choose one note to sync only that note.",selectFolder:"Select folder",datasetName:"Dify knowledge bases",datasetDesc:"Multiple selections are supported. If the list is empty, refresh knowledge bases or enter IDs manually.",manualDatasetIds:"Manual knowledge base IDs",manualDatasetIdsDesc:"Separate multiple IDs with commas, spaces, or new lines.",save:"Save",cancel:"Cancel",selectFolderTitle:"Select Obsidian folder or note",choose:"Choose",sectionAuto:"Auto sync",autoSyncName:"Enable auto sync",autoSyncDesc:"Master switch. Event sync and periodic full scans pause when disabled.",eventSyncName:"Sync after file changes",eventSyncDesc:"Listen to Obsidian create, modify, and rename events, then upload after debounce.",startupSyncName:"Sync after startup",startupSyncDesc:"Check changes after Obsidian finishes loading.",periodicSyncName:"Periodic full scan",periodicSyncDesc:"Fallback for event sync, useful with NAS/Docker, local Docker, LAN servers, Dify Cloud, or multi-device workflows.",syncIntervalName:"Sync interval",syncIntervalDesc:"Periodic full scan interval, in minutes.",debounceName:"Change debounce",debounceDesc:"Wait this many seconds after edits stop before syncing.",concurrencyName:"Concurrent uploads",concurrencyDesc:"Keep this at 1-2 for NAS/Docker, local Docker, or smaller self-hosted deployments to avoid overloading Dify indexing. Adjust for Dify Cloud rate limits.",pollIndexName:"Check indexing status",pollIndexDesc:"Briefly query Dify indexing status after upload. This is slower but more informative.",sectionActions:"Actions & diagnostics",manualSync:"Sync now",manualSyncDesc:"Scan mapped Markdown files and sync changes immediately.",debugName:"Debug logs",debugDesc:"Print detailed sync logs in the developer console.",lastSync:"Last sync: {time}",noLastSync:"No completed sync yet.",lastSyncInitial:"Last sync time: --/--/--",activeEndpoint:"Active endpoint: {url}",noActiveEndpoint:"Active endpoint: no successful connection yet.",recentSyncInitial:"Recent sync: 0 tasks, elapsed 0ms",recentSyncSummary:"Recent sync: {source}, {total} tasks, {synced} synced, {skipped} skipped, {failed} failed, elapsed {elapsed}",recentSyncAddress:"Recent sync endpoint: {url}",recentSyncError:"Recent sync error: {message}",recentSyncFailures:"Recent failed files: {items}",noRecentSync:"No recent sync details yet.",recordsCount:"{count} file-to-knowledge-base sync records stored.",resetRecords:"Reset sync records",resetRecordsDesc:"Remote Dify documents are not deleted. The next sync will compare remote documents again.",resetRecordsDone:"Sync records reset.",hashMigrated:"Legacy sync records migrated.",localDeleted:"Local deletion recorded: {path}",progress:"{current}/{total} processing {name}",folderPickerEmpty:"There are no mappable folders or Markdown notes in this vault."}},I=class extends p.Plugin{constructor(){super(...arguments);this.syncRecords=new Map;this.legacyHashFileName="historyContentHash";this.syncProgressNotice=null;this.queueTimer=null;this.startupSyncTimer=null;this.periodicIntervalId=null;this.pendingPaths=new Set;this.isSyncing=!1}async onload(){await this.loadPluginData(),this.client=new M(this),this.client.setActiveBaseUrl(this.settings.connectionHealth.lastSuccessfulBaseUrl),this.statusBarItem=this.addStatusBarItem(),this.updateStatusBar(this.t("ready")),this.addRibbonIcon("sync",this.t("ribbon"),async()=>{await this.performSync("manual")}).addClass("dify-sync-ribbon-class"),this.addCommand({id:"dify-sync-manual",name:this.t("commandManual"),callback:async()=>{await this.performSync("manual")}}),this.addCommand({id:"dify-sync-toggle-auto",name:this.t("commandToggleAuto"),callback:async()=>{this.settings.autoSyncEnabled=!this.settings.autoSyncEnabled,await this.savePluginData(),this.setupAutoSync(),new p.Notice(this.settings.autoSyncEnabled?this.t("autoOn"):this.t("autoOff"))}}),this.settingTab=new O(this.app,this),this.addSettingTab(this.settingTab),this.app.workspace.onLayoutReady(async()=>{await this.migrateLegacyHashStorage(),this.registerVaultEvents(),this.setupAutoSync(),this.settings.autoSyncEnabled&&this.settings.syncOnStartup&&(this.startupSyncTimer=window.setTimeout(()=>{this.startupSyncTimer=null,this.queueFullSync("startup")},5e3))})}onunload(){this.queueTimer!==null&&window.clearTimeout(this.queueTimer),this.startupSyncTimer!==null&&window.clearTimeout(this.startupSyncTimer),this.periodicIntervalId!==null&&window.clearInterval(this.periodicIntervalId)}t(e,t){var s;let n=(K[((s=this.settings)==null?void 0:s.language)||"zh-CN"]||K["zh-CN"])[e]||K["zh-CN"][e]||e;return t&&Object.entries(t).forEach(([o,c])=>{n=n.replace(new RegExp(`\\{${o}\\}`,"g"),String(c))}),n}debug(...e){this.settings.debugLogging&&console.log("[Dify Sync]",...e)}getConnectionFailureMessage(e="unknown"){return this.t(Ce(e))}showConnectionError(e){var n;let t=this.getConnectionFailureReason(e);(n=new p.Notice(this.t("connectionFailed",{message:this.getConnectionFailureMessage(t)}),8e3).noticeEl)==null||n.addClass("dify-sync-error-notice")}getConnectionFailureReason(e){if(!this.hasCompleteConnectionSettings())return"missing_config";let t=De(e);return t||(e instanceof m?C(e):this.settings.connectionHealth.status==="failed"&&this.settings.connectionHealth.reason?this.settings.connectionHealth.reason:"unknown")}hasCompleteConnectionSettings(){return!!this.settings.difyApiKey.trim()&&this.getConfiguredBaseUrls().length>0}async loadPluginData(){let e=await this.loadData(),t=f(e)?e:{},i=f(t.settings)?t.settings:t;this.settings=this.normalizeSettings(i,!!e),this.syncRecords=new Map(Object.entries(we(t.syncRecords))),await this.savePluginData()}async savePluginData(){let e={};this.syncRecords.forEach((t,i)=>{e[i]=t}),await this.saveData({schemaVersion:2,settings:this.settings,syncRecords:e})}normalizeSettings(e,t=!1){let i=f(e)?e:{},n=Object.assign({},ve,i);if(n.schemaVersion=2,n.initialSetupCompleted=typeof i.initialSetupCompleted=="boolean"?i.initialSetupCompleted:t,n.language=n.language==="en"?"en":"zh-CN",n.endpointMode=["primary","lan","public","auto"].includes(n.endpointMode)?n.endpointMode:"primary",n.apiPathStyle=["auto","hyphen","underscore"].includes(n.apiPathStyle)?n.apiPathStyle:"auto",n.syncInterval=v(n.syncInterval,5,240,30),n.debounceSeconds=v(n.debounceSeconds,1,120,8),n.requestTimeoutSeconds=v(n.requestTimeoutSeconds,5,180,30),n.maxRetries=v(n.maxRetries,0,5,2),n.maxConcurrent=v(n.maxConcurrent,1,5,2),n.knowledgeBases=Array.isArray(n.knowledgeBases)?n.knowledgeBases:[],n.obsidianFolders=Array.isArray(n.obsidianFolders)?n.obsidianFolders:[],n.mappings=Array.isArray(n.mappings)?n.mappings:[],n.connectionHealth=Ae(i.connectionHealth),n.mappings.length===0&&n.difyKnowledgeId){let s=n.obsidianFolders.length>0?n.obsidianFolders:[""];n.mappings=s.map(o=>({id:L(),folder:o,datasetIds:[n.difyKnowledgeId],enabled:!0}))}return n.mappings=n.mappings.map(s=>({id:s.id||L(),folder:P(s.folder||""),datasetIds:D((s.datasetIds||[]).map(o=>o.trim()).filter(Boolean)),enabled:s.enabled!==!1})),n}registerVaultEvents(){this.registerEvent(this.app.vault.on("create",e=>{this.handleVaultChange(e,"event")})),this.registerEvent(this.app.vault.on("modify",e=>{this.handleVaultChange(e,"event")})),this.registerEvent(this.app.vault.on("delete",async e=>{e instanceof p.TFile&&this.isMarkdownFile(e)&&await this.markLocalDeleted(e.path)})),this.registerEvent(this.app.vault.on("rename",async(e,t)=>{e instanceof p.TFile&&this.isMarkdownFile(e)&&(await this.migrateRenamedRecords(t,e.path),this.enqueueFile(e.path,"event"))}))}setupAutoSync(){this.periodicIntervalId!==null&&(window.clearInterval(this.periodicIntervalId),this.periodicIntervalId=null),!(!this.settings.autoSyncEnabled||!this.settings.periodicFullScanEnabled)&&(this.periodicIntervalId=window.setInterval(()=>{this.queueFullSync("interval")},this.settings.syncInterval*60*1e3),this.registerInterval(this.periodicIntervalId))}handleVaultChange(e,t){!this.settings.autoSyncEnabled||!this.settings.eventSyncEnabled||e instanceof p.TFile&&this.isMarkdownFile(e)&&this.enqueueFile(e.path,t)}enqueueFile(e,t){this.pendingPaths.add(e),this.scheduleQueueFlush(t)}queueFullSync(e){this.settings.autoSyncEnabled&&this.scheduleQueueFlush(e,!0)}scheduleQueueFlush(e,t=!1){this.queueTimer!==null&&window.clearTimeout(this.queueTimer),this.queueTimer=window.setTimeout(()=>{this.queueTimer=null;let i=t?void 0:Array.from(this.pendingPaths);this.pendingPaths.clear(),this.performSync(e,i).catch(n=>{let s=this.getConnectionFailureMessage(this.getConnectionFailureReason(n));this.updateStatusBar(this.t("syncFailedShort"),!0),this.showSyncError(this.t("syncFailed",{message:s}))})},this.settings.debounceSeconds*1e3)}async performSync(e="manual",t){if(!this.validateSettings(!0))return;if(this.isSyncing){t&&t.forEach(s=>this.pendingPaths.add(s)),new p.Notice(this.t("syncQueued"));return}this.isSyncing=!0,this.showSyncNotice(this.t("syncNotice")),this.updateStatusBar(this.t("syncing"));let i=new Date,n={synced:0,skipped:0,failed:0,total:0,syncedFiles:[],failedFiles:[]};try{let s=this.getCandidateFiles(t),o=await this.buildSyncPlan(s,n);if(n.total=o.length+n.skipped,o.length===0){this.settings.lastSyncTime=new Date().toISOString(),this.settings.recentSyncResult=this.createRecentSyncResult(e,i,n),this.markConnectionSuccessFromActive(),await this.savePluginData(),this.updateStatusBar(this.t("ready")),this.showSyncComplete(n);return}let c=await this.loadDocumentIndexes(o);await this.processTasks(o,c,n),this.settings.lastSyncTime=new Date().toISOString();let l=n.failed>0?this.t("syncComplete",X(n)):void 0;this.settings.recentSyncResult=this.createRecentSyncResult(e,i,n,l),n.failed>0&&n.synced===0?this.markConnectionFailure(new m(l||this.t("syncFailedShort"))):this.markConnectionSuccessFromActive(),await this.savePluginData(),this.updateStatusBar(n.failed>0?this.t("syncFailedShort"):this.t("ready"),n.failed>0),this.showSyncComplete(n)}catch(s){let o=this.getConnectionFailureMessage(this.getConnectionFailureReason(s));this.settings.recentSyncResult=this.createRecentSyncResult(e,i,n,o),this.markConnectionFailure(s),await this.savePluginData(),this.updateStatusBar(this.t("syncFailedShort"),!0),this.showSyncError(this.t("syncFailed",{message:o}))}finally{if(this.isSyncing=!1,this.pendingPaths.size>0){let s=Array.from(this.pendingPaths);this.pendingPaths.clear(),window.setTimeout(()=>{this.performSync("event",s).catch(o=>{let c=this.getConnectionFailureMessage(this.getConnectionFailureReason(o));this.updateStatusBar(this.t("syncFailedShort"),!0),this.showSyncError(this.t("syncFailed",{message:c}))})},1e3)}}}getCandidateFiles(e){if(!e)return this.app.vault.getMarkdownFiles();let t=[];return D(e).forEach(i=>{let n=this.app.vault.getAbstractFileByPath(i);n instanceof p.TFile&&this.isMarkdownFile(n)&&t.push(n)}),t}async buildSyncPlan(e,t){let i=[];for(let n of e){let s=this.getDatasetIdsForPath(n.path);if(s.length===0)continue;let o=await this.app.vault.cachedRead(n),c=this.hashContent(o),l=this.makeRemoteName(n.path);for(let d of s){B(this.syncRecords,d,n.path,c,g=>this.makeRemoteName(g));let u=this.getRecordKey(d,n.path),h=this.syncRecords.get(u);if(h&&h.hash===c&&h.documentId&&!h.deletedLocal&&h.remoteName===l){t.skipped++;continue}i.push({file:n,content:o,hash:c,datasetId:d,remoteName:l,recordKey:u})}}return i}async loadDocumentIndexes(e){let t=D(e.map(n=>n.datasetId)),i=new Map;for(let n of t){let s=await this.client.listDocuments(n),o={byId:new Map,byName:new Map};s.forEach(c=>{o.byId.set(c.id,c),c.name&&o.byName.set(c.name,c)}),i.set(n,o)}return i}async processTasks(e,t,i){let n=0,s=0,o=Math.min(this.settings.maxConcurrent,e.length),c=async()=>{for(;n<e.length;){let l=e[n++];s++,this.showSyncProgress(this.t("progress",{current:s,total:e.length,name:l.file.name}),s,e.length);try{await this.syncTask(l,t.get(l.datasetId)),i.synced++,i.syncedFiles.push(l.file.path)}catch(d){i.failed++;let u=this.getConnectionFailureMessage(this.getConnectionFailureReason(d));i.failedFiles.push({filePath:l.file.path,datasetId:l.datasetId,message:u}),this.syncRecords.set(l.recordKey,{filePath:l.file.path,datasetId:l.datasetId,remoteName:l.remoteName,hash:l.hash,lastModified:l.file.stat.mtime,lastSyncedAt:new Date().toISOString(),lastError:u}),this.debug(`Failed to sync ${l.file.path} -> ${l.datasetId}`,u)}}};await Promise.all(Array.from({length:o},c))}async syncTask(e,t){if(!t)throw new Error(`Unable to load remote document index for dataset ${e.datasetId}`);let i=this.syncRecords.get(e.recordKey),n=i!=null&&i.documentId?t.byId.get(i.documentId):void 0,s=t.byName.get(e.remoteName),o=n||s,c;if(o!=null&&o.id)try{c=await this.client.updateDocumentByText(e.datasetId,o.id,e.remoteName,e.content)}catch(u){let h=u instanceof m?u:new m(w(u));if(h.status!==404)throw h;c=await this.client.createDocumentByText(e.datasetId,e.remoteName,e.content)}else c=await this.client.createDocumentByText(e.datasetId,e.remoteName,e.content);let l=be(c),d=(l==null?void 0:l.id)||(o==null?void 0:o.id)||(i==null?void 0:i.documentId);if(!d)throw new Error("Dify did not return a document id.");this.settings.pollIndexStatus&&c.batch&&await this.pollIndexStatus(e.datasetId,c.batch),this.syncRecords.set(e.recordKey,{filePath:e.file.path,datasetId:e.datasetId,documentId:d,remoteName:e.remoteName,hash:e.hash,lastModified:e.file.stat.mtime,lastSyncedAt:new Date().toISOString(),lastBatch:c.batch}),t.byId.set(d,{id:d,name:e.remoteName}),t.byName.set(e.remoteName,{id:d,name:e.remoteName})}async pollIndexStatus(e,t){for(let i=0;i<3;i++)try{await Pe(1200),await this.client.getIndexingStatus(e,t);return}catch(n){this.debug("Indexing status check failed",w(n))}}async refreshKnowledgeBases(e=!0){if(!this.hasCompleteConnectionSettings())throw this.markConnectionMissingConfig(),await this.savePluginData(),new m(this.getConnectionFailureMessage("missing_config"),void 0,void 0,"missing_config");let t=await this.client.probeConnection();if(this.applyConnectionProbe(t),t.status!=="connected")throw await this.savePluginData(),new m(t.error||this.getConnectionFailureMessage(t.reason),t.statusCode,void 0,t.reason||"unknown");let i=t.datasets;return this.settings.knowledgeBases=i,this.settings.lastDatasetRefresh=t.checkedAt,await this.savePluginData(),e&&new p.Notice(i.length>0?this.t("datasetsRefreshed",{count:i.length}):this.t("datasetsEmpty")),i}async testConnection(){try{let e=await this.refreshKnowledgeBases(!1);this.settings.initialSetupCompleted=!0,await this.savePluginData(),new p.Notice(this.t("connectionOk",{count:e.length,url:this.settings.connectionHealth.activeBaseUrl||this.settings.connectionHealth.lastSuccessfulBaseUrl||b(this.settings.difyApiUrl)})),this.settingTab.display()}catch(e){this.showConnectionError(e)}}applyConnectionProbe(e){var n;let t=ke(e),i=e.reason||(t==null?void 0:t.reason);this.settings.connectionHealth={status:e.status,checkedAt:e.checkedAt,activeBaseUrl:e.activeBaseUrl,lastSuccessfulBaseUrl:e.lastSuccessfulBaseUrl||this.settings.connectionHealth.lastSuccessfulBaseUrl,datasetCount:e.datasetCount,latencyMs:e.latencyMs,error:e.status==="failed"?this.getConnectionFailureMessage(i||"unknown"):e.error,reason:i,statusCode:(n=e.statusCode)!=null?n:t==null?void 0:t.statusCode}}markConnectionSuccessFromActive(){let e=this.client.getActiveBaseUrl();e&&(this.settings.connectionHealth={...this.settings.connectionHealth,status:"connected",checkedAt:new Date().toISOString(),activeBaseUrl:e,lastSuccessfulBaseUrl:e,error:void 0,reason:void 0,statusCode:void 0})}markConnectionFailure(e){let t=e instanceof m?e:new m(w(e)),i=C(t);this.settings.connectionHealth={...this.settings.connectionHealth,status:"failed",checkedAt:new Date().toISOString(),activeBaseUrl:"",error:this.getConnectionFailureMessage(i),reason:i,statusCode:t.status}}markConnectionMissingConfig(){this.client.clearActiveBaseUrl(),this.settings.connectionHealth={...this.settings.connectionHealth,status:"missing_config",checkedAt:new Date().toISOString(),activeBaseUrl:"",error:this.getConnectionFailureMessage("missing_config"),reason:"missing_config",statusCode:void 0}}invalidateConnectionState(){this.client.clearActiveBaseUrl(),this.settings.connectionHealth={...this.settings.connectionHealth,status:this.settings.difyApiKey.trim()&&this.getConfiguredBaseUrls().length>0?"unknown":"missing_config",checkedAt:"",activeBaseUrl:"",error:void 0,reason:void 0,statusCode:void 0}}createRecentSyncResult(e,t,i,n){let s=new Date;return{source:e,status:n?"failed":"success",startedAt:t.toISOString(),finishedAt:s.toISOString(),elapsedMs:Math.max(0,s.getTime()-t.getTime()),activeBaseUrl:this.client.getActiveBaseUrl(),synced:i.synced,skipped:i.skipped,failed:i.failed,total:i.total,syncedFiles:i.syncedFiles.slice(0,20),failedFiles:i.failedFiles.slice(0,20),error:n}}getDatasetIdsForPath(e){return W(e,this.settings.mappings)}makeRemoteName(e){return e}getRecordKey(e,t){return E(e,t)}hashContent(e){let t=2166136261;for(let i=0;i<e.length;i++)t^=e.charCodeAt(i),t+=(t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24);return(t>>>0).toString(16)}async markLocalDeleted(e){let t=!1;this.syncRecords.forEach((i,n)=>{i.filePath===e&&(this.syncRecords.set(n,{...i,deletedLocal:!0,lastSyncedAt:new Date().toISOString()}),t=!0)}),t&&(await this.savePluginData(),new p.Notice(this.t("localDeleted",{path:e})))}async migrateRenamedRecords(e,t){F(this.syncRecords,e,t,n=>this.makeRemoteName(n))&&await this.savePluginData()}async migrateLegacyHashStorage(){if(!(this.syncRecords.size>0||this.settings.mappings.length===0))try{let t=this.app.vault.getAbstractFileByPath(this.legacyHashFileName);if(!(t instanceof p.TFile))return;let i=await this.app.vault.read(t),n=A(i);if(!f(n))return;Object.entries(n).forEach(([s,o])=>{let c=f(o)?o:{};this.getDatasetIdsForPath(s).forEach(d=>{this.syncRecords.set(this.getRecordKey(d,s),{filePath:s,datasetId:d,remoteName:this.makeRemoteName(s),hash:S(c,"hash")||"",lastModified:k(c,"lastModified")||0,lastSyncedAt:new Date().toISOString()})})}),this.syncRecords.size>0&&(await this.savePluginData(),new p.Notice(this.t("hashMigrated")))}catch(t){this.debug("Legacy hash migration failed",w(t))}}validateSettings(e){return this.validateConnectionSettings(e)&&this.validateMappingSettings(e)}validateConnectionSettings(e){return this.hasCompleteConnectionSettings()?!0:(e&&this.showConnectionError(new m(this.getConnectionFailureMessage("missing_config"),void 0,void 0,"missing_config")),!1)}validateMappingSettings(e){return this.settings.mappings.some(i=>i.enabled&&i.datasetIds.length>0)?!0:(e&&new p.Notice(this.t("validationMapping")),!1)}getConfiguredBaseUrls(){return D([b(this.settings.difyApiUrl)].filter(Boolean))}getActiveBaseUrl(){return this.client.getActiveBaseUrl()}isMarkdownFile(e){return e.extension.toLowerCase()==="md"}updateStatusBar(e,t=!1){this.statusBarItem.setText(`Dify: ${e}`),this.statusBarItem.toggleClass("dify-sync-error",t),this.statusBarItem.toggleClass("dify-sync-syncing",e===this.t("syncing"))}showSyncProgress(e,t,i){let n=i>0?Math.round(t/i*100):0,s=`${e}
${this.createProgressBar(n)} ${n}% (${t}/${i})`;this.showPersistentNotice(s)}showSyncNotice(e){this.showPersistentNotice(e)}showPersistentNotice(e){var i,n;if(!this.syncProgressNotice){this.syncProgressNotice=new p.Notice(e,0),(i=this.syncProgressNotice.noticeEl)==null||i.addClass("dify-sync-progress");return}let t=(n=this.syncProgressNotice.noticeEl)==null?void 0:n.querySelector(".notice-text");t&&(t.textContent=e)}showSyncComplete(e){var n;this.hideProgressNotice();let t=e.total===0?this.t("syncNoChanges"):this.t("syncComplete",X(e));(n=new p.Notice(t,5e3).noticeEl)==null||n.addClass("dify-sync-complete")}showSyncError(e){var i;this.hideProgressNotice(),(i=new p.Notice(e,8e3).noticeEl)==null||i.addClass("dify-sync-error-notice")}hideProgressNotice(){this.syncProgressNotice&&(this.syncProgressNotice.hide(),this.syncProgressNotice=null)}createProgressBar(e){let i=Math.round(e/100*20);return`[${"\u2588".repeat(i)}${"\u2591".repeat(20-i)}]`}getDatasetLabel(e){let t=this.settings.knowledgeBases.find(i=>i.id===e);return t?`${t.name} (${t.id})`:`${this.t("datasetUnknown")} (${e})`}getDatasetName(e){let t=this.settings.knowledgeBases.find(i=>i.id===e);return(t==null?void 0:t.name)||e}},O=class extends p.PluginSettingTab{constructor(e,t){super(e,t);this.mainMappingPage=0;this.mainMappingPageSize=4;this.outerScrollHostClass="dify-sync-outer-scroll-host";this.innerScrollHostClass="dify-sync-inner-scroll-host";this.outerScrollHosts=new Set;this.scrollbarMarkToken=0;this.plugin=t}display(){let{containerEl:e}=this;e.empty(),e.addClass("dify-sync-settings");let t=e.createDiv("app"),n=t.createEl("main",{cls:"main"}).createDiv("settings");this.renderTopbar(n),this.renderSyncSummary(n);let s=n.createDiv("dify-sync-content");this.renderConnectionSection(s),this.renderMappingSection(s),this.renderSyncSettingsSection(s),t.createDiv({cls:"toast-region",attr:{"aria-live":"polite","aria-atomic":"true"}}),this.scheduleScrollbarHostMarking(e)}hide(){this.scrollbarMarkToken++,this.clearScrollbarHosts(),super.hide()}scheduleScrollbarHostMarking(e){let t=++this.scrollbarMarkToken;this.clearScrollbarHosts(),window.requestAnimationFrame(()=>{window.requestAnimationFrame(()=>{t===this.scrollbarMarkToken&&e.isConnected&&this.markScrollbarHosts(e)})})}markScrollbarHosts(e){this.clearScrollbarHosts();let t=this.findScrollableAncestors(e);if(t.length===0)return;this.innerScrollHost=e,e.addClass(this.innerScrollHostClass),t.forEach(s=>this.addOuterScrollHost(s));let i=t[0],n=s=>this.handleSettingsWheel(s,e,i);e.addEventListener("wheel",n,{passive:!1}),this.wheelCleanup=()=>e.removeEventListener("wheel",n)}findScrollableAncestors(e){let t=[],i=e.parentElement;for(;i;)this.isVerticalScrollHost(i)&&t.push(i),i=i.parentElement;return t}isVerticalScrollHost(e){let t=window.getComputedStyle(e).overflowY;return e.scrollHeight>e.clientHeight+1&&["auto","scroll","overlay"].includes(t)}addOuterScrollHost(e){e.addClass(this.outerScrollHostClass),this.outerScrollHosts.add(e)}handleSettingsWheel(e,t,i){if(e.defaultPrevented||e.deltaY===0||this.targetCanScrollWithin(e.target,t,e.deltaY))return;let n=i.scrollTop;i.scrollTop+=e.deltaY,i.scrollTop!==n&&(e.preventDefault(),e.stopPropagation())}targetCanScrollWithin(e,t,i){let n=e instanceof HTMLElement?e:null;for(;n&&n!==t;){if(!this.outerScrollHosts.has(n)&&this.elementCanScrollInDirection(n,i))return!0;n=n.parentElement}return!1}elementCanScrollInDirection(e,t){return this.isVerticalScrollHost(e)?t<0?e.scrollTop>0:e.scrollTop+e.clientHeight<e.scrollHeight-1:!1}clearScrollbarHosts(){var e,t;(e=this.wheelCleanup)==null||e.call(this),this.wheelCleanup=void 0,this.outerScrollHosts.forEach(i=>i.removeClass(this.outerScrollHostClass)),this.outerScrollHosts.clear(),(t=this.innerScrollHost)==null||t.removeClass(this.innerScrollHostClass),this.innerScrollHost=void 0}renderTopbar(e){let t=e.createEl("header",{cls:"topbar"}),i=t.createDiv("title-line");new p.Setting(i).setName(this.plugin.t("settingsTitle")).setHeading().nameEl.addClass("heading-text"),i.createEl("p",{text:this.plugin.t("settingsSubtitle"),cls:"settings-subtitle"});let s=t.createDiv("top-actions"),o=new p.ExtraButtonComponent(s).setIcon("languages").setTooltip(this.plugin.t("languageName")),c=o.extraSettingsEl;o.onClick(()=>this.openLanguageMenu(c)),c.addClass("language-button"),c.setAttr("aria-label",this.plugin.t("languageName")),c.setAttr("title",this.plugin.t("languageName")),c.setAttr("data-action","open-language-menu");let l=new p.ExtraButtonComponent(s).setIcon("help-circle").setTooltip(this.plugin.t("openHelp")).onClick(()=>{new q(this.app,this.plugin).open()}).extraSettingsEl;l.addClass("help-button"),l.setAttr("aria-label",this.plugin.t("openHelp")),l.setAttr("title",this.plugin.t("openHelp")),l.setAttr("data-action","open-help");let d=s.createEl("a",{cls:"github-link",href:"https://github.com/BeatsAD/Vault2Dify"});d.setAttr("target","_blank"),d.setAttr("rel","noopener noreferrer"),d.setAttr("aria-label",this.plugin.t("openGithub")),d.setAttr("title","GitHub"),(0,p.setIcon)(d,"github")}openLanguageMenu(e){let t=new p.Menu;[{value:"zh-CN",label:this.plugin.t("languageChinese")},{value:"en",label:this.plugin.t("languageEnglish")}].forEach(s=>{t.addItem(o=>{o.setTitle(s.label).setChecked(this.plugin.settings.language===s.value).onClick(()=>{this.plugin.settings.language!==s.value&&(async()=>(this.plugin.settings.language=s.value,await this.plugin.savePluginData(),this.plugin.updateStatusBar(this.plugin.t("ready")),this.display()))()})})});let n=e.getBoundingClientRect();t.showAtPosition({x:n.left,y:n.bottom+4,width:n.width})}renderSyncSummary(e){let t=Y({connectionHealth:this.plugin.settings.connectionHealth,recentSyncResult:this.plugin.settings.recentSyncResult}),i={total:this.plugin.t("metricTotal"),synced:this.plugin.t("metricSynced"),skipped:this.plugin.t("metricSkipped"),failed:this.plugin.t("metricFailed")},n=e.createDiv("sync-summary");n.setAttr("aria-label",this.plugin.t("sectionDiagnostics")),t.metrics.forEach(s=>{let o=n.createDiv("metric");o.createDiv({text:i[s.key],cls:"metric-label"}),o.createDiv({text:String(s.value),cls:s.tone==="default"?"metric-value":`metric-value ${s.tone}`})})}renderConnectionSection(e){let{card:t}=this.createReviewSection(e,"connection-title",this.plugin.t("settingsReviewConnectionTitle")),i;this.createNativeSetting(t,"setting-row").setName(this.createSettingName(this.plugin.t("apiKeyName"),{required:!0})).setTooltip(this.plugin.t("apiKeyDesc")).addText(u=>{i=u.setPlaceholder(this.plugin.t("apiKeyPlaceholder")).setValue(this.plugin.settings.difyApiKey).onChange(h=>{this.plugin.settings.difyApiKey=h.trim(),this.plugin.invalidateConnectionState(),this.plugin.savePluginData()}).inputEl,i.id="dify-api-key",i.type="password",i.setAttr("aria-label",this.plugin.t("apiKeyName"))}).addExtraButton(u=>{let h=u.setIcon("eye").setTooltip(this.plugin.t("showApiKey")).onClick(()=>{let g=i.type==="password";i.type=g?"text":"password",u.setIcon(g?"eye-off":"eye");let y=this.plugin.t(g?"hideApiKey":"showApiKey");u.setTooltip(y),h.setAttr("aria-label",y),h.setAttr("title",y),h.setAttr("aria-pressed",String(g))}).extraSettingsEl;h.addClass("secret-toggle"),h.setAttr("aria-label",this.plugin.t("showApiKey")),h.setAttr("title",this.plugin.t("showApiKey")),h.setAttr("aria-controls","dify-api-key"),h.setAttr("aria-pressed","false")}),this.createNativeSetting(t,"setting-row").setName(this.createSettingName(this.plugin.t("apiUrlName"),{required:!0})).setTooltip(this.plugin.t("apiUrlDesc")).addText(u=>{u.setPlaceholder(this.plugin.t("urlPlaceholder")).setValue(this.plugin.settings.difyApiUrl).onChange(g=>{this.plugin.settings.difyApiUrl=g.trim(),this.plugin.invalidateConnectionState(),this.plugin.savePluginData()}).inputEl.setAttr("aria-label",this.plugin.t("apiUrlName"))});let n=t.createDiv("dataset-refresh-row"),s=n.createDiv("status-line");s.setAttr("aria-label",this.plugin.t("healthConnection")),s.createSpan({cls:`status-dot ${this.getConnectionStatusToneClass()}`}),s.createEl("strong",{text:this.getConnectionStatusLabel()});let o=n.createDiv("connection-action-buttons"),c=new p.ButtonComponent(o).setButtonText(this.plugin.t("clearConnectionConfig")).setClass("native-action-button").onClick(()=>{(async()=>(this.plugin.settings.difyApiKey="",this.plugin.settings.difyApiUrl="",this.plugin.settings.lanApiUrl="",this.plugin.settings.publicApiUrl="",this.plugin.invalidateConnectionState(),await this.plugin.savePluginData(),this.display()))()});c.buttonEl.setAttr("data-action","clear-connection-config"),c.buttonEl.setAttr("aria-label",this.plugin.t("clearConnectionConfig"));let l;l=new p.ButtonComponent(o).setButtonText(this.plugin.t("testConnection")).setClass("native-action-button").onClick(()=>{l.setDisabled(!0),l.setButtonText(this.plugin.t("syncing")),(async()=>{try{await this.plugin.testConnection()}finally{l.setDisabled(!1),l.setButtonText(this.plugin.t("testConnection")),this.display()}})()}),l.buttonEl.setAttr("data-action","test-connection"),l.buttonEl.setAttr("aria-label",this.plugin.t("testConnection"));let d=n.createDiv({cls:"callout",attr:{"data-role":"connection-result"}});d.hidden=!0,d.createEl("strong",{text:this.getConnectionStatusLabel()}),d.createSpan({text:this.getConnectionNote()})}renderMappingSection(e){let{card:t}=this.createReviewSection(e,"mapping-title",this.plugin.t("settingsReviewMappingTitle"),l=>{let d=new p.ButtonComponent(l).setButtonText(this.plugin.t("addMapping")).setCta().onClick(()=>{new R(this.app,this.plugin,void 0,async u=>{this.plugin.settings.mappings.push(u),await this.plugin.savePluginData(),new p.Notice(this.plugin.t("mappingSaved")),this.display()}).open()});d.buttonEl.setAttr("data-action","add-mapping"),d.buttonEl.setAttr("aria-label",this.plugin.t("addMapping"))}),i=t.createDiv({cls:"mapping-table main-mapping-table",attr:{role:"table","aria-label":this.plugin.t("sectionMapping")}}),n=i.createDiv({cls:"mapping-header",attr:{role:"row"}});n.createDiv({text:this.plugin.t("mappingIndex")}),n.createDiv({text:this.plugin.t("mappingFolderColumn")}),n.createDiv({text:this.plugin.t("mappingDatasetColumn")}),n.createDiv({text:this.plugin.t("mappingStatusColumn")}),n.createDiv({text:this.plugin.t("mappingActionColumn")});let s=this.plugin.settings.mappings,o=Math.max(0,Math.ceil(s.length/this.mainMappingPageSize)-1);this.mainMappingPage=Math.min(this.mainMappingPage,o),s.length===0&&i.createDiv({text:this.plugin.t("noMappings"),cls:"main-mapping-empty"});let c=this.mainMappingPage*this.mainMappingPageSize;s.slice(c,c+this.mainMappingPageSize).forEach((l,d)=>{this.renderMappingRow(i,l,c+d)}),this.renderMainMappingPagination(t,this.plugin.settings.mappings.length)}renderMainMappingPagination(e,t){let i=e.createDiv({cls:"main-mapping-pagination mapping-pagination",attr:{"data-role":"main-mapping-pagination"}}),n=Math.max(1,Math.ceil(t/this.mainMappingPageSize)),s=new p.ButtonComponent(i).setButtonText("\u2039"),o=s.buttonEl,c=t===0?0:this.mainMappingPage*this.mainMappingPageSize+1,l=t===0?0:Math.min(t,(this.mainMappingPage+1)*this.mainMappingPageSize);i.createSpan({text:t===0?this.plugin.t("mappingPageInfoEmpty"):`${c}-${l} / ${t}`,attr:{"data-role":"main-mapping-page-info"}});let d=new p.ButtonComponent(i).setButtonText("\u203A"),u=d.buttonEl;s.setDisabled(t===0||this.mainMappingPage===0),d.setDisabled(t===0||this.mainMappingPage>=n-1),s.onClick(()=>{this.mainMappingPage=Math.max(0,this.mainMappingPage-1),this.display()}),d.onClick(()=>{this.mainMappingPage=Math.min(n-1,this.mainMappingPage+1),this.display()})}renderMappingRow(e,t,i){let n=e.createDiv({cls:"mapping-row",attr:{role:"row"}});ie(n,this.plugin,t,i,"toggle-mapping-status",async()=>{t.enabled=!t.enabled,await this.plugin.savePluginData(),this.display()},s=>{let o=new p.ExtraButtonComponent(s).setIcon("pencil").setTooltip(this.plugin.t("edit")).onClick(()=>{new R(this.app,this.plugin,t,async l=>{this.plugin.settings.mappings=this.plugin.settings.mappings.map(d=>d.id===l.id?l:d),await this.plugin.savePluginData(),this.display()}).open()}).extraSettingsEl;o.addClass("icon"),o.setAttr("data-action","edit-mapping"),o.setAttr("aria-label",this.plugin.t("edit")),o.setAttr("title",this.plugin.t("edit"));let c=new p.ExtraButtonComponent(s).setIcon("trash-2").setTooltip(this.plugin.t("delete")).onClick(()=>{new $(this.app,this.plugin.t("deleteMappingTitle"),this.plugin.t("deleteMappingDesc"),this.plugin.t("deleteMappingConfirm"),this.plugin.t("cancel"),async()=>{this.plugin.settings.mappings=G(this.plugin.settings.mappings,t.id),await this.plugin.savePluginData(),this.display()},{folder:t.folder||this.plugin.t("rootFolder"),datasets:t.datasetIds.map(l=>this.plugin.getDatasetName(l)).join("\u3001")||this.plugin.t("datasetMissing")},l=>this.plugin.t(l)).open()}).extraSettingsEl;c.addClass("icon"),c.addClass("danger"),c.setAttr("data-action","delete-mapping"),c.setAttr("aria-label",this.plugin.t("delete")),c.setAttr("title",this.plugin.t("delete"))})}renderSyncSettingsSection(e){let{card:t}=this.createReviewSection(e,"auto-title",this.plugin.t("settingsReviewSyncTitle"));this.createNativeSetting(t,"setting-row","switch-row").setName(this.createSettingName(this.plugin.t("sectionAuto"))).addToggle(y=>{y.setValue(this.plugin.settings.autoSyncEnabled).onChange(se=>{(async()=>(this.plugin.settings.autoSyncEnabled=se,await this.plugin.savePluginData(),this.plugin.setupAutoSync(),this.display()))()}),y.toggleEl.setAttr("data-action","toggle-auto-sync")});let i=t.createDiv({attr:{id:"advanced-sync"}});this.createAdvancedSelect(i,this.plugin.t("syncAfterChange"),this.plugin.settings.debounceSeconds,[[8,this.plugin.t("debounceOption8")],[15,this.plugin.t("debounceOption15")],[30,this.plugin.t("debounceOption30")]],async y=>{this.plugin.settings.debounceSeconds=y,await this.plugin.savePluginData()},"debounce"),this.createAdvancedSelect(i,this.plugin.t("fullScanCheck"),this.plugin.settings.periodicFullScanEnabled?this.plugin.settings.syncInterval:0,[[30,this.plugin.t("fullScanOption30")],[60,this.plugin.t("fullScanOption60")],[0,this.plugin.t("fullScanOptionOff")]],async y=>{this.plugin.settings.periodicFullScanEnabled=y>0,y>0&&(this.plugin.settings.syncInterval=y),await this.plugin.savePluginData(),this.plugin.setupAutoSync()},"interval"),this.createAdvancedSelect(i,this.plugin.t("startupSyncShort"),this.plugin.settings.syncOnStartup,[[!0,this.plugin.t("optionOn")],[!1,this.plugin.t("optionOff")]],async y=>{this.plugin.settings.syncOnStartup=y,await this.plugin.savePluginData()},"startup-sync"),this.createAdvancedSelect(i,this.plugin.t("concurrentUpload"),this.plugin.settings.maxConcurrent,[[2,this.plugin.t("concurrencyOption2")],[4,this.plugin.t("concurrencyOption4")]],async y=>{this.plugin.settings.maxConcurrent=v(y,1,5,2),await this.plugin.savePluginData()},"concurrency");let n=t.createEl("details",{cls:"diagnostic-fold"});n.open=!0;let s=n.createEl("summary");s.createSpan({text:this.plugin.t("sectionDiagnostics")}),s.createSpan({text:`Dify: ${this.plugin.t("ready")}`});let o=n.createDiv("diagnostic-body"),c=this.plugin.settings.lastSyncTime?this.plugin.t("lastSync",{time:new Date(this.plugin.settings.lastSyncTime).toLocaleString()}):this.plugin.t("lastSyncInitial");o.createDiv({text:c,cls:"dify-sync-diagnostic-line"}),this.renderRecentSyncResult(o);let l=o.createDiv("sync-actions");new p.ButtonComponent(l).setButtonText(this.plugin.settings.debugLogging?`${this.plugin.t("debugName")} \xB7 ${this.plugin.t("enabled")}`:this.plugin.t("debugName")).onClick(()=>{(async()=>(this.plugin.settings.debugLogging=!this.plugin.settings.debugLogging,await this.plugin.savePluginData(),this.display()))()}).buttonEl.setAttr("data-action","toggle-debug-logging"),new p.ButtonComponent(l).setButtonText(this.plugin.t("resetRecords")).onClick(()=>{(async()=>(this.plugin.syncRecords.clear(),await this.plugin.savePluginData(),new p.Notice(this.plugin.t("resetRecordsDone")),this.display()))()}).buttonEl.setAttr("data-action","reset-sync-records");let h=t.createDiv("sync-actions manual-sync-actions"),g;g=new p.ButtonComponent(h).setButtonText(this.plugin.t("manualSync")).setCta().onClick(()=>{g.setDisabled(!0),g.setButtonText(this.plugin.t("syncing")),(async()=>{try{await this.plugin.performSync("manual")}finally{g.setDisabled(!1),g.setButtonText(this.plugin.t("manualSync")),this.display()}})()}),g.buttonEl.setAttr("data-action","sync-now"),g.buttonEl.setAttr("aria-label",this.plugin.t("manualSync"))}renderRecentSyncResult(e){let t=this.plugin.settings.recentSyncResult;if(!t){e.createDiv({text:this.plugin.t("recentSyncInitial"),cls:"dify-sync-diagnostic-line"});return}e.createDiv({text:this.plugin.t("recentSyncSummary",{source:t.source,total:t.total,synced:t.synced,skipped:t.skipped,failed:t.failed,elapsed:Te(t.elapsedMs)}),cls:"dify-sync-diagnostic-line"}),t.error&&e.createDiv({text:this.plugin.t("recentSyncError",{message:t.error}),cls:"dify-sync-diagnostic-line dify-sync-diagnostic-error"})}createReviewSection(e,t,i,n){let s=e.createEl("section",{cls:"section",attr:{"aria-labelledby":t}}),o=s.createDiv("section-head"),c=o.createDiv("heading-line"),l=new p.Setting(c).setName(i).setHeading();return l.nameEl.addClass("heading-text"),l.nameEl.id=t,n&&n(o),{card:s.createDiv("section-card")}}createSettingName(e,t={}){let i=this.containerEl.doc,n=i.createDocumentFragment(),s=i.createElement("span");if(s.className="setting-label",s.textContent=e,n.appendChild(s),t.required){let o=i.createElement("span");o.className="required-marker",o.textContent="*",o.setAttribute("aria-label","required"),n.appendChild(o)}return n}createSettingRow(e,t,i,n={}){return{control:this.createNativeSetting(e,"setting-row").setName(this.createSettingName(t,n)).setDesc(i).setTooltip(i).controlEl}}createTextInput(e,t,i,n){let s=e.createEl("input",{attr:{type:"text",placeholder:i,"aria-label":t}});return s.value=n,s}createAdvancedText(e,t,i,n,s,o=this.plugin.t("urlPlaceholder"),c={}){this.createNativeSetting(e,"advanced-field").setName(this.createSettingName(t,c)).addText(l=>{let d=l.setPlaceholder(o).setValue(i).onChange(u=>{n(u.trim())}).inputEl;d.id=s})}createAdvancedNumber(e,t,i,n,s,o,c){let l=e.createDiv("advanced-field");l.createEl("label",{text:t,attr:{for:c}});let d=l.createEl("input",{attr:{id:c,type:"number",min:String(n),max:String(s)}});d.value=String(i),d.addEventListener("change",()=>{o(Number(d.value)).catch(u=>{new p.Notice(w(u))})})}createAdvancedSelect(e,t,i,n,s,o){let c=new Map(n.map(([d])=>[String(d),d])),l=Object.fromEntries(n.map(([d,u])=>[String(d),u]));this.createNativeSetting(e,"advanced-field").setName(this.createSettingName(t)).addDropdown(d=>{d.addOptions(l).setValue(String(i)).onChange(u=>{let h=c.get(u);h!==void 0&&s(h)}),d.selectEl.id=`${o}-select`,d.selectEl.setAttr("aria-label",t)})}createNativeSetting(e,...t){let i=new p.Setting(e).setClass("native-setting-row");return t.forEach(n=>i.settingEl.addClass(n)),i}createHelpIcon(e,t){let i=e.createSpan({text:"?",cls:"help-icon"});i.setAttr("tabindex","0"),i.setAttr("aria-label",t),i.setAttr("data-tooltip",t)}getConnectionStatusLabel(){let e=this.plugin.settings.connectionHealth.status;return!this.plugin.settings.difyApiKey.trim()||this.plugin.getConfiguredBaseUrls().length===0?this.plugin.t("connectionMissing"):e==="connected"?this.plugin.t("connectionConnected"):e==="failed"?this.plugin.t("connectionFailedState"):e==="missing_config"?this.plugin.t("connectionMissing"):this.plugin.t("connectionUnknown")}getConnectionStatusToneClass(){let e=this.plugin.settings.connectionHealth.status;return!this.plugin.settings.difyApiKey.trim()||this.plugin.getConfiguredBaseUrls().length===0?"is-muted":e==="connected"?"is-success":e==="failed"?"is-error":"is-muted"}getActiveUrlLabel(){let e=this.plugin.settings.connectionHealth;return ee(e.activeBaseUrl||e.lastSuccessfulBaseUrl||b(this.plugin.settings.difyApiUrl)||"-")}getConnectionNote(){let e=this.plugin.settings.connectionHealth;return!this.plugin.settings.difyApiKey.trim()||this.plugin.getConfiguredBaseUrls().length===0?this.plugin.t("connectionNoteMissing"):e.status==="connected"?this.plugin.t("connectionNoteSuccess",{count:e.datasetCount,url:ee(e.activeBaseUrl||e.lastSuccessfulBaseUrl)}):e.status==="failed"&&e.error?this.plugin.t("connectionNoteFailed",{message:e.error}):this.plugin.t("connectionNoteIdle")}},q=class extends p.Modal{constructor(e,t){super(e);this.plugin=t}onOpen(){let{contentEl:e}=this;e.empty(),this.modalEl.addClass("dify-sync-modal-shell"),this.modalEl.addClass("help-modal-shell"),e.addClass("dify-sync-modal"),e.addClass("help-modal"),e.createDiv("modal-head").createDiv("modal-title-line").createEl("h2",{text:this.plugin.t("helpModalTitle"),attr:{id:"help-modal-title"}});let n=e.createDiv({cls:"help-modal-body",attr:{role:"document","aria-labelledby":"help-modal-title"}});this.getHelpSections().forEach(s=>this.renderHelpSection(n,s))}getHelpSections(){return[{titleKey:"helpQuickStartTitle",paragraphKeys:["helpQuickStartBody"],orderedListKeys:["helpQuickStartList"]},{titleKey:"helpApiUrlTitle",paragraphKeys:["helpApiUrlBody"]},{titleKey:"helpApiKeyTitle",paragraphKeys:["helpApiKeyBody"]},{titleKey:"helpMappingTitle",paragraphKeys:["helpMappingBody"],listKeys:["helpMappingList"]},{titleKey:"helpSyncModesTitle",listKeys:["helpSyncModesList"]},{titleKey:"helpSyncRecommendedTitle",listKeys:["helpSyncRecommendedList"]},{titleKey:"helpSyncRulesTitle",paragraphKeys:["helpSyncRulesBody"],orderedListKeys:["helpSyncRulesList"]},{titleKey:"helpTroubleshootingTitle",orderedListKeys:["helpTroubleshootingList"]},{titleKey:"helpCommonErrorsTitle",errorListKeys:["helpCommonErrorsList"]},{titleKey:"helpDatasetsTitle",listKeys:["helpDatasetsList"]},{titleKey:"helpFilesNotSyncingTitle",listKeys:["helpFilesNotSyncingList"]},{titleKey:"helpSlowSyncTitle",listKeys:["helpSlowSyncList"]},{titleKey:"helpDuplicateDocsTitle",paragraphKeys:["helpDuplicateDocsBody"],orderedListKeys:["helpDuplicateDocsList"]},{titleKey:"helpDebugTitle",paragraphKeys:["helpDebugBody"]},{titleKey:"helpPrivacyTitle",paragraphKeys:["helpPrivacyBody"]}]}renderHelpSection(e,t){let i=e.createEl("section",{cls:"help-section"});i.createEl("h3",{text:this.plugin.t(t.titleKey)}),(t.paragraphKeys||[]).forEach(n=>{this.splitHelpLines(this.plugin.t(n,{configDir:this.app.vault.configDir})).forEach(s=>{i.createEl("p",{text:s})})}),(t.orderedListKeys||[]).forEach(n=>{this.renderHelpList(i,this.splitHelpLines(this.plugin.t(n,{configDir:this.app.vault.configDir})),!0)}),(t.listKeys||[]).forEach(n=>{this.renderHelpList(i,this.splitHelpLines(this.plugin.t(n,{configDir:this.app.vault.configDir})),!1)}),(t.errorListKeys||[]).forEach(n=>{this.renderHelpErrorList(i,this.splitHelpLines(this.plugin.t(n,{configDir:this.app.vault.configDir})))})}renderHelpList(e,t,i){let n=e.createEl(i?"ol":"ul",{cls:"help-list"});t.forEach(s=>n.createEl("li",{text:s}))}renderHelpErrorList(e,t){let i=e.createDiv("help-error-list");t.forEach(n=>{let s=n.includes("\uFF1A")?"\uFF1A":":",[o,...c]=n.split(s),l=i.createDiv("help-error-item");l.createEl("strong",{text:o.trim()});let d=c.join(s).trim();d&&l.createSpan({text:d})})}splitHelpLines(e){return e.split(`
`).map(t=>t.trim()).filter(Boolean)}},$=class extends p.Modal{constructor(e,t,i,n,s,o,c,l=d=>d){super(e);this.title=t,this.message=i,this.confirmText=n,this.cancelText=s,this.onConfirm=o,this.preview=c,this.labelProvider=l}onOpen(){var h,g;let{contentEl:e}=this;e.empty(),this.modalEl.addClass("dify-sync-modal-shell"),this.modalEl.addClass("confirm-modal-shell"),e.addClass("dify-sync-modal"),e.addClass("confirm-modal"),e.createDiv("modal-head").createDiv("modal-title-line").createEl("h2",{text:this.title,attr:{id:"delete-modal-title"}});let s=e.createDiv("confirm-body").createDiv({cls:"confirm-mapping",attr:{"data-role":"delete-mapping-preview"}}),o=s.createDiv("confirm-mapping-item");o.createEl("strong",{text:this.pluginLabel("mappingFolderColumn"),cls:"confirm-mapping-label"}),o.createSpan({text:((h=this.preview)==null?void 0:h.folder)||"-",cls:"confirm-mapping-value"}).setAttr("data-role","delete-folder");let c=s.createDiv("confirm-mapping-item");c.createEl("strong",{text:this.pluginLabel("datasetName"),cls:"confirm-mapping-label"}),c.createSpan({text:((g=this.preview)==null?void 0:g.datasets)||"-",cls:"confirm-mapping-value"}).setAttr("data-role","delete-datasets");let l=e.createDiv("modal-actions");new p.ButtonComponent(l).setButtonText(this.cancelText).onClick(()=>this.close()).buttonEl.setAttr("data-action","close-delete-confirm"),new p.ButtonComponent(l).setButtonText(this.confirmText).setWarning().onClick(()=>{(async()=>(await this.onConfirm(),this.close()))()}).buttonEl.setAttr("data-action","confirm-delete")}pluginLabel(e){return this.labelProvider(e)}},R=class extends p.Modal{constructor(e,t,i,n){super(e);this.selectedFolder="";this.folderSelected=!1;this.selectedDatasets=new Set;this.pendingMappings=[];this.plugin=t,this.isEditing=!!i,this.mapping=i?{id:i.id,folder:i.folder,datasetIds:[...i.datasetIds],enabled:i.enabled}:{id:L(),folder:"",datasetIds:[],enabled:!0},this.onSave=n}onOpen(){let{contentEl:e}=this;e.empty(),this.modalEl.addClass("dify-sync-modal-shell"),this.modalEl.addClass("mapping-modal-shell"),e.addClass("dify-sync-modal"),e.addClass("mapping-modal"),this.contentEl.addEventListener("click",()=>this.closeSiblingDropdowns()),e.createDiv("modal-head").createDiv("modal-title-line").createEl("h2",{text:this.plugin.t(this.isEditing?"mappingModalTitle":"addMappingModalTitle"),attr:{id:"mapping-modal-title"}});let n=e.createDiv("modal-body"),s=n.createDiv("mapping-builder");this.renderFolderPanel(s);let c=s.createDiv({cls:"mapping-arrow",attr:{"aria-hidden":"true"}}).createDiv("mapping-arrow-icon");(0,p.setIcon)(c,"arrow-right"),this.renderDatasetPanel(s),this.renderPendingMappings(n);let l=e.createDiv("modal-actions");new p.ButtonComponent(l).setButtonText(this.plugin.t("cancel")).onClick(()=>this.close()).buttonEl.setAttr("data-action","close-modal");let u=new p.ButtonComponent(l).setButtonText(this.plugin.t("refreshDatasets")).onClick(()=>{(async()=>{try{await this.plugin.refreshKnowledgeBases(),this.renderDatasetChoices(),new p.Notice(this.plugin.t("datasetsRefreshed",{count:this.plugin.settings.knowledgeBases.length}))}catch(g){this.plugin.showConnectionError(g)}})()});u.buttonEl.setAttr("data-action","refresh-modal-datasets"),u.buttonEl.setAttr("aria-label",this.plugin.t("refreshDatasets")),new p.ButtonComponent(l).setButtonText(this.plugin.t("saveMapping")).setCta().onClick(()=>{this.savePendingMappings()}).buttonEl.setAttr("data-action","save-mapping"),this.isEditing?(this.selectFolder(this.mapping.folder,!1),this.mapping.datasetIds.forEach(g=>this.selectedDatasets.add(g)),this.updateDatasetSummary(),this.addPendingMapping(!1,this.mapping.enabled,this.mapping.id)):(this.updateDatasetSummary(),this.updatePendingVisibility())}renderFolderPanel(e){let t=e.createDiv("mapping-panel");t.createDiv("label-line").createEl("label",{text:this.plugin.t("folderName"),attr:{id:"modal-folder-label"}}),this.folderInputEl=t.createEl("input",{attr:{id:"modal-folder",type:"hidden",value:""}});let n=t.createDiv("dropdown-box");n.addEventListener("click",l=>l.stopPropagation());let s=n.createEl("button",{cls:"dropdown-trigger",attr:{type:"button","aria-expanded":"false","aria-controls":"folder-dropdown-menu","data-action":"toggle-folder-dropdown"}});this.folderSummaryEl=s.createSpan({text:this.plugin.t("selectFolderPlaceholder"),attr:{"data-role":"folder-summary"}}),(0,p.setIcon)(s.createSpan({cls:"dropdown-caret",attr:{"aria-hidden":"true"}}),"chevron-down");let o=n.createDiv({cls:"dropdown-menu",attr:{id:"folder-dropdown-menu"}});o.hidden=!0;let c=o.createEl("input",{cls:"folder-search",attr:{type:"search",placeholder:this.plugin.t("folderSearch"),"aria-label":this.plugin.t("folderSearch")}});this.folderTreeEl=o.createDiv({cls:"folder-tree dify-sync-obsidian-folder-tree",attr:{role:"tree","aria-labelledby":"modal-folder-label"}}),this.renderFolderTree(),s.addEventListener("click",()=>this.toggleMenu(s,o)),c.addEventListener("input",()=>{let l=c.value.trim().toLowerCase();this.applyFolderSearch(l)})}renderDatasetPanel(e){let t=e.createDiv("mapping-panel");t.createDiv("label-line").createEl("label",{text:this.plugin.t("datasetName"),attr:{id:"modal-dataset-label"}}),this.datasetInputEl=t.createEl("input",{attr:{id:"modal-dataset",type:"hidden",value:"","data-dataset-id":""}});let n=t.createDiv("dataset-select-row"),s=n.createDiv("dropdown-box");s.addEventListener("click",c=>c.stopPropagation()),this.datasetTriggerEl=s.createEl("button",{cls:"dropdown-trigger",attr:{type:"button","aria-expanded":"false","aria-controls":"dataset-dropdown-menu","data-action":"toggle-dataset-dropdown"}}),this.datasetSummaryEl=this.datasetTriggerEl.createSpan({attr:{"data-role":"dataset-summary"}}),(0,p.setIcon)(this.datasetTriggerEl.createSpan({cls:"dropdown-caret",attr:{"aria-hidden":"true"}}),"chevron-down"),this.datasetOptionsEl=s.createDiv({cls:"dropdown-menu",attr:{id:"dataset-dropdown-menu"}}),this.datasetOptionsEl.hidden=!0,this.renderDatasetChoices(),this.datasetTriggerEl.addEventListener("click",()=>{if(!this.folderSelected){new p.Notice(this.plugin.t("chooseFolderFirst"));return}this.toggleMenu(this.datasetTriggerEl,this.datasetOptionsEl)}),new p.ButtonComponent(n).setButtonText(this.plugin.t("addPendingMapping")).setCta().onClick(()=>this.addPendingMapping(!0)).buttonEl.setAttr("data-action","add-pending-mapping")}renderFolderTree(){this.folderTreeEl.empty();let e=this.app.vault.getAllLoadedFiles().filter(n=>n instanceof p.TFolder&&!!n.path&&n.path!=="/").map(n=>n.path).sort(),t=this.app.vault.getMarkdownFiles().filter(n=>n.extension.toLowerCase()==="md").map(n=>n.path).sort();if(e.length===0&&t.length===0){this.folderTreeEl.createDiv({text:this.plugin.t("folderPickerEmpty"),cls:"pending-empty"});return}let i=new Map;e.forEach(n=>{let s=n.lastIndexOf("/"),o=s===-1?"":n.slice(0,s),c=i.get(o)||[];c.push({path:n,type:"folder"}),i.set(o,c)}),t.forEach(n=>{let s=n.lastIndexOf("/"),o=s===-1?"":n.slice(0,s),c=i.get(o)||[];c.push({path:n,type:"file"}),i.set(o,c)}),i.forEach(n=>{n.sort((s,o)=>s.type!==o.type?s.type==="folder"?-1:1:s.path.localeCompare(o.path))}),(i.get("")||[]).forEach(n=>this.renderPathNode(n,i,this.folderTreeEl,0))}renderPathNode(e,t,i,n){if(e.type==="file"){this.renderFileNode(e.path,i);return}this.renderFolderNode(e.path,t,i,n)}renderFolderNode(e,t,i,n){let s=t.get(e)||[],o=s.length>0,c=`folder-tree-${e.replace(/[^a-zA-Z0-9_-]+/g,"-").toLowerCase()}`,l=e.split("/").pop()||e,d=i.createDiv({cls:["nav-folder",n===0?"mod-root":""].filter(Boolean).join(" ")});d.dataset.folder=e;let u=d.createDiv({cls:["nav-folder-title",o?"":"is-folder-leaf",e===this.selectedFolder&&this.folderSelected?"is-selected":""].filter(Boolean).join(" "),attr:{role:"treeitem",tabindex:"0","data-action":o?"toggle-tree-folder":"select-folder","aria-expanded":o?"true":null,"data-tree-target":o?c:null}});u.dataset.folder=e;let h=u.createSpan({cls:o?"nav-folder-collapse-indicator dify-sync-folder-toggle":"nav-folder-collapse-indicator dify-sync-folder-toggle is-leaf",attr:{"aria-hidden":"true"}});if(o&&(0,p.setIcon)(h,"chevron-right"),u.createDiv({text:l,cls:"nav-folder-title-content"}),u.createSpan({text:this.getFolderCountLabel(e),cls:"dify-sync-folder-count"}),u.addEventListener("click",()=>{if(o){this.toggleTreeFolder(u),this.selectFolder(e,!1);return}this.selectFolder(e,!0)}),u.addEventListener("keydown",y=>this.handleFolderTreeKeydown(y,u,o)),!o)return;let g=d.createDiv({cls:"nav-folder-children",attr:{id:c,role:"group"}});s.forEach(y=>this.renderPathNode(y,t,g,n+1))}renderFileNode(e,t){let i=e.split("/").pop()||e,n=t.createDiv({cls:"nav-file"});n.dataset.folder=e;let s=n.createDiv({cls:["nav-file-title",e===this.selectedFolder&&this.folderSelected?"is-selected":""].filter(Boolean).join(" "),attr:{role:"treeitem",tabindex:"0","data-action":"select-note"}});s.dataset.folder=e,s.createDiv({text:i,cls:"nav-file-title-content"}),s.addEventListener("click",()=>this.selectFolder(e,!0)),s.addEventListener("keydown",o=>this.handleFolderTreeKeydown(o,s,!1))}applyFolderSearch(e){let t=Array.from(this.folderTreeEl.querySelectorAll(".nav-folder, .nav-file")),i=t.map(n=>n.dataset.folder||"");t.forEach(n=>{let s=n.dataset.folder||"",o=s.toLowerCase(),c=!e||o.includes(e)||i.some(l=>l.startsWith(`${s}/`)&&l.toLowerCase().includes(e));n.hidden=!c}),this.folderTreeEl.querySelectorAll(".nav-folder-title[data-tree-target]").forEach(n=>{let s=this.getFolderChildContainer(n);if(!s)return;if(e){let c=Array.from(s.querySelectorAll(".nav-folder, .nav-file")).some(l=>!l.hidden);s.hidden=!c,n.toggleClass("is-collapsed",!c),n.setAttr("aria-expanded",String(c));return}let o=n.getAttr("aria-expanded")!=="false";s.hidden=!o,n.toggleClass("is-collapsed",!o)})}handleFolderTreeKeydown(e,t,i){var n,s;if(e.key==="Enter"||e.key===" "){e.preventDefault();let o=t.dataset.folder||"";i&&this.toggleTreeFolder(t),this.selectFolder(o,!i);return}if(e.key==="ArrowRight"&&i){e.preventDefault(),this.setFolderExpanded(t,!0);return}if(e.key==="ArrowLeft"&&i){e.preventDefault(),this.setFolderExpanded(t,!1);return}if(e.key==="Escape"){e.preventDefault();let o=this.folderSummaryEl.closest(".dropdown-box");(n=o==null?void 0:o.querySelector(".dropdown-menu"))==null||n.setAttr("hidden","true"),(s=o==null?void 0:o.querySelector(".dropdown-trigger"))==null||s.setAttr("aria-expanded","false")}}getFolderCountLabel(e){return`${this.app.vault.getMarkdownFiles().filter(i=>i.path.startsWith(`${e}/`)).length} \u7BC7`}renderDatasetChoices(){if(this.datasetOptionsEl.empty(),this.plugin.settings.knowledgeBases.length===0){this.datasetOptionsEl.createDiv({text:this.plugin.t("datasetsDropdownEmpty"),cls:"dataset-empty-state"});return}this.plugin.settings.knowledgeBases.forEach(e=>{let t=this.datasetOptionsEl.createEl("label",{cls:"dataset-option"}),i=t.createEl("input",{attr:{type:"checkbox","data-action":"select-dataset","data-dataset":e.name||e.id,"data-dataset-id":e.id}});i.checked=this.selectedDatasets.has(e.id);let n=t.createSpan({cls:"dataset-checkmark",attr:{"aria-hidden":"true"}});(0,p.setIcon)(n,"check"),t.toggleClass("is-selected",i.checked),i.addEventListener("change",()=>{i.checked?this.selectedDatasets.add(e.id):this.selectedDatasets.delete(e.id),t.toggleClass("is-selected",i.checked),this.updateDatasetSummary()});let s=t.createSpan();s.createSpan({text:e.name||e.id}),s.createEl("small",{text:e.id})})}renderPendingMappings(e){let t=e.createDiv("pending-mappings"),i=t.createDiv("pending-mapping-head");i.createDiv("label-line").createEl("label",{text:this.plugin.t("pendingMappingsTitle")});let s=i.createDiv("pending-bulk-actions");s.setAttr("aria-label",this.plugin.t("bulkSet"));let o=new p.ButtonComponent(s).setButtonText(this.plugin.t("enableAll")).setClass("bulk-action").onClick(()=>this.setAllPendingStatus(!0));this.enableAllButtonEl=o.buttonEl,this.enableAllButtonEl.setAttr("data-action","enable-all-pending");let c=new p.ButtonComponent(s).setButtonText(this.plugin.t("pauseAll")).setClass("bulk-action").onClick(()=>this.setAllPendingStatus(!1));this.pauseAllButtonEl=c.buttonEl,this.pauseAllButtonEl.setAttr("data-action","pause-all-pending"),this.pendingEmptyEl=t.createDiv({text:this.plugin.t("pendingEmptyDesc"),cls:"pending-empty",attr:{"data-role":"pending-empty"}}),this.pendingTableEl=t.createDiv({cls:"mapping-table pending-mapping-table",attr:{"data-role":"pending-mapping-table",hidden:"true"}}),this.renderPendingHeader();let l=t.createDiv({cls:"mapping-pagination",attr:{"data-role":"pending-pagination"}});new p.ButtonComponent(l).setButtonText("\u2039").setDisabled(!0),this.pendingPageInfoEl=l.createSpan({text:"0-0 / 0",attr:{"data-role":"pending-page-info"}}),new p.ButtonComponent(l).setButtonText("\u203A").setDisabled(!0)}renderPendingHeader(){this.pendingTableEl.empty();let e=this.pendingTableEl.createDiv({cls:"mapping-header",attr:{role:"row"}});e.createDiv({text:this.plugin.t("mappingIndex")}),e.createDiv({text:this.plugin.t("mappingFolderColumn")}),e.createDiv({text:this.plugin.t("mappingDatasetColumn")}),e.createDiv({text:this.plugin.t("mappingStatusColumn")}),e.createDiv({text:this.plugin.t("mappingActionColumn")})}addPendingMapping(e=!0,t=!0,i=L()){if(!this.folderSelected){new p.Notice(this.plugin.t("chooseFolderFirst"));return}if(this.selectedDatasets.size===0){new p.Notice(this.plugin.t("datasetMissing"));return}let n={id:i,folder:P(this.selectedFolder),datasetIds:Array.from(this.selectedDatasets),enabled:t};this.pendingMappings=this.isEditing?[n]:this.pendingMappings.filter(s=>s.folder!==n.folder).concat(n),e&&new p.Notice(this.plugin.t("pendingAdded")),this.renderPendingRows(),this.resetDraft()}renderPendingRows(){this.renderPendingHeader(),this.pendingMappings.forEach((e,t)=>{let i=this.pendingTableEl.createDiv({cls:"mapping-row",attr:{role:"row"}});ie(i,this.plugin,e,t,"toggle-pending-status",()=>{e.enabled=!e.enabled,this.renderPendingRows()},n=>{let s=new p.ExtraButtonComponent(n).setIcon("refresh-cw").setTooltip(this.plugin.t("refreshDatasets")).onClick(()=>{(async()=>{try{await this.plugin.refreshKnowledgeBases(),this.renderDatasetChoices(),new p.Notice(this.plugin.t("datasetsRefreshed",{count:this.plugin.settings.knowledgeBases.length}))}catch(c){this.plugin.showConnectionError(c)}})()}).extraSettingsEl;s.addClass("icon"),s.setAttr("data-action","refresh-pending-mapping"),s.setAttr("aria-label",this.plugin.t("refreshDatasets")),s.setAttr("title",this.plugin.t("refreshDatasets"));let o=new p.ExtraButtonComponent(n).setIcon("trash-2").setTooltip(this.plugin.t("delete")).onClick(()=>{this.pendingMappings=this.pendingMappings.filter(c=>c.id!==e.id),this.renderPendingRows()}).extraSettingsEl;o.addClass("icon"),o.addClass("danger"),o.setAttr("data-action","remove-pending-mapping"),o.setAttr("aria-label",this.plugin.t("delete"))})}),this.updatePendingVisibility()}updatePendingVisibility(){let e=this.pendingMappings.length;this.pendingTableEl&&(this.pendingTableEl.hidden=e===0,this.pendingTableEl.toggleClass("is-hidden",e===0),this.pendingTableEl.style.display=e===0?"none":""),this.pendingEmptyEl&&(this.pendingEmptyEl.hidden=e>0,this.pendingEmptyEl.toggleClass("is-hidden",e>0),this.pendingEmptyEl.style.display=e>0?"none":""),this.pendingPageInfoEl&&this.pendingPageInfoEl.setText(e?`1-${e} / ${e}`:"0-0 / 0"),this.enableAllButtonEl&&(this.enableAllButtonEl.disabled=e===0),this.pauseAllButtonEl&&(this.pauseAllButtonEl.disabled=e===0)}setAllPendingStatus(e){this.pendingMappings=this.pendingMappings.map(t=>({...t,enabled:e})),this.renderPendingRows()}async savePendingMappings(){if(this.pendingMappings.length===0){new p.Notice(this.plugin.t("validationMapping"));return}for(let e of this.pendingMappings)await this.onSave(e);this.close()}selectFolder(e,t){var i,n;if(this.selectedFolder=e,this.folderSelected=!0,this.folderInputEl&&(this.folderInputEl.value=e),this.folderSummaryEl.setText(e||this.plugin.t("rootFolder")),this.folderTreeEl.querySelectorAll(".nav-folder-title, .nav-file-title").forEach(s=>{s.toggleClass("is-selected",s.dataset.folder===e)}),this.datasetTriggerEl.disabled=!1,this.updateDatasetSummary(),t){let s=this.folderSummaryEl.closest(".dropdown-box");(i=s==null?void 0:s.querySelector(".dropdown-menu"))==null||i.setAttr("hidden","true"),(n=s==null?void 0:s.querySelector(".dropdown-trigger"))==null||n.setAttr("aria-expanded","false")}}updateDatasetSummary(){if(!this.datasetSummaryEl)return;if(!this.folderSelected){this.datasetSummaryEl.setText(this.plugin.t("chooseFolderFirst")),this.datasetTriggerEl&&(this.datasetTriggerEl.disabled=!0),this.datasetInputEl&&(this.datasetInputEl.value="",this.datasetInputEl.dataset.datasetId="");return}if(this.selectedDatasets.size===0){this.datasetSummaryEl.setText(this.plugin.t("datasetName")),this.datasetInputEl&&(this.datasetInputEl.value="",this.datasetInputEl.dataset.datasetId="");return}let e=Array.from(this.selectedDatasets),t=e.map(i=>this.plugin.getDatasetName(i));this.datasetSummaryEl.setText(t.join("\u3001")),this.datasetInputEl&&(this.datasetInputEl.value=t.join(","),this.datasetInputEl.dataset.datasetId=e.join(","))}resetDraft(){this.isEditing||(this.folderSelected=!1,this.selectedFolder="",this.selectedDatasets.clear(),this.folderInputEl&&(this.folderInputEl.value=""),this.folderSummaryEl.setText(this.plugin.t("selectFolderPlaceholder")),this.renderDatasetChoices(),this.updateDatasetSummary())}toggleMenu(e,t){if(e.getAttr("aria-expanded")==="true"){e.setAttr("aria-expanded","false"),t.hidden=!0;return}this.closeSiblingDropdowns(t),e.setAttr("aria-expanded","true"),t.hidden=!1}closeSiblingDropdowns(e){let t=(e==null?void 0:e.closest(".dify-sync-modal"))||this.contentEl;t.querySelectorAll(".dropdown-menu").forEach(i=>{var s;if(i===e)return;i.hidden=!0;let n=i.id?t.querySelector(`.dropdown-trigger[aria-controls="${i.id}"]`):(s=i.parentElement)==null?void 0:s.querySelector(".dropdown-trigger");n==null||n.setAttr("aria-expanded","false")})}toggleTreeFolder(e){let t=e.getAttr("aria-expanded")==="true";this.setFolderExpanded(e,!t)}setFolderExpanded(e,t){let i=this.getFolderChildContainer(e);i&&(e.setAttr("aria-expanded",String(t)),e.toggleClass("is-collapsed",!t),i.hidden=!t)}getFolderChildContainer(e){let t=e.dataset.treeTarget,i=t?this.contentEl.querySelector(`#${t}`):null;return i!=null&&i.instanceOf(HTMLElement)?i:null}onClose(){this.contentEl.empty()}};function te(){return{status:"unknown",checkedAt:"",activeBaseUrl:"",lastSuccessfulBaseUrl:"",datasetCount:0,latencyMs:0}}function De(a){if(f(a))return ne(a.reason)?a.reason:void 0}function be(a){let r=a.document;if(Z(r))return r;let e=a.data;return Z(e)?e:void 0}function Z(a){return f(a)&&typeof a.id=="string"}function we(a){return f(a)?Object.fromEntries(Object.entries(a).filter(r=>Ee(r[1]))):{}}function Ee(a){return f(a)&&typeof a.filePath=="string"&&typeof a.datasetId=="string"&&typeof a.remoteName=="string"&&typeof a.hash=="string"&&typeof a.lastModified=="number"&&typeof a.lastSyncedAt=="string"}function Ae(a){let r=te(),e=f(a)?a:{},t=["unknown","missing_config","connected","failed"].includes(String(e.status))?e.status:r.status,i=ne(e.reason)?e.reason:void 0;return{status:t,checkedAt:S(e,"checkedAt")||r.checkedAt,activeBaseUrl:S(e,"activeBaseUrl")||r.activeBaseUrl,lastSuccessfulBaseUrl:S(e,"lastSuccessfulBaseUrl")||r.lastSuccessfulBaseUrl,datasetCount:v(k(e,"datasetCount")||r.datasetCount,0,1e5,r.datasetCount),latencyMs:v(k(e,"latencyMs")||r.latencyMs,0,6e5,r.latencyMs),error:S(e,"error"),reason:i,statusCode:k(e,"statusCode")}}function ke(a){for(let r=a.candidates.length-1;r>=0;r--){let e=a.candidates[r];if(!e.ok)return e}}function Ce(a){let r={missing_config:"connectionErrorMissingConfig",auth_failed:"connectionErrorAuthFailed",permission_denied:"connectionErrorPermissionDenied",not_found:"connectionErrorNotFound",timeout:"connectionErrorTimeout",network:"connectionErrorNetwork",server:"connectionErrorServer",path_mismatch:"connectionErrorPathMismatch",rate_limited:"connectionErrorRateLimited",unexpected_response:"connectionErrorUnexpectedResponse",unknown:"connectionErrorUnknown"};return r[a]||r.unknown}function ne(a){return["missing_config","auth_failed","permission_denied","not_found","timeout","network","server","path_mismatch","rate_limited","unexpected_response","unknown"].includes(String(a))}function Te(a){return a<1e3?`${a}ms`:`${(a/1e3).toFixed(1)}s`}function X(a){return{synced:a.synced,skipped:a.skipped,failed:a.failed}}function ee(a){return(a||"").replace(/^https?:\/\//i,"")||"-"}function Pe(a){return new Promise(r=>window.setTimeout(r,a))}function ie(a,r,e,t,i,n,s){a.dataset.folder=e.folder,a.dataset.dataset=e.datasetIds.map(h=>r.getDatasetName(h)).join(","),a.dataset.datasetId=e.datasetIds.join(","),a.createDiv({text:String(t+1),cls:"mapping-index"}),a.createDiv().createDiv({text:e.folder||r.t("rootFolder"),cls:"folder-name"});let c=a.createDiv("tags");(e.datasetIds.length?e.datasetIds:[""]).forEach(h=>{c.createSpan({text:h?r.getDatasetName(h):r.t("datasetMissing"),cls:"tag dataset-name"})});let d=a.createDiv().createDiv("mapping-status-control"),u=new p.ToggleComponent(d).setValue(e.enabled).onChange(()=>{Promise.resolve(n()).catch(h=>{new p.Notice(w(h))})});u.toggleEl.setAttr("data-action",i),u.toggleEl.setAttr("aria-label",e.enabled?r.t("enabled"):r.t("disabled")),d.createSpan({text:e.enabled?r.t("enabled"):r.t("disabled"),cls:"mapping-status-label"}),s(a.createDiv("row-actions"))}function L(){return`map-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}function w(a){return f(a)&&S(a,"message")||String(a)}