From 32e69a6c7bd6c76e91dfa8d04d00cacd2aacc0f9 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:07:26 +0800 Subject: [PATCH 01/21] Delete sql.js: remove db.ts, wasm, dependency, and all sql.js code paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove paperforge/plugin/src/services/db.ts (sql.js wrapper, initDatabase/searchMetadata/SearchResultItem) - Remove paperforge/plugin/sql-wasm.wasm (644KB binary) - Remove sql.js and @types/sql.js from package.json; npm install to update lockfile - dashboard.ts: remove import of db.ts, remove _sqlJsInitialized/_sqlJsFailed state, remove the sql.js search path block entirely — all searches go straight to CLI spawn. Clean up stale comments. - Bundle drops from 346KB to 167KB; 6 test files / 58 tests still pass --- paperforge/plugin/main.js | 9649 +--------------------- paperforge/plugin/package-lock.json | 28 - paperforge/plugin/package.json | 4 - paperforge/plugin/sql-wasm.wasm | Bin 659730 -> 0 bytes paperforge/plugin/src/services/db.ts | 119 - paperforge/plugin/src/views/dashboard.ts | 75 +- 6 files changed, 43 insertions(+), 9832 deletions(-) delete mode 100644 paperforge/plugin/sql-wasm.wasm delete mode 100644 paperforge/plugin/src/services/db.ts diff --git a/paperforge/plugin/main.js b/paperforge/plugin/main.js index 4540ad4b..d95235db 100644 --- a/paperforge/plugin/main.js +++ b/paperforge/plugin/main.js @@ -1,4980 +1,11 @@ -"use strict"; -var $s = Object.create; -var Pt = Object.defineProperty; -var Vs = Object.getOwnPropertyDescriptor; -var qs = Object.getOwnPropertyNames; -var Hs = Object.getPrototypeOf, - Ks = Object.prototype.hasOwnProperty; -var Us = (_, y, r) => - y in _ - ? Pt(_, y, { enumerable: !0, configurable: !0, writable: !0, value: r }) - : (_[y] = r); -var vn = (_, y) => () => (y || _((y = { exports: {} }).exports, y), y.exports), - Ws = (_, y) => { - for (var r in y) Pt(_, r, { get: y[r], enumerable: !0 }); - }, - En = (_, y, r, n) => { - if ((y && typeof y == "object") || typeof y == "function") - for (let i of qs(y)) - !Ks.call(_, i) && - i !== r && - Pt(_, i, { - get: () => y[i], - enumerable: !(n = Vs(y, i)) || n.enumerable, - }); - return _; - }; -var ae = (_, y, r) => ( - (r = _ != null ? $s(Hs(_)) : {}), - En( - y || !_ || !_.__esModule - ? Pt(r, "default", { value: _, enumerable: !0 }) - : r, - _ - ) - ), - Zs = (_) => En(Pt({}, "__esModule", { value: !0 }), _); -var Xe = (_, y, r) => Us(_, typeof y != "symbol" ? y + "" : y, r); -var Sr = vn((oa, Gs) => { - Gs.exports = { - versions: [ - { - version: "1.5.15", - date: "2026-06-01", - title: - "\u5168\u6587\u5B58\u50A8\u91CD\u6784 + OCR \u9605\u8BFB\u987A\u5E8F\u4FEE\u590D + Redo \u4E00\u952E\u91CD\u505A", - breaking_or_migration: [ - "\u5168\u6587\u6587\u4EF6\u73B0\u5728\u7EDF\u4E00\u5B58\u653E\u4E8E System/PaperForge/ocr/ \u4E0B\uFF0C\u4E0D\u518D\u5728\u5DE5\u4F5C\u533A\u4FDD\u7559\u526F\u672C", - "Redo OCR \u73B0\u5728\u4F1A\u7ACB\u5373\u6267\u884C\uFF08\u4E00\u952E\u5B8C\u6210\uFF09\uFF0C\u4E0D\u518D\u9700\u8981\u624B\u52A8\u518D\u8DD1\u4E00\u6B21", - ], - new_features: [ - "Redo OCR \u4E00\u952E\u95ED\u73AF\uFF1A\u52FE\u9009 \u2192 \u70B9\u6309\u94AE \u2192 \u81EA\u52A8\u5B8C\u6210\u5168\u90E8\u6D41\u7A0B", - "\u8BBE\u7F6E\u9875\u65B0\u589E\u300C\u66F4\u65B0\u4E0E\u624B\u518C\u300D\u6807\u7B7E\u9875\uFF0C\u53EF\u968F\u65F6\u67E5\u770B\u7248\u672C\u66F4\u65B0\u8BB0\u5F55\u548C\u4F7F\u7528\u624B\u518C", - "\u63D2\u4EF6\u66F4\u65B0\u540E\u81EA\u52A8\u5F39\u51FA\u66F4\u65B0\u8BF4\u660E", - ], - fixes: [ - "\u4FEE\u590D\u5168\u6587\u9605\u8BFB\u987A\u5E8F\u6DF7\u4E71\uFF0C\u4F18\u5316\u6574\u4F53\u6392\u7248\u4F53\u9A8C", - "\u4FEE\u590D\u7AE0\u8282\u6807\u9898\u548C\u6B63\u6587\u6BB5\u843D\u9519\u4F4D\u65AD\u5F00\u7684\u95EE\u9898", - "\u4FEE\u590D\u56FE\u8868\u548C\u5BF9\u5E94\u56FE\u6CE8\u88AB\u5206\u5F00\u7684\u95EE\u9898", - "\u4FEE\u590D\u9996\u9875\u6458\u8981\u533A\u5757\u6392\u5E8F\u5F02\u5E38", - "\u4FEE\u590D\u5E76\u6392\u56FE\u7247\u672A\u80FD\u81EA\u52A8\u5408\u5E76\u7684\u95EE\u9898", - "Dashboard \u73B0\u5728\u80FD\u6B63\u786E\u8BC6\u522B\u65B0\u7684\u5168\u6587\u6587\u4EF6\u4F4D\u7F6E", - ], - recommended_actions: [ - "\u65E7\u7248 OCR \u5168\u6587\u53EF\u80FD\u5B58\u5728\u9605\u8BFB\u987A\u5E8F\u95EE\u9898\uFF0C\u5EFA\u8BAE\u5BF9\u91CD\u8981\u8BBA\u6587\u6267\u884C\u4E00\u6B21 Redo OCR", - "\u6253\u5F00\u5168\u6587\u8BF7\u76F4\u63A5\u4F7F\u7528 Dashboard \u7684\u300C\u6253\u5F00\u5168\u6587\u300D\u6309\u94AE", - ], - }, - ], - }; -}); -var Zn = vn((nr, Ot) => { - var tr = void 0, - rr = function (_) { - return ( - tr || - ((tr = new Promise(function (y, r) { - var cn, pn; - var n = typeof _ != "undefined" ? _ : {}, - i = n.onAbort; - ((n.onAbort = function (e) { - (r(new Error(e)), i && i(e)); - }), - (n.postRun = n.postRun || []), - n.postRun.push(function () { - y(n); - }), - (Ot = void 0)); - var a; - a || (a = typeof n != "undefined" ? n : {}); - var c = !!globalThis.window, - l = !!globalThis.WorkerGlobalScope; - a.onRuntimeInitialized = function () { - function e(m, T) { - switch (typeof T) { - case "boolean": - js(m, T ? 1 : 0); - break; - case "number": - Ls(m, T); - break; - case "string": - Is(m, T, -1, -1); - break; - case "object": - if (T === null) _n(m); - else if (T.length != null) { - var L = Ht(T.length); - (F.set(T, L), Ns(m, L, T.length, -1), St(L)); - } else - Zt( - m, - "Wrong API use : tried to return a value of an unknown type (" + - T + - ").", - -1 - ); - break; - default: - _n(m); - } - } - function t(m, T) { - for (var L = [], N = 0; N < m; N += 1) { - var W = fe(T + 4 * N, "i32"), - ee = Ds(W); - if (ee === 1 || ee === 2) W = Ms(W); - else if (ee === 3) W = Bs(W); - else if (ee === 4) { - ((ee = W), (W = As(ee)), (ee = Os(ee))); - for (var Be = new Uint8Array(W), Re = 0; Re < W; Re += 1) - Be[Re] = F[ee + Re]; - W = Be; - } else W = null; - L.push(W); - } - return L; - } - function s(m, T) { - ((this.Qa = m), (this.db = T), (this.Oa = 1), (this.yb = [])); - } - function o(m, T) { - if (((this.db = T), (this.ob = qt(m)), this.ob === null)) - throw Error("Unable to allocate memory for the SQL string"); - ((this.ub = this.ob), (this.gb = this.Fb = null)); - } - function d(m) { - if ( - ((this.filename = - "dbfile_" + ((4294967295 * Math.random()) >>> 0)), - m != null) - ) { - var T = this.filename, - L = "/", - N = T; - if ( - (L && - ((L = typeof L == "string" ? L : lr(L)), - (N = T ? ce(L + "/" + T) : L)), - (T = jr(!0, !0)), - (N = os(N, T)), - m) - ) { - if (typeof m == "string") { - L = Array(m.length); - for (var W = 0, ee = m.length; W < ee; ++W) - L[W] = m.charCodeAt(W); - m = L; - } - (jt(N, T | 146), - (L = ft(N, 577)), - en(L, m, 0, m.length, 0), - hr(L), - jt(N, T)); - } - } - (this.handleError($(this.filename, E)), - (this.db = fe(E, "i32")), - yn(this.db), - (this.pb = {}), - (this.Sa = {})); - } - var E = st(4), - P = a.cwrap, - $ = P("sqlite3_open", "number", ["string", "number"]), - Q = P("sqlite3_close_v2", "number", ["number"]), - Z = P("sqlite3_exec", "number", [ - "number", - "string", - "number", - "number", - "number", - ]), - Y = P("sqlite3_changes", "number", ["number"]), - _e = P("sqlite3_prepare_v2", "number", [ - "number", - "string", - "number", - "number", - "number", - ]), - ht = P("sqlite3_sql", "string", ["number"]), - un = P("sqlite3_normalized_sql", "string", ["number"]), - dn = P("sqlite3_prepare_v2", "number", [ - "number", - "number", - "number", - "number", - "number", - ]), - gs = P("sqlite3_bind_text", "number", [ - "number", - "number", - "number", - "number", - "number", - ]), - fn = P("sqlite3_bind_blob", "number", [ - "number", - "number", - "number", - "number", - "number", - ]), - _s = P("sqlite3_bind_double", "number", [ - "number", - "number", - "number", - ]), - ms = P("sqlite3_bind_int", "number", [ - "number", - "number", - "number", - ]), - ys = P("sqlite3_bind_parameter_index", "number", [ - "number", - "string", - ]), - bs = P("sqlite3_step", "number", ["number"]), - vs = P("sqlite3_errmsg", "string", ["number"]), - Es = P("sqlite3_column_count", "number", ["number"]), - xs = P("sqlite3_data_count", "number", ["number"]), - ws = P("sqlite3_column_double", "number", ["number", "number"]), - hn = P("sqlite3_column_text", "string", ["number", "number"]), - ks = P("sqlite3_column_blob", "number", ["number", "number"]), - Ss = P("sqlite3_column_bytes", "number", ["number", "number"]), - Ps = P("sqlite3_column_type", "number", ["number", "number"]), - Cs = P("sqlite3_column_name", "string", ["number", "number"]), - Fs = P("sqlite3_reset", "number", ["number"]), - Rs = P("sqlite3_clear_bindings", "number", ["number"]), - Ts = P("sqlite3_finalize", "number", ["number"]), - gn = P( - "sqlite3_create_function_v2", - "number", - "number string number number number number number number number".split( - " " - ) - ), - Ds = P("sqlite3_value_type", "number", ["number"]), - As = P("sqlite3_value_bytes", "number", ["number"]), - Bs = P("sqlite3_value_text", "string", ["number"]), - Os = P("sqlite3_value_blob", "number", ["number"]), - Ms = P("sqlite3_value_double", "number", ["number"]), - Ls = P("sqlite3_result_double", "", ["number", "number"]), - _n = P("sqlite3_result_null", "", ["number"]), - Is = P("sqlite3_result_text", "", [ - "number", - "string", - "number", - "number", - ]), - Ns = P("sqlite3_result_blob", "", [ - "number", - "number", - "number", - "number", - ]), - js = P("sqlite3_result_int", "", ["number", "number"]), - Zt = P("sqlite3_result_error", "", [ - "number", - "string", - "number", - ]), - mn = P("sqlite3_aggregate_context", "number", [ - "number", - "number", - ]), - yn = P("RegisterExtensionFunctions", "number", ["number"]), - bn = P("sqlite3_update_hook", "number", [ - "number", - "number", - "number", - ]); - ((s.prototype.bind = function (m) { - if (!this.Qa) throw "Statement closed"; - return ( - this.reset(), - Array.isArray(m) - ? this.Wb(m) - : m != null && typeof m == "object" - ? this.Xb(m) - : !0 - ); - }), - (s.prototype.step = function () { - if (!this.Qa) throw "Statement closed"; - this.Oa = 1; - var m = bs(this.Qa); - switch (m) { - case 100: - return !0; - case 101: - return !1; - default: - throw this.db.handleError(m); - } - }), - (s.prototype.Pb = function (m) { - return ( - m == null && ((m = this.Oa), (this.Oa += 1)), - ws(this.Qa, m) - ); - }), - (s.prototype.hc = function (m) { - if ( - (m == null && ((m = this.Oa), (this.Oa += 1)), - (m = hn(this.Qa, m)), - typeof BigInt != "function") - ) - throw Error("BigInt is not supported"); - return BigInt(m); - }), - (s.prototype.mc = function (m) { - return ( - m == null && ((m = this.Oa), (this.Oa += 1)), - hn(this.Qa, m) - ); - }), - (s.prototype.getBlob = function (m) { - m == null && ((m = this.Oa), (this.Oa += 1)); - var T = Ss(this.Qa, m); - m = ks(this.Qa, m); - for (var L = new Uint8Array(T), N = 0; N < T; N += 1) - L[N] = F[m + N]; - return L; - }), - (s.prototype.get = function (m, T) { - ((T = T || {}), - m != null && this.bind(m) && this.step(), - (m = [])); - for (var L = xs(this.Qa), N = 0; N < L; N += 1) - switch (Ps(this.Qa, N)) { - case 1: - var W = T.useBigInt ? this.hc(N) : this.Pb(N); - m.push(W); - break; - case 2: - m.push(this.Pb(N)); - break; - case 3: - m.push(this.mc(N)); - break; - case 4: - m.push(this.getBlob(N)); - break; - default: - m.push(null); - } - return m; - }), - (s.prototype.Db = function () { - for (var m = [], T = Es(this.Qa), L = 0; L < T; L += 1) - m.push(Cs(this.Qa, L)); - return m; - }), - (s.prototype.Ob = function (m, T) { - ((m = this.get(m, T)), (T = this.Db())); - for (var L = {}, N = 0; N < T.length; N += 1) L[T[N]] = m[N]; - return L; - }), - (s.prototype.lc = function () { - return ht(this.Qa); - }), - (s.prototype.ic = function () { - return un(this.Qa); - }), - (s.prototype.Jb = function (m) { - return (m != null && this.bind(m), this.step(), this.reset()); - }), - (s.prototype.Lb = function (m, T) { - (T == null && ((T = this.Oa), (this.Oa += 1)), - (m = qt(m)), - this.yb.push(m), - this.db.handleError(gs(this.Qa, T, m, -1, 0))); - }), - (s.prototype.Vb = function (m, T) { - T == null && ((T = this.Oa), (this.Oa += 1)); - var L = Ht(m.length); - (F.set(m, L), - this.yb.push(L), - this.db.handleError(fn(this.Qa, T, L, m.length, 0))); - }), - (s.prototype.Kb = function (m, T) { - (T == null && ((T = this.Oa), (this.Oa += 1)), - this.db.handleError( - (m === (m | 0) ? ms : _s)(this.Qa, T, m) - )); - }), - (s.prototype.Yb = function (m) { - (m == null && ((m = this.Oa), (this.Oa += 1)), - fn(this.Qa, m, 0, 0, 0)); - }), - (s.prototype.Mb = function (m, T) { - switch ( - (T == null && ((T = this.Oa), (this.Oa += 1)), typeof m) - ) { - case "string": - this.Lb(m, T); - return; - case "number": - this.Kb(m, T); - return; - case "bigint": - this.Lb(m.toString(), T); - return; - case "boolean": - this.Kb(m + 0, T); - return; - case "object": - if (m === null) { - this.Yb(T); - return; - } - if (m.length != null) { - this.Vb(m, T); - return; - } - } - throw ( - "Wrong API use : tried to bind a value of an unknown type (" + - m + - ")." - ); - }), - (s.prototype.Xb = function (m) { - var T = this; - return ( - Object.keys(m).forEach(function (L) { - var N = ys(T.Qa, L); - N !== 0 && T.Mb(m[L], N); - }), - !0 - ); - }), - (s.prototype.Wb = function (m) { - for (var T = 0; T < m.length; T += 1) this.Mb(m[T], T + 1); - return !0; - }), - (s.prototype.reset = function () { - return (this.Cb(), Rs(this.Qa) === 0 && Fs(this.Qa) === 0); - }), - (s.prototype.Cb = function () { - for (var m; (m = this.yb.pop()) !== void 0; ) St(m); - }), - (s.prototype.cb = function () { - this.Cb(); - var m = Ts(this.Qa) === 0; - return (delete this.db.pb[this.Qa], (this.Qa = 0), m); - }), - (o.prototype.next = function () { - if (this.ob === null) return { done: !0 }; - if ( - (this.gb !== null && (this.gb.cb(), (this.gb = null)), - !this.db.db) - ) - throw (this.Ab(), Error("Database closed")); - var m = Ut(), - T = st(4); - (De(E), De(T)); - try { - (this.db.handleError(dn(this.db.db, this.ub, -1, E, T)), - (this.ub = fe(T, "i32"))); - var L = fe(E, "i32"); - return L === 0 - ? (this.Ab(), { done: !0 }) - : ((this.gb = new s(L, this.db)), - (this.db.pb[L] = this.gb), - { value: this.gb, done: !1 }); - } catch (N) { - throw ((this.Fb = j(this.ub)), this.Ab(), N); - } finally { - Kt(m); - } - }), - (o.prototype.Ab = function () { - (St(this.ob), (this.ob = null)); - }), - (o.prototype.jc = function () { - return this.Fb !== null ? this.Fb : j(this.ub); - }), - typeof Symbol == "function" && - typeof Symbol.iterator == "symbol" && - (o.prototype[Symbol.iterator] = function () { - return this; - }), - (d.prototype.Jb = function (m, T) { - if (!this.db) throw "Database closed"; - if (T) { - m = this.Gb(m, T); - try { - m.step(); - } finally { - m.cb(); - } - } else this.handleError(Z(this.db, m, 0, 0, E)); - return this; - }), - (d.prototype.exec = function (m, T, L) { - if (!this.db) throw "Database closed"; - var N = null, - W = null, - ee = null; - try { - ee = W = qt(m); - var Be = st(4); - for (m = []; fe(ee, "i8") !== 0; ) { - (De(E), - De(Be), - this.handleError(dn(this.db, ee, -1, E, Be))); - var Re = fe(E, "i32"); - if (((ee = fe(Be, "i32")), Re !== 0)) { - var Se = null; - for ( - N = new s(Re, this), T != null && N.bind(T); - N.step(); - ) - (Se === null && - ((Se = { columns: N.Db(), values: [] }), m.push(Se)), - Se.values.push(N.get(null, L))); - N.cb(); - } - } - return m; - } catch (Oe) { - throw (N && N.cb(), Oe); - } finally { - W && St(W); - } - }), - (d.prototype.ec = function (m, T, L, N, W) { - (typeof T == "function" && ((N = L), (L = T), (T = void 0)), - (m = this.Gb(m, T))); - try { - for (; m.step(); ) L(m.Ob(null, W)); - } finally { - m.cb(); - } - if (typeof N == "function") return N(); - }), - (d.prototype.Gb = function (m, T) { - if ( - (De(E), - this.handleError(_e(this.db, m, -1, E, 0)), - (m = fe(E, "i32")), - m === 0) - ) - throw "Nothing to prepare"; - var L = new s(m, this); - return (T != null && L.bind(T), (this.pb[m] = L)); - }), - (d.prototype.pc = function (m) { - return new o(m, this); - }), - (d.prototype.fc = function () { - (Object.values(this.pb).forEach(function (T) { - T.cb(); - }), - Object.values(this.Sa).forEach(Ge), - (this.Sa = {}), - this.handleError(Q(this.db))); - var m = ls(this.filename); - return ( - this.handleError($(this.filename, E)), - (this.db = fe(E, "i32")), - yn(this.db), - m - ); - }), - (d.prototype.close = function () { - this.db !== null && - (Object.values(this.pb).forEach(function (m) { - m.cb(); - }), - Object.values(this.Sa).forEach(Ge), - (this.Sa = {}), - this.fb && (Ge(this.fb), (this.fb = void 0)), - this.handleError(Q(this.db)), - Jr("/" + this.filename), - (this.db = null)); - }), - (d.prototype.handleError = function (m) { - if (m === 0) return null; - throw ((m = vs(this.db)), Error(m)); - }), - (d.prototype.kc = function () { - return Y(this.db); - }), - (d.prototype.bc = function (m, T) { - Object.prototype.hasOwnProperty.call(this.Sa, m) && - (Ge(this.Sa[m]), delete this.Sa[m]); - var L = kt(function (N, W, ee) { - W = t(W, ee); - try { - var Be = T.apply(null, W); - } catch (Re) { - Zt(N, Re, -1); - return; - } - e(N, Be); - }, "viii"); - return ( - (this.Sa[m] = L), - this.handleError(gn(this.db, m, T.length, 1, 0, L, 0, 0, 0)), - this - ); - }), - (d.prototype.ac = function (m, T) { - var L = - T.init || - function () { - return null; - }, - N = - T.finalize || - function (Se) { - return Se; - }, - W = T.step; - if (!W) - throw ( - "An aggregate function must have a step function in " + m - ); - var ee = {}; - (Object.hasOwnProperty.call(this.Sa, m) && - (Ge(this.Sa[m]), delete this.Sa[m]), - (T = m + "__finalize"), - Object.hasOwnProperty.call(this.Sa, T) && - (Ge(this.Sa[T]), delete this.Sa[T])); - var Be = kt(function (Se, Oe, Er) { - var at = mn(Se, 1); - (Object.hasOwnProperty.call(ee, at) || (ee[at] = L()), - (Oe = t(Oe, Er)), - (Oe = [ee[at]].concat(Oe))); - try { - ee[at] = W.apply(null, Oe); - } catch (zs) { - (delete ee[at], Zt(Se, zs, -1)); - } - }, "viii"), - Re = kt(function (Se) { - var Oe = mn(Se, 1); - try { - var Er = N(ee[Oe]); - } catch (at) { - (delete ee[Oe], Zt(Se, at, -1)); - return; - } - (e(Se, Er), delete ee[Oe]); - }, "vi"); - return ( - (this.Sa[m] = Be), - (this.Sa[T] = Re), - this.handleError( - gn(this.db, m, W.length - 1, 1, 0, 0, Be, Re, 0) - ), - this - ); - }), - (d.prototype.vc = function (m) { - return ( - this.fb && - (bn(this.db, 0, 0), Ge(this.fb), (this.fb = void 0)), - m - ? ((this.fb = kt(function (T, L, N, W, ee) { - switch (L) { - case 18: - T = "insert"; - break; - case 23: - T = "update"; - break; - case 9: - T = "delete"; - break; - default: - throw ( - "unknown operationCode in updateHook callback: " + - L - ); - } - if ( - ((N = j(N)), (W = j(W)), ee > Number.MAX_SAFE_INTEGER) - ) - throw "rowId too big to fit inside a Number"; - m(T, N, W, Number(ee)); - }, "viiiij")), - bn(this.db, this.fb, 0), - this) - : this - ); - }), - (s.prototype.bind = s.prototype.bind), - (s.prototype.step = s.prototype.step), - (s.prototype.get = s.prototype.get), - (s.prototype.getColumnNames = s.prototype.Db), - (s.prototype.getAsObject = s.prototype.Ob), - (s.prototype.getSQL = s.prototype.lc), - (s.prototype.getNormalizedSQL = s.prototype.ic), - (s.prototype.run = s.prototype.Jb), - (s.prototype.reset = s.prototype.reset), - (s.prototype.freemem = s.prototype.Cb), - (s.prototype.free = s.prototype.cb), - (o.prototype.next = o.prototype.next), - (o.prototype.getRemainingSQL = o.prototype.jc), - (d.prototype.run = d.prototype.Jb), - (d.prototype.exec = d.prototype.exec), - (d.prototype.each = d.prototype.ec), - (d.prototype.prepare = d.prototype.Gb), - (d.prototype.iterateStatements = d.prototype.pc), - (d.prototype.export = d.prototype.fc), - (d.prototype.close = d.prototype.close), - (d.prototype.handleError = d.prototype.handleError), - (d.prototype.getRowsModified = d.prototype.kc), - (d.prototype.create_function = d.prototype.bc), - (d.prototype.create_aggregate = d.prototype.ac), - (d.prototype.updateHook = d.prototype.vc), - (a.Database = d)); - }; - var u = "./this.program", - p = - (pn = - (cn = globalThis.document) == null - ? void 0 - : cn.currentScript) == null - ? void 0 - : pn.src; - l && (p = self.location.href); - var h = "", - b, - k; - if (c || l) { - try { - h = new URL(".", p).href; - } catch (e) {} - (l && - (k = (e) => { - var t = new XMLHttpRequest(); - return ( - t.open("GET", e, !1), - (t.responseType = "arraybuffer"), - t.send(null), - new Uint8Array(t.response) - ); - }), - (b = async (e) => { - if ( - ((e = await fetch(e, { credentials: "same-origin" })), e.ok) - ) - return e.arrayBuffer(); - throw Error(e.status + " : " + e.url); - })); - } - var g = console.log.bind(console), - x = console.error.bind(console), - C, - R = !1, - S, - F, - B, - A, - v, - w, - O, - M, - I; - function J() { - var e = Wt.buffer; - ((F = new Int8Array(e)), - (A = new Int16Array(e)), - (B = new Uint8Array(e)), - new Uint16Array(e), - (v = new Int32Array(e)), - (w = new Uint32Array(e)), - (O = new Float32Array(e)), - (M = new Float64Array(e)), - (I = new BigInt64Array(e)), - new BigUint64Array(e)); - } - function q(e) { - var t; - throw ( - (t = a.onAbort) == null || t.call(a, e), - (e = "Aborted(" + e + ")"), - x(e), - (R = !0), - new WebAssembly.RuntimeError( - e + ". Build with -sASSERTIONS for more info." - ) - ); - } - var te; - async function se(e) { - if (!C) - try { - var t = await b(e); - return new Uint8Array(t); - } catch (s) {} - if (e == te && C) e = new Uint8Array(C); - else if (k) e = k(e); - else throw "both async and sync fetching of the wasm failed"; - return e; - } - async function G(e, t) { - try { - var s = await se(e); - return await WebAssembly.instantiate(s, t); - } catch (o) { - (x(`failed to asynchronously prepare wasm: ${o}`), q(o)); - } - } - async function ye(e) { - var t = te; - if (!C) - try { - var s = fetch(t, { credentials: "same-origin" }); - return await WebAssembly.instantiateStreaming(s, e); - } catch (o) { - (x(`wasm streaming compile failed: ${o}`), - x("falling back to ArrayBuffer instantiation")); - } - return G(t, e); - } - class ue { - constructor(t) { - Xe(this, "name", "ExitStatus"); - ((this.message = `Program terminated with exit(${t})`), - (this.status = t)); - } - } - var V = (e) => { - for (; 0 < e.length; ) e.shift()(a); - }, - U = [], - be = [], - we = () => { - var e = a.preRun.shift(); - be.push(e); - }, - ge = 0, - Ce = null; - function fe(e, t = "i8") { - switch ((t.endsWith("*") && (t = "*"), t)) { - case "i1": - return F[e]; - case "i8": - return F[e]; - case "i16": - return A[e >> 1]; - case "i32": - return v[e >> 2]; - case "i64": - return I[e >> 3]; - case "float": - return O[e >> 2]; - case "double": - return M[e >> 3]; - case "*": - return w[e >> 2]; - default: - q(`invalid type for getValue: ${t}`); - } - } - var Le = !0; - function De(e) { - var t = "i32"; - switch ((t.endsWith("*") && (t = "*"), t)) { - case "i1": - F[e] = 0; - break; - case "i8": - F[e] = 0; - break; - case "i16": - A[e >> 1] = 0; - break; - case "i32": - v[e >> 2] = 0; - break; - case "i64": - I[e >> 3] = BigInt(0); - break; - case "float": - O[e >> 2] = 0; - break; - case "double": - M[e >> 3] = 0; - break; - case "*": - w[e >> 2] = 0; - break; - default: - q(`invalid type for setValue: ${t}`); - } - } - var Ie = new TextDecoder(), - K = (e, t, s, o) => { - if (((s = t + s), o)) return s; - for (; e[t] && !(t >= s); ) ++t; - return t; - }, - j = (e, t, s) => (e ? Ie.decode(B.subarray(e, K(B, e, t, s))) : ""), - ke = (e, t) => { - for (var s = 0, o = e.length - 1; 0 <= o; o--) { - var d = e[o]; - d === "." - ? e.splice(o, 1) - : d === ".." - ? (e.splice(o, 1), s++) - : s && (e.splice(o, 1), s--); - } - if (t) for (; s; s--) e.unshift(".."); - return e; - }, - ce = (e) => { - var t = e.charAt(0) === "/", - s = e.slice(-1) === "/"; - return ( - (e = ke( - e.split("/").filter((o) => !!o), - !t - ).join("/")) || - t || - (e = "."), - e && s && (e += "/"), - (t ? "/" : "") + e - ); - }, - Ae = (e) => { - var t = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/ - .exec(e) - .slice(1); - return ( - (e = t[0]), - (t = t[1]), - !e && !t ? "." : (t && (t = t.slice(0, -1)), e + t) - ); - }, - Ne = (e) => e && e.match(/([^\/]+|\/)\/*$/)[1], - vt = () => (e) => crypto.getRandomValues(e), - Lr = (e) => { - (Lr = vt())(e); - }, - Xn = (...e) => { - for (var t = "", s = !1, o = e.length - 1; -1 <= o && !s; o--) { - if (((s = 0 <= o ? e[o] : "/"), typeof s != "string")) - throw new TypeError( - "Arguments to path.resolve must be strings" - ); - if (!s) return ""; - ((t = s + "/" + t), (s = s.charAt(0) === "/")); - } - return ( - (t = ke( - t.split("/").filter((d) => !!d), - !s - ).join("/")), - (s ? "/" : "") + t || "." - ); - }, - Et = (e) => { - var t = K(e, 0); - return Ie.decode( - e.buffer ? e.subarray(0, t) : new Uint8Array(e.slice(0, t)) - ); - }, - ir = [], - pt = (e) => { - for (var t = 0, s = 0; s < e.length; ++s) { - var o = e.charCodeAt(s); - 127 >= o - ? t++ - : 2047 >= o - ? (t += 2) - : 55296 <= o && 57343 >= o - ? ((t += 4), ++s) - : (t += 3); - } - return t; - }, - je = (e, t, s, o) => { - if (!(0 < o)) return 0; - var d = s; - o = s + o - 1; - for (var E = 0; E < e.length; ++E) { - var P = e.codePointAt(E); - if (127 >= P) { - if (s >= o) break; - t[s++] = P; - } else if (2047 >= P) { - if (s + 1 >= o) break; - ((t[s++] = 192 | (P >> 6)), (t[s++] = 128 | (P & 63))); - } else if (65535 >= P) { - if (s + 2 >= o) break; - ((t[s++] = 224 | (P >> 12)), - (t[s++] = 128 | ((P >> 6) & 63)), - (t[s++] = 128 | (P & 63))); - } else { - if (s + 3 >= o) break; - ((t[s++] = 240 | (P >> 18)), - (t[s++] = 128 | ((P >> 12) & 63)), - (t[s++] = 128 | ((P >> 6) & 63)), - (t[s++] = 128 | (P & 63)), - E++); - } - } - return ((t[s] = 0), s - d); - }, - Ir = []; - function Nr(e, t) { - ((Ir[e] = { input: [], output: [], kb: t }), dr(e, Yn)); - } - var Yn = { - open(e) { - var t = Ir[e.node.nb]; - if (!t) throw new D(43); - ((e.Va = t), (e.seekable = !1)); - }, - close(e) { - e.Va.kb.lb(e.Va); - }, - lb(e) { - e.Va.kb.lb(e.Va); - }, - read(e, t, s, o) { - if (!e.Va || !e.Va.kb.Qb) throw new D(60); - for (var d = 0, E = 0; E < o; E++) { - try { - var P = e.Va.kb.Qb(e.Va); - } catch ($) { - throw new D(29); - } - if (P === void 0 && d === 0) throw new D(6); - if (P == null) break; - (d++, (t[s + E] = P)); - } - return (d && (e.node.$a = Date.now()), d); - }, - write(e, t, s, o) { - if (!e.Va || !e.Va.kb.Hb) throw new D(60); - try { - for (var d = 0; d < o; d++) e.Va.kb.Hb(e.Va, t[s + d]); - } catch (E) { - throw new D(29); - } - return (o && (e.node.Ua = e.node.Ta = Date.now()), d); - }, - }, - es = { - Qb() { - var s; - e: { - if (!ir.length) { - var e = null; - if ( - ((s = globalThis.window) != null && - s.prompt && - ((e = window.prompt("Input: ")), - e !== null && - (e += ` -`)), - !e) - ) { - var t = null; - break e; - } - ((t = Array(pt(e) + 1)), - (e = je(e, t, 0, t.length)), - (t.length = e), - (ir = t)); - } - t = ir.shift(); - } - return t; - }, - Hb(e, t) { - t === null || t === 10 - ? (g(Et(e.output)), (e.output = [])) - : t != 0 && e.output.push(t); - }, - lb(e) { - var t; - 0 < ((t = e.output) == null ? void 0 : t.length) && - (g(Et(e.output)), (e.output = [])); - }, - Dc() { - return { - yc: 25856, - Ac: 5, - xc: 191, - zc: 35387, - wc: [ - 3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - }; - }, - Ec() { - return 0; - }, - Fc() { - return [24, 80]; - }, - }, - ts = { - Hb(e, t) { - t === null || t === 10 - ? (x(Et(e.output)), (e.output = [])) - : t != 0 && e.output.push(t); - }, - lb(e) { - var t; - 0 < ((t = e.output) == null ? void 0 : t.length) && - (x(Et(e.output)), (e.output = [])); - }, - }, - H = { - Za: null, - ab() { - return H.createNode(null, "/", 16895, 0); - }, - createNode(e, t, s, o) { - if ((s & 61440) === 24576 || (s & 61440) === 4096) - throw new D(63); - return ( - H.Za || - (H.Za = { - dir: { - node: { - Wa: H.La.Wa, - Xa: H.La.Xa, - mb: H.La.mb, - rb: H.La.rb, - Tb: H.La.Tb, - xb: H.La.xb, - vb: H.La.vb, - Ib: H.La.Ib, - wb: H.La.wb, - }, - stream: { Ya: H.Ma.Ya }, - }, - file: { - node: { Wa: H.La.Wa, Xa: H.La.Xa }, - stream: { - Ya: H.Ma.Ya, - read: H.Ma.read, - write: H.Ma.write, - sb: H.Ma.sb, - tb: H.Ma.tb, - }, - }, - link: { - node: { Wa: H.La.Wa, Xa: H.La.Xa, eb: H.La.eb }, - stream: {}, - }, - Nb: { node: { Wa: H.La.Wa, Xa: H.La.Xa }, stream: is }, - }), - (s = qr(e, t, s, o)), - Ee(s.mode) - ? ((s.La = H.Za.dir.node), - (s.Ma = H.Za.dir.stream), - (s.Na = {})) - : (s.mode & 61440) === 32768 - ? ((s.La = H.Za.file.node), - (s.Ma = H.Za.file.stream), - (s.Ra = 0), - (s.Na = null)) - : (s.mode & 61440) === 40960 - ? ((s.La = H.Za.link.node), (s.Ma = H.Za.link.stream)) - : (s.mode & 61440) === 8192 && - ((s.La = H.Za.Nb.node), (s.Ma = H.Za.Nb.stream)), - (s.$a = s.Ua = s.Ta = Date.now()), - e && ((e.Na[t] = s), (e.$a = e.Ua = e.Ta = s.$a)), - s - ); - }, - Cc(e) { - return e.Na - ? e.Na.subarray - ? e.Na.subarray(0, e.Ra) - : new Uint8Array(e.Na) - : new Uint8Array(0); - }, - La: { - Wa(e) { - var t = {}; - return ( - (t.cc = (e.mode & 61440) === 8192 ? e.id : 1), - (t.oc = e.id), - (t.mode = e.mode), - (t.rc = 1), - (t.uid = 0), - (t.nc = 0), - (t.nb = e.nb), - Ee(e.mode) - ? (t.size = 4096) - : (e.mode & 61440) === 32768 - ? (t.size = e.Ra) - : (e.mode & 61440) === 40960 - ? (t.size = e.link.length) - : (t.size = 0), - (t.$a = new Date(e.$a)), - (t.Ua = new Date(e.Ua)), - (t.Ta = new Date(e.Ta)), - (t.Zb = 4096), - (t.$b = Math.ceil(t.size / t.Zb)), - t - ); - }, - Xa(e, t) { - for (var s of ["mode", "atime", "mtime", "ctime"]) - t[s] != null && (e[s] = t[s]); - t.size !== void 0 && - ((t = t.size), - e.Ra != t && - (t == 0 - ? ((e.Na = null), (e.Ra = 0)) - : ((s = e.Na), - (e.Na = new Uint8Array(t)), - s && e.Na.set(s.subarray(0, Math.min(t, e.Ra))), - (e.Ra = t)))); - }, - mb() { - throw ( - H.zb || - ((H.zb = new D(44)), - (H.zb.stack = "")), - H.zb - ); - }, - rb(e, t, s, o) { - return H.createNode(e, t, s, o); - }, - Tb(e, t, s) { - try { - var o = tt(t, s); - } catch (E) {} - if (o) { - if (Ee(e.mode)) for (var d in o.Na) throw new D(55); - pr(o); - } - (delete e.parent.Na[e.name], - (t.Na[s] = e), - (e.name = s), - (t.Ta = t.Ua = e.parent.Ta = e.parent.Ua = Date.now())); - }, - xb(e, t) { - (delete e.Na[t], (e.Ta = e.Ua = Date.now())); - }, - vb(e, t) { - var s = tt(e, t), - o; - for (o in s.Na) throw new D(55); - (delete e.Na[t], (e.Ta = e.Ua = Date.now())); - }, - Ib(e) { - return [".", "..", ...Object.keys(e.Na)]; - }, - wb(e, t, s) { - return ((e = H.createNode(e, t, 41471, 0)), (e.link = s), e); - }, - eb(e) { - if ((e.mode & 61440) !== 40960) throw new D(28); - return e.link; - }, - }, - Ma: { - read(e, t, s, o, d) { - var E = e.node.Na; - if (d >= e.node.Ra) return 0; - if (((e = Math.min(e.node.Ra - d, o)), 8 < e && E.subarray)) - t.set(E.subarray(d, d + e), s); - else for (o = 0; o < e; o++) t[s + o] = E[d + o]; - return e; - }, - write(e, t, s, o, d, E) { - if ((t.buffer === F.buffer && (E = !1), !o)) return 0; - if ( - ((e = e.node), - (e.Ua = e.Ta = Date.now()), - t.subarray && (!e.Na || e.Na.subarray)) - ) { - if (E) return ((e.Na = t.subarray(s, s + o)), (e.Ra = o)); - if (e.Ra === 0 && d === 0) - return ((e.Na = t.slice(s, s + o)), (e.Ra = o)); - if (d + o <= e.Ra) - return (e.Na.set(t.subarray(s, s + o), d), o); - } - E = d + o; - var P = e.Na ? e.Na.length : 0; - if ( - (P >= E || - ((E = Math.max(E, (P * (1048576 > P ? 2 : 1.125)) >>> 0)), - P != 0 && (E = Math.max(E, 256)), - (P = e.Na), - (e.Na = new Uint8Array(E)), - 0 < e.Ra && e.Na.set(P.subarray(0, e.Ra), 0)), - e.Na.subarray && t.subarray) - ) - e.Na.set(t.subarray(s, s + o), d); - else for (E = 0; E < o; E++) e.Na[d + E] = t[s + E]; - return ((e.Ra = Math.max(e.Ra, d + o)), o); - }, - Ya(e, t, s) { - if ( - (s === 1 - ? (t += e.position) - : s === 2 && - (e.node.mode & 61440) === 32768 && - (t += e.node.Ra), - 0 > t) - ) - throw new D(28); - return t; - }, - sb(e, t, s, o, d) { - if ((e.node.mode & 61440) !== 32768) throw new D(43); - if (((e = e.node.Na), d & 2 || !e || e.buffer !== F.buffer)) { - ((d = !0), (o = 65536 * Math.ceil(t / 65536))); - var E = on(65536, o); - if ((E && B.fill(0, E, E + o), (o = E), !o)) - throw new D(48); - e && - ((0 < s || s + t < e.length) && - (e.subarray - ? (e = e.subarray(s, s + t)) - : (e = Array.prototype.slice.call(e, s, s + t))), - F.set(e, o)); - } else ((d = !1), (o = e.byteOffset)); - return { tc: o, Ub: d }; - }, - tb(e, t, s, o) { - return (H.Ma.write(e, t, 0, o, s, !1), 0); - }, - }, - }, - jr = (e, t) => { - var s = 0; - return (e && (s |= 365), t && (s |= 146), s); - }, - or = null, - zr = {}, - ut = [], - rs = 1, - Ze = null, - $r = !1, - Vr = !0, - D = class { - constructor(e) { - Xe(this, "name", "ErrnoError"); - this.Pa = e; - } - }, - ns = class { - constructor() { - Xe(this, "qb", {}); - Xe(this, "node", null); - } - get flags() { - return this.qb.flags; - } - set flags(e) { - this.qb.flags = e; - } - get position() { - return this.qb.position; - } - set position(e) { - this.qb.position = e; - } - }, - ss = class { - constructor(e, t, s, o) { - Xe(this, "La", {}); - Xe(this, "Ma", {}); - Xe(this, "ib", null); - (e || (e = this), - (this.parent = e), - (this.ab = e.ab), - (this.id = rs++), - (this.name = t), - (this.mode = s), - (this.nb = o), - (this.$a = this.Ua = this.Ta = Date.now())); - } - get read() { - return (this.mode & 365) === 365; - } - set read(e) { - e ? (this.mode |= 365) : (this.mode &= -366); - } - get write() { - return (this.mode & 146) === 146; - } - set write(e) { - e ? (this.mode |= 146) : (this.mode &= -147); - } - }; - function Fe(e, t = {}) { - var $; - if (!e) throw new D(44); - (($ = t.Bb) != null || (t.Bb = !0), - e.charAt(0) === "/" || (e = "//" + e)); - var s = 0; - e: for (; 40 > s; s++) { - e = e.split("/").filter((Q) => !!Q); - for (var o = or, d = "/", E = 0; E < e.length; E++) { - var P = E === e.length - 1; - if (P && t.parent) break; - if (e[E] !== ".") - if (e[E] === "..") - if (((d = Ae(d)), o === o.parent)) { - ((e = d + "/" + e.slice(E + 1).join("/")), s--); - continue e; - } else o = o.parent; - else { - d = ce(d + "/" + e[E]); - try { - o = tt(o, e[E]); - } catch (Q) { - if ((Q == null ? void 0 : Q.Pa) === 44 && P && t.sc) - return { path: d }; - throw Q; - } - if ( - (!o.ib || (P && !t.Bb) || (o = o.ib.root), - (o.mode & 61440) === 40960 && (!P || t.hb)) - ) { - if (!o.La.eb) throw new D(52); - ((o = o.La.eb(o)), - o.charAt(0) === "/" || (o = Ae(d) + "/" + o), - (e = o + "/" + e.slice(E + 1).join("/"))); - continue e; - } - } - } - return { path: d, node: o }; - } - throw new D(32); - } - function lr(e) { - for (var t; ; ) { - if (e === e.parent) - return ( - (e = e.ab.Sb), - t ? (e[e.length - 1] !== "/" ? `${e}/${t}` : e + t) : e - ); - ((t = t ? `${e.name}/${t}` : e.name), (e = e.parent)); - } - } - function cr(e, t) { - for (var s = 0, o = 0; o < t.length; o++) - s = ((s << 5) - s + t.charCodeAt(o)) | 0; - return ((e + s) >>> 0) % Ze.length; - } - function pr(e) { - var t = cr(e.parent.id, e.name); - if (Ze[t] === e) Ze[t] = e.jb; - else - for (t = Ze[t]; t; ) { - if (t.jb === e) { - t.jb = e.jb; - break; - } - t = t.jb; - } - } - function tt(e, t) { - var s = Ee(e.mode) ? ((s = dt(e, "x")) ? s : e.La.mb ? 0 : 2) : 54; - if (s) throw new D(s); - for (s = Ze[cr(e.id, t)]; s; s = s.jb) { - var o = s.name; - if (s.parent.id === e.id && o === t) return s; - } - return e.La.mb(e, t); - } - function qr(e, t, s, o) { - return ( - (e = new ss(e, t, s, o)), - (t = cr(e.parent.id, e.name)), - (e.jb = Ze[t]), - (Ze[t] = e) - ); - } - function Ee(e) { - return (e & 61440) === 16384; - } - function dt(e, t) { - return Vr - ? 0 - : (t.includes("r") && !(e.mode & 292)) || - (t.includes("w") && !(e.mode & 146)) || - (t.includes("x") && !(e.mode & 73)) - ? 2 - : 0; - } - function Hr(e, t) { - if (!Ee(e.mode)) return 54; - try { - return (tt(e, t), 20); - } catch (s) {} - return dt(e, "wx"); - } - function Kr(e, t, s) { - try { - var o = tt(e, t); - } catch (d) { - return d.Pa; - } - if ((e = dt(e, "wx"))) return e; - if (s) { - if (!Ee(o.mode)) return 54; - if (o === o.parent || lr(o) === "/") return 10; - } else if (Ee(o.mode)) return 31; - return 0; - } - function Lt(e) { - if (!e) throw new D(63); - return e; - } - function ve(e) { - if (((e = ut[e]), !e)) throw new D(8); - return e; - } - function Ur(e, t = -1) { - if (((e = Object.assign(new ns(), e)), t == -1)) - e: { - for (t = 0; 4096 >= t; t++) if (!ut[t]) break e; - throw new D(33); - } - return ((e.bb = t), (ut[t] = e)); - } - function as(e, t = -1) { - var s, o; - return ( - (e = Ur(e, t)), - (o = (s = e.Ma) == null ? void 0 : s.Bc) == null || o.call(s, e), - e - ); - } - function ur(e, t, s) { - var o = e == null ? void 0 : e.Ma.Xa; - ((e = o ? e : t), o != null || (o = t.La.Xa), Lt(o), o(e, s)); - } - var is = { - open(e) { - var t, s; - ((e.Ma = zr[e.node.nb].Ma), - (s = (t = e.Ma).open) == null || s.call(t, e)); - }, - Ya() { - throw new D(70); - }, - }; - function dr(e, t) { - zr[e] = { Ma: t }; - } - function Wr(e, t) { - var s = t === "/"; - if (s && or) throw new D(10); - if (!s && t) { - var o = Fe(t, { Bb: !1 }); - if (((t = o.path), (o = o.node), o.ib)) throw new D(10); - if (!Ee(o.mode)) throw new D(54); - } - ((t = { type: e, Gc: {}, Sb: t, qc: [] }), - (e = e.ab(t)), - (e.ab = t), - (t.root = e), - s ? (or = e) : o && ((o.ib = t), o.ab && o.ab.qc.push(t))); - } - function It(e, t, s) { - var o = Fe(e, { parent: !0 }).node; - if (((e = Ne(e)), !e)) throw new D(28); - if (e === "." || e === "..") throw new D(20); - var d = Hr(o, e); - if (d) throw new D(d); - if (!o.La.rb) throw new D(63); - return o.La.rb(o, e, t, s); - } - function os(e, t = 438) { - return It(e, (t & 4095) | 32768, 0); - } - function ze(e, t = 511) { - return It(e, (t & 1023) | 16384, 0); - } - function Nt(e, t, s) { - (typeof s == "undefined" && ((s = t), (t = 438)), - It(e, t | 8192, s)); - } - function fr(e, t) { - if (!Xn(e)) throw new D(44); - var s = Fe(t, { parent: !0 }).node; - if (!s) throw new D(44); - t = Ne(t); - var o = Hr(s, t); - if (o) throw new D(o); - if (!s.La.wb) throw new D(63); - s.La.wb(s, t, e); - } - function Zr(e) { - var t = Fe(e, { parent: !0 }).node; - e = Ne(e); - var s = tt(t, e), - o = Kr(t, e, !0); - if (o) throw new D(o); - if (!t.La.vb) throw new D(63); - if (s.ib) throw new D(10); - (t.La.vb(t, e), pr(s)); - } - function Jr(e) { - var t = Fe(e, { parent: !0 }).node; - if (!t) throw new D(44); - e = Ne(e); - var s = tt(t, e), - o = Kr(t, e, !1); - if (o) throw new D(o); - if (!t.La.xb) throw new D(63); - if (s.ib) throw new D(10); - (t.La.xb(t, e), pr(s)); - } - function xt(e, t) { - return ((e = Fe(e, { hb: !t }).node), Lt(e.La.Wa)(e)); - } - function Gr(e, t, s, o) { - ur(e, t, { - mode: (s & 4095) | (t.mode & -4096), - Ta: Date.now(), - dc: o, - }); - } - function jt(e, t) { - ((e = typeof e == "string" ? Fe(e, { hb: !0 }).node : e), - Gr(null, e, t)); - } - function Qr(e, t, s) { - if (Ee(t.mode)) throw new D(31); - if ((t.mode & 61440) !== 32768) throw new D(28); - var o = dt(t, "w"); - if (o) throw new D(o); - ur(e, t, { size: s, timestamp: Date.now() }); - } - function ft(e, t, s = 438) { - if (e === "") throw new D(44); - if (typeof t == "string") { - var o = { r: 0, "r+": 2, w: 577, "w+": 578, a: 1089, "a+": 1090 }[ - t - ]; - if (typeof o == "undefined") - throw Error(`Unknown file open mode: ${t}`); - t = o; - } - if (((s = t & 64 ? (s & 4095) | 32768 : 0), typeof e == "object")) - o = e; - else { - var d = e.endsWith("/"), - E = Fe(e, { hb: !(t & 131072), sc: !0 }); - ((o = E.node), (e = E.path)); - } - if (((E = !1), t & 64)) - if (o) { - if (t & 128) throw new D(20); - } else { - if (d) throw new D(31); - ((o = It(e, s | 511, 0)), (E = !0)); - } - if (!o) throw new D(44); - if ( - ((o.mode & 61440) === 8192 && (t &= -513), - t & 65536 && !Ee(o.mode)) - ) - throw new D(54); - if ( - !E && - (o - ? (o.mode & 61440) === 40960 - ? (d = 32) - : ((d = ["r", "w", "rw"][t & 3]), - t & 512 && (d += "w"), - (d = Ee(o.mode) && (d !== "r" || t & 576) ? 31 : dt(o, d))) - : (d = 44), - d) - ) - throw new D(d); - return ( - t & 512 && - !E && - ((d = o), - (d = typeof d == "string" ? Fe(d, { hb: !0 }).node : d), - Qr(null, d, 0)), - (t = Ur({ - node: o, - path: lr(o), - flags: t & -131713, - seekable: !0, - position: 0, - Ma: o.Ma, - uc: [], - error: !1, - })), - t.Ma.open && t.Ma.open(t), - E && jt(o, s & 511), - t - ); - } - function hr(e) { - if (e.bb === null) throw new D(8); - e.Eb && (e.Eb = null); - try { - e.Ma.close && e.Ma.close(e); - } catch (t) { - throw t; - } finally { - ut[e.bb] = null; - } - e.bb = null; - } - function Xr(e, t, s) { - if (e.bb === null) throw new D(8); - if (!e.seekable || !e.Ma.Ya) throw new D(70); - if (s != 0 && s != 1 && s != 2) throw new D(28); - ((e.position = e.Ma.Ya(e, t, s)), (e.uc = [])); - } - function Yr(e, t, s, o, d) { - if (0 > o || 0 > d) throw new D(28); - if (e.bb === null) throw new D(8); - if ((e.flags & 2097155) === 1) throw new D(8); - if (Ee(e.node.mode)) throw new D(31); - if (!e.Ma.read) throw new D(28); - var E = typeof d != "undefined"; - if (!E) d = e.position; - else if (!e.seekable) throw new D(70); - return ((t = e.Ma.read(e, t, s, o, d)), E || (e.position += t), t); - } - function en(e, t, s, o, d) { - if (0 > o || 0 > d) throw new D(28); - if (e.bb === null) throw new D(8); - if ((e.flags & 2097155) === 0) throw new D(8); - if (Ee(e.node.mode)) throw new D(31); - if (!e.Ma.write) throw new D(28); - e.seekable && e.flags & 1024 && Xr(e, 0, 2); - var E = typeof d != "undefined"; - if (!E) d = e.position; - else if (!e.seekable) throw new D(70); - return ( - (t = e.Ma.write(e, t, s, o, d, void 0)), - E || (e.position += t), - t - ); - } - function ls(e) { - var t = t || 0, - s = "binary"; - (s !== "utf8" && - s !== "binary" && - q(`Invalid encoding type "${s}"`), - (t = ft(e, t)), - (e = xt(e).size)); - var o = new Uint8Array(e); - return (Yr(t, o, 0, e, 0), s === "utf8" && (o = Et(o)), hr(t), o); - } - function Je(e, t, s) { - var E; - e = ce("/dev/" + e); - var o = jr(!!t, !!s); - (E = Je.Rb) != null || (Je.Rb = 64); - var d = (Je.Rb++ << 8) | 0; - (dr(d, { - open(P) { - P.seekable = !1; - }, - close() { - var P; - (P = s == null ? void 0 : s.buffer) != null && - P.length && - s(10); - }, - read(P, $, Q, Z) { - for (var Y = 0, _e = 0; _e < Z; _e++) { - try { - var ht = t(); - } catch (un) { - throw new D(29); - } - if (ht === void 0 && Y === 0) throw new D(6); - if (ht == null) break; - (Y++, ($[Q + _e] = ht)); - } - return (Y && (P.node.$a = Date.now()), Y); - }, - write(P, $, Q, Z) { - for (var Y = 0; Y < Z; Y++) - try { - s($[Q + Y]); - } catch (_e) { - throw new D(29); - } - return (Z && (P.node.Ua = P.node.Ta = Date.now()), Y); - }, - }), - Nt(e, o, d)); - } - var ne = {}; - function rt(e, t, s) { - if (t.charAt(0) === "/") return t; - if (((e = e === -100 ? "/" : ve(e).path), t.length == 0)) { - if (!s) throw new D(44); - return e; - } - return e + "/" + t; - } - function zt(e, t) { - ((w[e >> 2] = t.cc), - (w[(e + 4) >> 2] = t.mode), - (w[(e + 8) >> 2] = t.rc), - (w[(e + 12) >> 2] = t.uid), - (w[(e + 16) >> 2] = t.nc), - (w[(e + 20) >> 2] = t.nb), - (I[(e + 24) >> 3] = BigInt(t.size)), - (v[(e + 32) >> 2] = 4096), - (v[(e + 36) >> 2] = t.$b)); - var s = t.$a.getTime(), - o = t.Ua.getTime(), - d = t.Ta.getTime(); - return ( - (I[(e + 40) >> 3] = BigInt(Math.floor(s / 1e3))), - (w[(e + 48) >> 2] = (s % 1e3) * 1e6), - (I[(e + 56) >> 3] = BigInt(Math.floor(o / 1e3))), - (w[(e + 64) >> 2] = (o % 1e3) * 1e6), - (I[(e + 72) >> 3] = BigInt(Math.floor(d / 1e3))), - (w[(e + 80) >> 2] = (d % 1e3) * 1e6), - (I[(e + 88) >> 3] = BigInt(t.oc)), - 0 - ); - } - var $t = void 0, - Vt = () => { - var e = v[+$t >> 2]; - return (($t += 4), e); - }, - gr = 0, - cs = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335], - ps = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], - wt = {}, - tn = (e) => { - if (!(e instanceof ue || e == "unwind")) throw e; - }, - rn = (e) => { - var t; - throw ( - (S = e), - Le || - 0 < gr || - ((t = a.onExit) == null || t.call(a, e), (R = !0)), - new ue(e) - ); - }, - us = (e) => { - if (!R) - try { - e(); - } catch (t) { - tn(t); - } finally { - if (!(Le || 0 < gr)) - try { - ((S = e = S), rn(e)); - } catch (t) { - tn(t); - } - } - }, - _r = {}, - nn = () => { - var o, d; - if (!mr) { - var e = { - USER: "web_user", - LOGNAME: "web_user", - PATH: "/", - PWD: "/", - HOME: "/home/web_user", - LANG: - ((d = - (o = globalThis.navigator) == null - ? void 0 - : o.language) != null - ? d - : "C" - ).replace("-", "_") + ".UTF-8", - _: u || "./this.program", - }, - t; - for (t in _r) _r[t] === void 0 ? delete e[t] : (e[t] = _r[t]); - var s = []; - for (t in e) s.push(`${t}=${e[t]}`); - mr = s; - } - return mr; - }, - mr, - ds = (e, t, s, o) => { - var d = { - string: (Z) => { - var Y = 0; - if (Z != null && Z !== 0) { - Y = pt(Z) + 1; - var _e = st(Y); - (je(Z, B, _e, Y), (Y = _e)); - } - return Y; - }, - array: (Z) => { - var Y = st(Z.length); - return (F.set(Z, Y), Y); - }, - }; - e = a["_" + e]; - var E = [], - P = 0; - if (o) - for (var $ = 0; $ < o.length; $++) { - var Q = d[s[$]]; - Q ? (P === 0 && (P = Ut()), (E[$] = Q(o[$]))) : (E[$] = o[$]); - } - return ( - (s = e(...E)), - (s = (function (Z) { - return ( - P !== 0 && Kt(P), - t === "string" ? j(Z) : t === "boolean" ? !!Z : Z - ); - })(s)) - ); - }, - qt = (e) => { - var t = pt(e) + 1, - s = Ht(t); - return (s && je(e, B, s, t), s); - }, - nt, - yr = [], - Ge = (e) => { - (nt.delete(Qe.get(e)), Qe.set(e, null), yr.push(e)); - }, - sn = (e) => { - let t = e.length; - return [(t % 128) | 128, t >> 7, ...e]; - }, - fs = { i: 127, p: 127, j: 126, f: 125, d: 124, e: 111 }, - an = (e) => sn(Array.from(e, (t) => fs[t])), - kt = (e, t) => { - if (!nt) { - nt = new WeakMap(); - var s = Qe.length; - if (nt) - for (var o = 0; o < 0 + s; o++) { - var d = Qe.get(o); - d && nt.set(d, o); - } - } - if ((s = nt.get(e) || 0)) return s; - s = yr.length ? yr.pop() : Qe.grow(1); - try { - Qe.set(s, e); - } catch (E) { - if (!(E instanceof TypeError)) throw E; - ((t = Uint8Array.of( - 0, - 97, - 115, - 109, - 1, - 0, - 0, - 0, - 1, - ...sn([ - 1, - 96, - ...an(t.slice(1)), - ...an(t[0] === "v" ? "" : t[0]), - ]), - 2, - 7, - 1, - 1, - 101, - 1, - 102, - 0, - 0, - 7, - 5, - 1, - 1, - 102, - 0, - 0 - )), - (t = new WebAssembly.Module(t)), - (t = new WebAssembly.Instance(t, { e: { f: e } }).exports.f), - Qe.set(s, t)); - } - return (nt.set(e, s), s); - }; - if ( - ((Ze = Array(4096)), - Wr(H, "/"), - ze("/tmp"), - ze("/home"), - ze("/home/web_user"), - (function () { - (ze("/dev"), - dr(259, { - read: () => 0, - write: (o, d, E, P) => P, - Ya: () => 0, - }), - Nt("/dev/null", 259), - Nr(1280, es), - Nr(1536, ts), - Nt("/dev/tty", 1280), - Nt("/dev/tty1", 1536)); - var e = new Uint8Array(1024), - t = 0, - s = () => (t === 0 && (Lr(e), (t = e.byteLength)), e[--t]); - (Je("random", s), - Je("urandom", s), - ze("/dev/shm"), - ze("/dev/shm/tmp")); - })(), - (function () { - ze("/proc"); - var e = ze("/proc/self"); - (ze("/proc/self/fd"), - Wr( - { - ab() { - var t = qr(e, "fd", 16895, 73); - return ( - (t.Ma = { Ya: H.Ma.Ya }), - (t.La = { - mb(s, o) { - s = +o; - var d = ve(s); - return ( - (s = { - parent: null, - ab: { Sb: "fake" }, - La: { eb: () => d.path }, - id: s + 1, - }), - (s.parent = s) - ); - }, - Ib() { - return Array.from(ut.entries()) - .filter(([, s]) => s) - .map(([s]) => s.toString()); - }, - }), - t - ); - }, - }, - "/proc/self/fd" - )); - })(), - a.noExitRuntime && (Le = a.noExitRuntime), - a.print && (g = a.print), - a.printErr && (x = a.printErr), - a.wasmBinary && (C = a.wasmBinary), - a.thisProgram && (u = a.thisProgram), - a.preInit) - ) - for ( - typeof a.preInit == "function" && (a.preInit = [a.preInit]); - 0 < a.preInit.length; - ) - a.preInit.shift()(); - ((a.stackSave = () => Ut()), - (a.stackRestore = (e) => Kt(e)), - (a.stackAlloc = (e) => st(e)), - (a.cwrap = (e, t, s, o) => { - var d = !s || s.every((E) => E === "number" || E === "boolean"); - return t !== "string" && d && !o - ? a["_" + e] - : (...E) => ds(e, t, s, E); - }), - (a.addFunction = kt), - (a.removeFunction = Ge), - (a.UTF8ToString = j), - (a.stringToNewUTF8 = qt), - (a.writeArrayToMemory = (e, t) => { - F.set(e, t); - })); - var Ht, - St, - on, - ln, - Kt, - st, - Ut, - Wt, - Qe, - hs = { - a: (e, t, s, o) => - q( - `Assertion failed: ${j(e)}, at: ` + - [ - t ? j(t) : "unknown filename", - s, - o ? j(o) : "unknown function", - ] - ), - i: function (e, t) { - try { - return ((e = j(e)), jt(e, t), 0); - } catch (s) { - if (typeof ne == "undefined" || s.name !== "ErrnoError") - throw s; - return -s.Pa; - } - }, - L: function (e, t, s) { - try { - if (((t = j(t)), (t = rt(e, t)), s & -8)) return -28; - var o = Fe(t, { hb: !0 }).node; - return o - ? ((e = ""), - s & 4 && (e += "r"), - s & 2 && (e += "w"), - s & 1 && (e += "x"), - e && dt(o, e) ? -2 : 0) - : -44; - } catch (d) { - if (typeof ne == "undefined" || d.name !== "ErrnoError") - throw d; - return -d.Pa; - } - }, - j: function (e, t) { - try { - var s = ve(e); - return (Gr(s, s.node, t, !1), 0); - } catch (o) { - if (typeof ne == "undefined" || o.name !== "ErrnoError") - throw o; - return -o.Pa; - } - }, - h: function (e) { - try { - var t = ve(e); - return (ur(t, t.node, { timestamp: Date.now(), dc: !1 }), 0); - } catch (s) { - if (typeof ne == "undefined" || s.name !== "ErrnoError") - throw s; - return -s.Pa; - } - }, - b: function (e, t, s) { - $t = s; - try { - var o = ve(e); - switch (t) { - case 0: - var d = Vt(); - if (0 > d) break; - for (; ut[d]; ) d++; - return as(o, d).bb; - case 1: - case 2: - return 0; - case 3: - return o.flags; - case 4: - return ((d = Vt()), (o.flags |= d), 0); - case 12: - return ((d = Vt()), (A[(d + 0) >> 1] = 2), 0); - case 13: - case 14: - return 0; - } - return -28; - } catch (E) { - if (typeof ne == "undefined" || E.name !== "ErrnoError") - throw E; - return -E.Pa; - } - }, - g: function (e, t) { - try { - var s = ve(e), - o = s.node, - d = s.Ma.Wa; - ((e = d ? s : o), d != null || (d = o.La.Wa), Lt(d)); - var E = d(e); - return zt(t, E); - } catch (P) { - if (typeof ne == "undefined" || P.name !== "ErrnoError") - throw P; - return -P.Pa; - } - }, - H: function (e, t) { - t = - -9007199254740992 > t || 9007199254740992 < t - ? NaN - : Number(t); - try { - if (isNaN(t)) return -61; - var s = ve(e); - if (0 > t || (s.flags & 2097155) === 0) throw new D(28); - return (Qr(s, s.node, t), 0); - } catch (o) { - if (typeof ne == "undefined" || o.name !== "ErrnoError") - throw o; - return -o.Pa; - } - }, - G: function (e, t) { - try { - if (t === 0) return -28; - var s = pt("/") + 1; - return t < s ? -68 : (je("/", B, e, t), s); - } catch (o) { - if (typeof ne == "undefined" || o.name !== "ErrnoError") - throw o; - return -o.Pa; - } - }, - K: function (e, t) { - try { - return ((e = j(e)), zt(t, xt(e, !0))); - } catch (s) { - if (typeof ne == "undefined" || s.name !== "ErrnoError") - throw s; - return -s.Pa; - } - }, - C: function (e, t, s) { - try { - return ((t = j(t)), (t = rt(e, t)), ze(t, s), 0); - } catch (o) { - if (typeof ne == "undefined" || o.name !== "ErrnoError") - throw o; - return -o.Pa; - } - }, - J: function (e, t, s, o) { - try { - t = j(t); - var d = o & 256; - return ( - (t = rt(e, t, o & 4096)), - zt(s, d ? xt(t, !0) : xt(t)) - ); - } catch (E) { - if (typeof ne == "undefined" || E.name !== "ErrnoError") - throw E; - return -E.Pa; - } - }, - x: function (e, t, s, o) { - $t = o; - try { - ((t = j(t)), (t = rt(e, t))); - var d = o ? Vt() : 0; - return ft(t, s, d).bb; - } catch (E) { - if (typeof ne == "undefined" || E.name !== "ErrnoError") - throw E; - return -E.Pa; - } - }, - v: function (e, t, s, o) { - try { - if (((t = j(t)), (t = rt(e, t)), 0 >= o)) return -28; - var d = Fe(t).node; - if (!d) throw new D(44); - if (!d.La.eb) throw new D(28); - var E = d.La.eb(d), - P = Math.min(o, pt(E)), - $ = F[s + P]; - return (je(E, B, s, o + 1), (F[s + P] = $), P); - } catch (Q) { - if (typeof ne == "undefined" || Q.name !== "ErrnoError") - throw Q; - return -Q.Pa; - } - }, - u: function (e) { - try { - return ((e = j(e)), Zr(e), 0); - } catch (t) { - if (typeof ne == "undefined" || t.name !== "ErrnoError") - throw t; - return -t.Pa; - } - }, - f: function (e, t) { - try { - return ((e = j(e)), zt(t, xt(e))); - } catch (s) { - if (typeof ne == "undefined" || s.name !== "ErrnoError") - throw s; - return -s.Pa; - } - }, - r: function (e, t, s) { - try { - if (((t = j(t)), (t = rt(e, t)), s)) - if (s === 512) Zr(t); - else return -28; - else Jr(t); - return 0; - } catch (o) { - if (typeof ne == "undefined" || o.name !== "ErrnoError") - throw o; - return -o.Pa; - } - }, - q: function (e, t, s) { - try { - ((t = j(t)), (t = rt(e, t, !0))); - var o = Date.now(), - d, - E; - if (s) { - var P = w[s >> 2] + 4294967296 * v[(s + 4) >> 2], - $ = v[(s + 8) >> 2]; - ($ == 1073741823 - ? (d = o) - : $ == 1073741822 - ? (d = null) - : (d = 1e3 * P + $ / 1e6), - (s += 16), - (P = w[s >> 2] + 4294967296 * v[(s + 4) >> 2]), - ($ = v[(s + 8) >> 2]), - $ == 1073741823 - ? (E = o) - : $ == 1073741822 - ? (E = null) - : (E = 1e3 * P + $ / 1e6)); - } else E = d = o; - if ((E != null ? E : d) !== null) { - e = d; - var Q = Fe(t, { hb: !0 }).node; - Lt(Q.La.Xa)(Q, { $a: e, Ua: E }); - } - return 0; - } catch (Z) { - if (typeof ne == "undefined" || Z.name !== "ErrnoError") - throw Z; - return -Z.Pa; - } - }, - m: () => q(""), - l: () => { - ((Le = !1), (gr = 0)); - }, - A: function (e, t) { - ((e = - -9007199254740992 > e || 9007199254740992 < e - ? NaN - : Number(e)), - (e = new Date(1e3 * e)), - (v[t >> 2] = e.getSeconds()), - (v[(t + 4) >> 2] = e.getMinutes()), - (v[(t + 8) >> 2] = e.getHours()), - (v[(t + 12) >> 2] = e.getDate()), - (v[(t + 16) >> 2] = e.getMonth()), - (v[(t + 20) >> 2] = e.getFullYear() - 1900), - (v[(t + 24) >> 2] = e.getDay())); - var s = e.getFullYear(); - ((v[(t + 28) >> 2] = - ((s % 4 !== 0 || (s % 100 === 0 && s % 400 !== 0) ? ps : cs)[ - e.getMonth() - ] + - e.getDate() - - 1) | - 0), - (v[(t + 36) >> 2] = -(60 * e.getTimezoneOffset())), - (s = new Date(e.getFullYear(), 6, 1).getTimezoneOffset())); - var o = new Date(e.getFullYear(), 0, 1).getTimezoneOffset(); - v[(t + 32) >> 2] = - (s != o && e.getTimezoneOffset() == Math.min(o, s)) | 0; - }, - y: function (e, t, s, o, d, E, P) { - d = - -9007199254740992 > d || 9007199254740992 < d - ? NaN - : Number(d); - try { - var $ = ve(o); - if ( - (t & 2) !== 0 && - (s & 2) === 0 && - ($.flags & 2097155) !== 2 - ) - throw new D(2); - if (($.flags & 2097155) === 1) throw new D(2); - if (!$.Ma.sb) throw new D(43); - if (!e) throw new D(28); - var Q = $.Ma.sb($, e, d, t, s), - Z = Q.tc; - return ((v[E >> 2] = Q.Ub), (w[P >> 2] = Z), 0); - } catch (Y) { - if (typeof ne == "undefined" || Y.name !== "ErrnoError") - throw Y; - return -Y.Pa; - } - }, - z: function (e, t, s, o, d, E) { - E = - -9007199254740992 > E || 9007199254740992 < E - ? NaN - : Number(E); - try { - var P = ve(d); - if (s & 2) { - if ((P.node.mode & 61440) !== 32768) throw new D(43); - o & 2 || - (P.Ma.tb && P.Ma.tb(P, B.slice(e, e + t), E, t, o)); - } - } catch ($) { - if (typeof ne == "undefined" || $.name !== "ErrnoError") - throw $; - return -$.Pa; - } - }, - n: (e, t) => { - if ((wt[e] && (clearTimeout(wt[e].id), delete wt[e]), !t)) - return 0; - var s = setTimeout(() => { - (delete wt[e], us(() => ln(e, performance.now()))); - }, t); - return ((wt[e] = { id: s, Hc: t }), 0); - }, - B: (e, t, s, o) => { - var d = new Date().getFullYear(), - E = new Date(d, 0, 1).getTimezoneOffset(); - ((d = new Date(d, 6, 1).getTimezoneOffset()), - (w[e >> 2] = 60 * Math.max(E, d)), - (v[t >> 2] = +(E != d)), - (t = (P) => { - var $ = Math.abs(P); - return `UTC${0 <= P ? "-" : "+"}${String(Math.floor($ / 60)).padStart(2, "0")}${String($ % 60).padStart(2, "0")}`; - }), - (e = t(E)), - (t = t(d)), - d < E - ? (je(e, B, s, 17), je(t, B, o, 17)) - : (je(e, B, o, 17), je(t, B, s, 17))); - }, - d: () => Date.now(), - s: () => 2147483648, - c: () => performance.now(), - o: (e) => { - var t = B.length; - if (((e >>>= 0), 2147483648 < e)) return !1; - for (var s = 1; 4 >= s; s *= 2) { - var o = t * (1 + 0.2 / s); - o = Math.min(o, e + 100663296); - e: { - o = - ((Math.min( - 2147483648, - 65536 * Math.ceil(Math.max(e, o) / 65536) - ) - - Wt.buffer.byteLength + - 65535) / - 65536) | - 0; - try { - (Wt.grow(o), J()); - var d = 1; - break e; - } catch (E) {} - d = void 0; - } - if (d) return !0; - } - return !1; - }, - E: (e, t) => { - var s = 0, - o = 0, - d; - for (d of nn()) { - var E = t + s; - ((w[(e + o) >> 2] = E), - (s += je(d, B, E, 1 / 0) + 1), - (o += 4)); - } - return 0; - }, - F: (e, t) => { - var s = nn(); - ((w[e >> 2] = s.length), (e = 0)); - for (var o of s) e += pt(o) + 1; - return ((w[t >> 2] = e), 0); - }, - e: function (e) { - try { - var t = ve(e); - return (hr(t), 0); - } catch (s) { - if (typeof ne == "undefined" || s.name !== "ErrnoError") - throw s; - return s.Pa; - } - }, - p: function (e, t) { - try { - var s = ve(e); - return ( - (F[t] = s.Va - ? 2 - : Ee(s.mode) - ? 3 - : (s.mode & 61440) === 40960 - ? 7 - : 4), - (A[(t + 2) >> 1] = 0), - (I[(t + 8) >> 3] = BigInt(0)), - (I[(t + 16) >> 3] = BigInt(0)), - 0 - ); - } catch (o) { - if (typeof ne == "undefined" || o.name !== "ErrnoError") - throw o; - return o.Pa; - } - }, - w: function (e, t, s, o) { - try { - e: { - var d = ve(e); - e = t; - for (var E, P = (t = 0); P < s; P++) { - var $ = w[e >> 2], - Q = w[(e + 4) >> 2]; - e += 8; - var Z = Yr(d, F, $, Q, E); - if (0 > Z) { - var Y = -1; - break e; - } - if (((t += Z), Z < Q)) break; - typeof E != "undefined" && (E += Z); - } - Y = t; - } - return ((w[o >> 2] = Y), 0); - } catch (_e) { - if (typeof ne == "undefined" || _e.name !== "ErrnoError") - throw _e; - return _e.Pa; - } - }, - D: function (e, t, s, o) { - t = - -9007199254740992 > t || 9007199254740992 < t - ? NaN - : Number(t); - try { - if (isNaN(t)) return 61; - var d = ve(e); - return ( - Xr(d, t, s), - (I[o >> 3] = BigInt(d.position)), - d.Eb && t === 0 && s === 0 && (d.Eb = null), - 0 - ); - } catch (E) { - if (typeof ne == "undefined" || E.name !== "ErrnoError") - throw E; - return E.Pa; - } - }, - I: function (e) { - var s, o; - try { - var t = ve(e); - return (o = (s = t.Ma) == null ? void 0 : s.lb) == null - ? void 0 - : o.call(s, t); - } catch (d) { - if (typeof ne == "undefined" || d.name !== "ErrnoError") - throw d; - return d.Pa; - } - }, - t: function (e, t, s, o) { - try { - e: { - var d = ve(e); - e = t; - for (var E, P = (t = 0); P < s; P++) { - var $ = w[e >> 2], - Q = w[(e + 4) >> 2]; - e += 8; - var Z = en(d, F, $, Q, E); - if (0 > Z) { - var Y = -1; - break e; - } - if (((t += Z), Z < Q)) break; - typeof E != "undefined" && (E += Z); - } - Y = t; - } - return ((w[o >> 2] = Y), 0); - } catch (_e) { - if (typeof ne == "undefined" || _e.name !== "ErrnoError") - throw _e; - return _e.Pa; - } - }, - k: rn, - }; - function br() { - function e() { - var d; - if (((a.calledRun = !0), !R)) { - if (!a.noFSInit && !$r) { - var t, s; - (($r = !0), - t != null || (t = a.stdin), - s != null || (s = a.stdout), - o != null || (o = a.stderr), - t ? Je("stdin", t) : fr("/dev/tty", "/dev/stdin"), - s ? Je("stdout", null, s) : fr("/dev/tty", "/dev/stdout"), - o ? Je("stderr", null, o) : fr("/dev/tty1", "/dev/stderr"), - ft("/dev/stdin", 0), - ft("/dev/stdout", 1), - ft("/dev/stderr", 1)); - } - if ( - (vr.N(), - (Vr = !1), - (d = a.onRuntimeInitialized) == null || d.call(a), - a.postRun) - ) - for ( - typeof a.postRun == "function" && (a.postRun = [a.postRun]); - a.postRun.length; - ) { - var o = a.postRun.shift(); - U.push(o); - } - V(U); - } - } - if (0 < ge) Ce = br; - else { - if (a.preRun) - for ( - typeof a.preRun == "function" && (a.preRun = [a.preRun]); - a.preRun.length; - ) - we(); - (V(be), - 0 < ge - ? (Ce = br) - : a.setStatus - ? (a.setStatus("Running..."), - setTimeout(() => { - (setTimeout(() => a.setStatus(""), 1), e()); - }, 1)) - : e()); - } - } - var vr; - return ( - (async function () { - var s; - function e(o) { - var d; - return ( - (o = vr = o.exports), - (a._sqlite3_free = o.P), - (a._sqlite3_value_text = o.Q), - (a._sqlite3_prepare_v2 = o.R), - (a._sqlite3_step = o.S), - (a._sqlite3_reset = o.T), - (a._sqlite3_exec = o.U), - (a._sqlite3_finalize = o.V), - (a._sqlite3_column_name = o.W), - (a._sqlite3_column_text = o.X), - (a._sqlite3_column_type = o.Y), - (a._sqlite3_errmsg = o.Z), - (a._sqlite3_clear_bindings = o._), - (a._sqlite3_value_blob = o.$), - (a._sqlite3_value_bytes = o.aa), - (a._sqlite3_value_double = o.ba), - (a._sqlite3_value_int = o.ca), - (a._sqlite3_value_type = o.da), - (a._sqlite3_result_blob = o.ea), - (a._sqlite3_result_double = o.fa), - (a._sqlite3_result_error = o.ga), - (a._sqlite3_result_int = o.ha), - (a._sqlite3_result_int64 = o.ia), - (a._sqlite3_result_null = o.ja), - (a._sqlite3_result_text = o.ka), - (a._sqlite3_aggregate_context = o.la), - (a._sqlite3_column_count = o.ma), - (a._sqlite3_data_count = o.na), - (a._sqlite3_column_blob = o.oa), - (a._sqlite3_column_bytes = o.pa), - (a._sqlite3_column_double = o.qa), - (a._sqlite3_bind_blob = o.ra), - (a._sqlite3_bind_double = o.sa), - (a._sqlite3_bind_int = o.ta), - (a._sqlite3_bind_text = o.ua), - (a._sqlite3_bind_parameter_index = o.va), - (a._sqlite3_sql = o.wa), - (a._sqlite3_normalized_sql = o.xa), - (a._sqlite3_changes = o.ya), - (a._sqlite3_close_v2 = o.za), - (a._sqlite3_create_function_v2 = o.Aa), - (a._sqlite3_update_hook = o.Ba), - (a._sqlite3_open = o.Ca), - (Ht = a._malloc = o.Da), - (St = a._free = o.Ea), - (a._RegisterExtensionFunctions = o.Fa), - (on = o.Ga), - (ln = o.Ha), - (Kt = o.Ia), - (st = o.Ja), - (Ut = o.Ka), - (Wt = o.M), - (Qe = o.O), - J(), - ge--, - (d = a.monitorRunDependencies) == null || d.call(a, ge), - ge == 0 && Ce && ((o = Ce), (Ce = null), o()), - vr - ); - } - (ge++, (s = a.monitorRunDependencies) == null || s.call(a, ge)); - var t = { a: hs }; - return a.instantiateWasm - ? new Promise((o) => { - a.instantiateWasm(t, (d, E) => { - o(e(d, E)); - }); - }) - : (te != null || - (te = a.locateFile - ? a.locateFile("sql-wasm-browser.wasm", h) - : h + "sql-wasm-browser.wasm"), - e((await ye(t)).instance)); - })(), - br(), - n - ); - })), - tr) - ); - }; - typeof nr == "object" && typeof Ot == "object" - ? ((Ot.exports = rr), (Ot.exports.default = rr)) - : typeof define == "function" && define.amd - ? define([], function () { - return rr; - }) - : typeof nr == "object" && (nr.Module = rr); -}); -var na = {}; -Ws(na, { default: () => ar }); -module.exports = Zs(na); -var de = require("obsidian"), - le = ae(require("fs")), - bt = ae(require("path")), - He = require("child_process"); -var it = "paperforge-status", - Ct = "paperforge", - xn = - '', - Pe = [ - { - id: "paperforge-sync", - title: "Sync Library", - desc: "Pull new references from Zotero and generate literature notes", - icon: "\u21BB", - cmd: "sync", - okMsg: "Sync complete", - }, - { - id: "paperforge-ocr", - title: "Run OCR", - desc: "Extract full text and figures from PDFs via PaddleOCR", - icon: "\u229E", - cmd: "ocr", - okMsg: "OCR started", - }, - { - id: "paperforge-doctor", - title: "Run Doctor", - desc: "Verify PaperForge setup \u2014 check configs, Zotero, paths, and index health", - icon: "\u2695", - cmd: "doctor", - okMsg: "Doctor complete", - }, - { - id: "paperforge-repair", - title: "Repair Issues", - desc: "Fix three-way state divergence, path errors, and rebuild index", - icon: "\u21BA", - cmd: "repair", - args: ["--fix", "--fix-paths"], - okMsg: "Repair complete", - }, - { - id: "paperforge-ocr-redo", - title: "Redo OCR", - desc: "Re-run OCR for papers marked ocr_redo: true", - icon: "\u21BA", - cmd: "ocr", - args: ["redo"], - okMsg: "OCR redo started", - }, - ], - Ft = { - vault_path: "", - setup_complete: !1, - auto_update: !0, - auto_update_on_startup: !0, - agent_platform: "opencode", - language: "", - paddleocr_api_key: "", - zotero_data_dir: "", - python_path: "", - features: { memory_layer: !0, vector_db: !1 }, - selected_skill_platform: "opencode", - vector_db_api_key: "", - vector_db_api_base: "", - vector_db_api_model: "text-embedding-3-small", - frozen_skills: {}, - system_dir: "", - resources_dir: "", - literature_dir: "", - base_dir: "", - last_seen_version: "", - }; -function wn(_, y) { - if (!y || !y.note_path) return y; - let r = _.vault.getAbstractFileByPath(y.note_path); - if (!r) return y; - let n = _.metadataCache.getFileCache(r), - i = n && n.frontmatter; - if (!i) return y; - let a = { ...y }; - for (let c of [ - "do_ocr", - "analyze", - "ocr_status", - "ocr_redo", - "deep_reading_status", - ]) - Object.prototype.hasOwnProperty.call(i, c) && (a[c] = i[c]); - return a; -} -function xr(_, y) { - return _ && { ..._, ...y }; -} -var wr = { - en: { - action_running: "Running ", - api_key_missing: "Missing", - api_key_set: "Entered", - btn_install: "Open Setup Wizard", - btn_install_desc: - "Check whether the environment is ready, then open the step-by-step setup wizard", - btn_reconfig: "Reconfigure", - btn_reconfig_desc: - "Open the setup wizard again to change directories, platform, or API keys", - btn_validate: "Validate", - check_bbt_fail: "Not detected", - check_bbt_ok: "Installed", - check_python_fail: "Not found", - check_python_ok: "Ready", - check_zotero_fail: "Not detected", - check_zotero_ok: "Found", - complete_export_path: "Save Better BibTeX JSON exports into:", - complete_next: "Recommended next steps", - complete_step1: "Open Dashboard", - complete_step1_desc: - 'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.', - complete_step2: "Sync Literature", - complete_step2_desc: - "In the main panel, click Sync Library to bring papers from Zotero into Obsidian and generate notes.", - complete_step3: "Run OCR", - complete_step3_desc: - "In the Obsidian Base view, mark do_ocr:true on papers, then run OCR in the main panel.", - complete_step4: "Configure Better BibTeX Auto-export", - complete_step4_desc: - 'In Zotero, right-click the library or collection you want to sync -> Export -> Better BibTeX JSON -> enable "Keep updated".', - complete_summary: "Saved Configuration", - complete_title: "Setup Complete", - copied: "Copied!", - copy_pf_deep_cmd: "Copy /pf-deep Command", - dashboard_drift_warning: - "PaperForge CLI (v{0}) differs from plugin (v{1}). Open Settings \u2192 Runtime Health to sync.", - deep_reading_not_found: "Deep reading file not found", - desc: "Obsidian + Zotero literature pipeline. Sync papers, generate notes, run OCR, and read deeply in one place.", - dir_base: "Base Dir", - dir_index: "Index Dir", - dir_notes: "Notes Dir", - dir_resources: "Resource Dir", - dir_system: "System Dir", - dir_vault: "Vault Path", - error_copied: "Copied!", - error_copy_diagnostic: "Copy diagnostic", - feat_agent_platform: "Agent Platform", - feat_agent_platform_desc: - "Select which agent platform to manage skills for.", - feat_api_base_url: "API Base URL", - feat_api_base_url_desc: - "Custom OpenAI-compatible API endpoint. Leave empty for default.", - feat_api_model: "API Model", - feat_api_model_desc: "Embedding model name for this endpoint.", - feat_build_btn: "Build", - feat_build_complete: "Vector build complete.", - feat_build_failed: "Build failed. See terminal output.", - feat_building: "Building...", - feat_cache_remove_failed: "Failed: {0}", - feat_cache_removed: "Model cache removed.", - feat_checking: "Checking...", - feat_checking_btn: "Checking...", - feat_deps_checking: "Checking dependencies...", - feat_deps_missing: - "Dependencies not installed. Required: chromadb, openai.", - feat_enter_key: "Enter a valid OpenAI API key.", - feat_install_btn: "Install", - feat_install_deps: "Install Dependencies", - feat_install_deps_desc: "pip install chromadb openai (~35MB).", - feat_install_done: "Dependencies installed. Building vectors...", - feat_install_failed: "Install failed: ", - feat_installing: "Installing...", - feat_installing_pkgs: "Installing {pkgs}...", - feat_key_rejected: "API key rejected.", - feat_memory_desc: - "The Memory Layer is the core data engine of PaperForge, powered by SQLite. It integrates literature metadata (papers, assets, aliases, reading events), provides FTS5 metadata search across titles, abstracts, authors, domains, and collections, and powers agent-context and paper-status. Always active \u2014 no toggle needed.", - feat_memory_rebuild_btn: "Rebuild", - feat_memory_rebuild_done: "Memory DB rebuilt.", - feat_memory_rebuild_failed: "Rebuild failed.", - feat_memory_rebuilding: "Rebuilding...", - feat_model_changed_warn: - "Model changed ({0} -> {1}). Existing vectors are incompatible \u2014 rebuild required.", - feat_network_error: "Network error: ", - feat_no_python: "No Python found. Check Installation tab.", - feat_not_cached: "Not cached", - feat_openai_key: "OpenAI API Key", - feat_openai_key_desc: - "Used for API embedding calls. Model is defined below.", - feat_output_copied: "Output copied to clipboard.", - feat_rebuild_btn: "Rebuild", - feat_rebuild_vectors: "Rebuild Vectors", - feat_rebuild_vectors_changed: - "Model changed \u2014 rebuild to update all vectors.", - feat_rebuild_vectors_desc: - "Rebuild all OCR fulltext vectors. Required after model or mode change.", - feat_removing: "Removing...", - feat_retry_btn: "Retry", - feat_skills_desc: - "Manage and enable/disable agent skills installed in your vault. Each row corresponds to a SKILL.md file \u2014 toggle off to prevent the agent from auto-invoking that skill.", - feat_skills_system: - "System Skills ship with PaperForge and are updated alongside PaperForge.", - feat_skills_user: - "User Skills are custom skills you install from community or create yourself.", - feat_uninstall_btn: "Uninstall", - feat_valid_key: "API key valid.", - feat_vector_config_label: "Vector Settings", - feat_vector_corrupted: - "Vector index corrupted \u2014 needs force rebuild.", - feat_vector_desc: - "Vector Database enables semantic search across OCR-extracted fulltext via API embedding. Documents are split into chunks, embedded via OpenAI-compatible API, and stored in ChromaDB.", - feat_vector_enable: "Enable Vector Retrieval", - feat_vector_enable_desc: - "Semantic search across OCR fulltext. Requires: pip install openai chromadb (~35MB).", - feat_vector_rebuild_force_btn: "Force Rebuild", - feat_verify: "Verify", - feat_verify_btn: "Verify", - field_paddleocr: "PaddleOCR API Key", - field_python_custom: "Custom Path", - field_python_interp: "Python Interpreter", - field_zotero_data: "Zotero Data Dir", - field_zotero_placeholder: - "Required. Path to Zotero data directory for PDF attachment resolution.", - guide_ocr: "Run OCR", - guide_ocr_desc: - "In the main panel, click Run OCR to extract full text and figures from PDFs for later reading and analysis.", - guide_open: "Open Main Panel", - guide_open_desc: - 'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.', - guide_sync: "Sync Literature", - guide_sync_desc: - "After Better BibTeX JSON export is configured, click Sync Library to import papers from Zotero into Obsidian and generate notes automatically.", - header_title: "PaperForge", - install_bootstrapping: - "PaperForge Python package not found. Installing automatically...", - install_btn: "Start Install", - install_btn_retry: "Retry", - install_btn_running: "Installing...", - install_complete: "Installation complete!", - install_failed: "Installation failed: ", - install_validating: "Validating setup...", - jump_to_deep_reading: "Open Deep Reading", - label_agent: "Agent Platform", - nav_close: "Close", - nav_next: "Next", - nav_prev: "Back", - not_set: "Not entered", - notice_check_fail: "Missing: ", - notice_python_missing: - "Python was not detected. Install Python 3.10+ and add it to PATH.", - ocr_privacy_title: "OCR Privacy Notice", - ocr_privacy_warning: - "OCR will upload PDFs to the PaddleOCR API. Do not upload sensitive or confidential documents.", - ocr_queue_add: "Add to OCR Queue", - ocr_queue_added: "Added to OCR queue", - ocr_queue_remove: "Remove from OCR Queue", - ocr_queue_removed: "Removed from OCR queue", - ocr_understand: "I understand, continue", - optional_later: "(can be set later in Settings)", - orphan_delete_failed: "Prune failed", - orphan_delete_selected: "Delete {count} selected", - orphan_deleted: "Deleted {count} orphan workspace(s)", - orphan_desc: "These papers are no longer in your Zotero library.", - orphan_deselect_all: "Deselect all", - orphan_explain: "Removed from Zotero. Workspace files remain on disk.", - orphan_keep_all: "Keep all", - orphan_none_selected: "No papers selected for deletion", - orphan_select_all: "Select all", - orphan_title: "Found {count} orphan paper(s)", - panel_actions: "Quick Actions", - prep_bbt: "Better BibTeX", - prep_bbt_desc: "In Zotero: Tools -> Add-ons -> install Better BibTeX.", - prep_export: "Better BibTeX Auto-export", - prep_export_desc: - 'In Zotero, right-click the collection you want to sync -> Export Collection -> BetterBibTeX JSON -> enable "Keep updated" -> save the JSON file into the exports folder shown below. Obsidian Base views will use the JSON filename as the Base name:', - prep_export_path_label: "Save the exported JSON file into this folder:", - prep_key: "PaddleOCR Key", - prep_key_desc: - "Get your API key from https://aistudio.baidu.com/paddleocr", - prep_python: "Python 3.10+", - prep_python_desc: - "Python must be available from the command line. If you are not sure, click below to auto-detect.", - prep_zotero: "Zotero Desktop", - prep_zotero_desc: "Install Zotero from https://www.zotero.org", - run_in_agent: "Run in {0}", - runtime_health: "Runtime Health", - runtime_health_checking: "Checking...", - runtime_health_desc: - "Check whether the installed paperforge Python package matches the plugin version and whether the deployed skill contract is current.", - runtime_health_match: "Match", - runtime_health_mismatch: "Mismatch", - runtime_health_package_ver: "Python package v{0}", - runtime_health_plugin_ver: "Plugin v{0}", - runtime_health_sync: "Sync Runtime", - runtime_health_sync_done: "Runtime synced to v{0}", - runtime_health_sync_fail: "Sync failed: {0}", - runtime_health_syncing: "Syncing...", - section_config: "Current Configuration", - section_guide: "How To Use", - section_prep: "Preparation", - section_prep_desc: - "Before first use, finish these 4 preparation items. Better BibTeX auto-export is configured after setup:", - setup_done: "PaperForge environment is ready", - setup_pending: - "Not installed yet. Finish the preparation items below, then open the wizard.", - tab_features: "Features", - tab_setup: "Installation", - tab_maintenance: "Maintenance", - validate_base: "Base directory is required", - validate_fail: "Please complete the required fields below", - validate_index: "Index directory is required", - validate_key: "PaddleOCR API key (optional, needed for OCR)", - validate_notes: "Notes directory is required", - validate_resources: "Resources directory is required", - validate_system: "System directory is required", - validate_vault: "Vault path is required", - validate_zotero: - "Zotero data directory (optional, needed for PDF linking)", - wizard_agent_hint: - "Choose the AI agent platform you use most often. PaperForge will place the matching command and skill files in the correct location.", - wizard_dir_hint: - "PaperForge stores user-facing literature data under the resources directory. These folders will live there:", - wizard_dir_sub_hint: "Resolved folder preview based on the names below:", - wizard_intro: - "This wizard walks you through the full setup. In most cases, the default values are fine to keep.", - wizard_keys_hint: - "Enter your PaddleOCR API key below. If you want PaperForge to auto-locate Zotero PDFs, you can also fill in the Zotero data directory.", - wizard_preview: - "After installation, system files stay at the vault root while literature data stays under the resources directory.", - wizard_safety: - "Safety: if the selected folders already contain files, setup preserves existing files and only creates missing PaperForge folders and files.", - wizard_step1: "Overview", - wizard_step2: "Directory Setup", - wizard_step3: "Platform & Keys", - wizard_step4: "Install", - wizard_step5: "Done", - wizard_skip_ocr_desc: - "OCR will not be available until you configure a valid PaddleOCR API key. You can continue setup now and configure it later in Settings.", - wizard_skip_ocr_continue: "Continue without OCR key", - wizard_skip_ocr_back: "Back to configure", - wizard_api_hint_skip: - "OCR key is optional \u2014 you may skip it and configure later.", - wizard_sys_hint: - "These folders live at the vault root, outside the resources directory:", - wizard_title: "PaperForge Setup Wizard", - ocr_maint_no_action: "No Action Needed", - ocr_maint_rebuild: "Rebuild Recommended", - ocr_maint_failed: "OCR Failed", - ocr_maint_limited: "Result Limited", - ocr_maint_needs_attention: "Needs Attention", - ocr_maint_limitations: "Result Limitations", - ocr_maint_hero_ok: "OCR looks usable overall.", - ocr_maint_hero_warn: - "OCR needs attention: {rebuild} rebuild recommended, {failed} failed.", - ocr_maint_hero_note: - "This page only promotes issues where maintenance is likely to help. Some papers may have limitations that maintenance will not improve.", - ocr_maint_limitations_intro: - "These papers look less certain, but PaperForge does not currently have a high-confidence maintenance action to recommend.", - ocr_maint_all_papers: "All Papers", - ocr_maint_rebuild_btn: "Rebuild results", - ocr_maint_redo_btn: "Rerun OCR", - maintenance_group_retry: "Needs Retry", - maintenance_group_rebuild: "Can Rebuild", - maintenance_group_legacy: "Upgrade Available (Optional)", - maintenance_btn_retry: "Retry", - maintenance_btn_rebuild: "Rebuild", - maintenance_btn_upgrade: "Upgrade", - maintenance_refresh_spinning: "Updating\u2026", - maintenance_all_good: "\u2705 All good \u2014 no action needed", - maintenance_n_pending: "{n} need attention", - version_panel_title: "Version History", - version_panel_back: "Back", - version_filter_placeholder: "Filter papers...", - version_papers_count: "{n} papers", - version_current: "current", - version_restore_btn: "Restore", - version_compare_btn: "Compare", - version_restore_selected: "Restore selected", - version_clear_old: "Clear old versions (free {size})", - version_no_backups: "No version history available", - version_restore_confirm: "Restore {label} for {paper}?", - version_restore_done: "Restored {label}", - version_compare_title: "{vA} vs {vB}", - version_compare_paragraphs: "{n} paragraphs changed", - version_error_read: "Cannot read version data", - }, - zh: { - action_running: "\u6B63\u5728\u6267\u884C ", - api_key_missing: "\u672A\u914D\u7F6E \u2717", - api_key_set: "\u5DF2\u914D\u7F6E \u2713", - btn_install: "\u6253\u5F00\u5B89\u88C5\u5411\u5BFC", - btn_install_desc: - "\u81EA\u52A8\u68C0\u6D4B Python + \u524D\u7F6E\u73AF\u5883\uFF0C\u901A\u8FC7\u540E\u6253\u5F00\u5206\u6B65\u5B89\u88C5\u5411\u5BFC", - btn_reconfig: "\u91CD\u65B0\u914D\u7F6E", - btn_reconfig_desc: - "\u91CD\u65B0\u8FD0\u884C\u5B89\u88C5\u5411\u5BFC\uFF0C\u4FEE\u6539\u76EE\u5F55\u6216\u5BC6\u94A5\u914D\u7F6E", - btn_validate: "\u9A8C\u8BC1", - check_bbt_fail: "\u672A\u68C0\u6D4B\u5230", - check_bbt_ok: "\u5DF2\u5B89\u88C5", - check_python_fail: "\u672A\u5B89\u88C5", - check_python_ok: "\u5DF2\u5C31\u7EEA", - check_zotero_fail: "\u672A\u68C0\u6D4B\u5230", - check_zotero_ok: "\u5DF2\u5B89\u88C5", - complete_next: "\u4E0B\u4E00\u6B65\u64CD\u4F5C", - complete_step1: "\u6253\u5F00 PaperForge Dashboard", - complete_step1_desc: - "Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807", - complete_step2: "\u540C\u6B65\u6587\u732E", - complete_step2_desc: - "Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0", - complete_step3: "\u8FD0\u884C OCR", - complete_step3_desc: - "Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868", - complete_step4: "\u914D\u7F6E BBT \u81EA\u52A8\u5BFC\u51FA", - complete_summary: "\u5F53\u524D\u5B8C\u6574\u914D\u7F6E", - complete_title: "\u2713 PaperForge \u5B89\u88C5\u5B8C\u6210", - copied: "\u5DF2\u590D\u5236\uFF01", - copy_pf_deep_cmd: "\u590D\u5236 /pf-deep \u547D\u4EE4", - dashboard_drift_warning: - '\u63D2\u4EF6\u7248\u672C\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u4E0D\u5339\u914D\u3002\u8BF7\u5728\u8BBE\u7F6E\u4E2D\u70B9\u51FB"\u540C\u6B65\u8FD0\u884C\u65F6"\u3002', - deep_reading_not_found: "\u7CBE\u8BFB\u6587\u4EF6\u672A\u627E\u5230", - desc: "Obsidian + Zotero \u6587\u732E\u7BA1\u7406\u6D41\u6C34\u7EBF\u3002\u81EA\u52A8\u540C\u6B65\u6587\u732E\u3001\u751F\u6210\u7B14\u8BB0\u3001OCR \u63D0\u53D6\u5168\u6587\uFF0C\u4E00\u7AD9\u5F0F\u6587\u732E\u7CBE\u8BFB\u5DE5\u4F5C\u6D41\u3002", - dir_base: "Base \u76EE\u5F55", - dir_index: "\u7D22\u5F15\u76EE\u5F55", - dir_notes: "\u6B63\u6587\u76EE\u5F55", - dir_resources: "\u8D44\u6E90\u76EE\u5F55", - dir_system: "\u7CFB\u7EDF\u76EE\u5F55", - dir_vault: "Vault \u8DEF\u5F84", - error_copied: "\u5DF2\u590D\u5236\uFF01", - error_copy_diagnostic: "\u590D\u5236\u8BCA\u65AD\u4FE1\u606F", - feat_agent_platform: "Agent \u5E73\u53F0", - feat_agent_platform_desc: - "\u9009\u62E9\u8981\u7BA1\u7406\u7684 Agent \u5E73\u53F0\u3002", - feat_api_base_url: "API \u5730\u5740", - feat_api_base_url_desc: - "\u81EA\u5B9A\u4E49 OpenAI \u517C\u5BB9 API \u7AEF\u70B9\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u5730\u5740\u3002", - feat_api_model: "API \u6A21\u578B", - feat_api_model_desc: - "\u8BE5\u7AEF\u70B9\u4F7F\u7528\u7684\u5D4C\u5165\u6A21\u578B\u540D\u79F0\u3002", - feat_build_btn: "\u6784\u5EFA", - feat_build_complete: "\u5411\u91CF\u6784\u5EFA\u5B8C\u6210\u3002", - feat_build_failed: - "\u6784\u5EFA\u5931\u8D25\u3002\u8BF7\u67E5\u770B\u7EC8\u7AEF\u8F93\u51FA\u3002", - feat_building: "\u6784\u5EFA\u4E2D\u2026", - feat_cache_remove_failed: "\u5931\u8D25\uFF1A{0}", - feat_cache_removed: "\u6A21\u578B\u7F13\u5B58\u5DF2\u6E05\u9664\u3002", - feat_checking: "\u68C0\u6D4B\u4E2D\u2026", - feat_checking_btn: "\u68C0\u6D4B\u4E2D\u2026", - feat_deps_checking: "\u6B63\u5728\u68C0\u6D4B\u4F9D\u8D56\u2026", - feat_deps_missing: - "\u4F9D\u8D56\u672A\u5B89\u88C5\u3002\u9700\u8981\uFF1Achromadb, openai\u3002", - feat_enter_key: - "\u8BF7\u8F93\u5165\u6709\u6548\u7684 OpenAI API Key\u3002", - feat_install_btn: "\u5B89\u88C5", - feat_install_deps: "\u5B89\u88C5\u4F9D\u8D56", - feat_install_done: - "\u4F9D\u8D56\u5DF2\u5B89\u88C5\u3002\u6B63\u5728\u6784\u5EFA\u5411\u91CF\u2026", - feat_install_failed: "\u5B89\u88C5\u5931\u8D25\uFF1A", - feat_installing: "\u5B89\u88C5\u4E2D\u2026", - feat_installing_pkgs: "\u6B63\u5728\u5B89\u88C5 {pkgs}...", - feat_key_rejected: "API Key \u88AB\u62D2\u7EDD\u3002", - feat_memory_desc: - "\u8BB0\u5FC6\u5C42\u662F PaperForge \u7684\u6838\u5FC3\u6570\u636E\u5F15\u64CE\uFF0C\u57FA\u4E8E SQLite \u6784\u5EFA\u3002\u5B83\u6574\u5408\u4E86\u6587\u732E\u5143\u6570\u636E\uFF08\u8BBA\u6587\u3001\u8D44\u6E90\u6587\u4EF6\u3001\u522B\u540D\u3001\u9605\u8BFB\u4E8B\u4EF6\uFF09\uFF0C\u652F\u6301 FTS5 \u5143\u6570\u636E\u68C0\u7D22\uFF08\u6807\u9898\u3001\u6458\u8981\u3001\u4F5C\u8005\u3001domain\u3001collection\uFF09\uFF0C\u5E76\u4E3A agent-context \u548C paper-status \u547D\u4EE4\u63D0\u4F9B\u6570\u636E\u652F\u6491\u3002\u59CB\u7EC8\u8FD0\u884C\uFF0C\u65E0\u9700\u624B\u52A8\u5F00\u542F\u3002", - feat_memory_rebuild_btn: "\u91CD\u5EFA\u6570\u636E\u5E93", - feat_memory_rebuild_done: - "\u8BB0\u5FC6\u6570\u636E\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002", - feat_memory_rebuild_failed: "\u91CD\u5EFA\u5931\u8D25\u3002", - feat_memory_rebuilding: "\u91CD\u5EFA\u4E2D\u2026", - feat_model: "\u6A21\u578B", - feat_model_changed_warn: - "\u6A21\u578B\u5DF2\u66F4\u6362\uFF08{0} -> {1}\uFF09\u3002\u5DF2\u6709\u5411\u91CF\u4E0D\u517C\u5BB9\u2014\u2014\u9700\u8981\u91CD\u5EFA\u3002", - feat_network_error: "\u7F51\u7EDC\u9519\u8BEF\uFF1A", - feat_no_python: - "\u672A\u627E\u5230 Python\u3002\u8BF7\u67E5\u770B\u5B89\u88C5\u6807\u7B7E\u9875\u3002", - feat_not_cached: "\u672A\u7F13\u5B58", - feat_openai_key: "OpenAI API Key", - feat_openai_key_desc: - "\u7528\u4E8E API \u5D4C\u5165\u8C03\u7528\uFF0C\u6A21\u578B\u5728\u4E0B\u65B9\u5B9A\u4E49\u3002", - feat_output_copied: - "\u8F93\u51FA\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\u3002", - feat_rebuild_btn: "\u91CD\u5EFA", - feat_rebuild_vectors: "\u91CD\u5EFA\u5411\u91CF", - feat_rebuild_vectors_changed: - "\u6A21\u578B\u5DF2\u66F4\u6362 \u2014 \u9700\u8981\u91CD\u5EFA\u5411\u91CF\u3002", - feat_rebuild_vectors_desc: - "\u91CD\u5EFA\u6240\u6709 OCR \u5168\u6587\u5411\u91CF\u3002\u66F4\u6362\u6A21\u578B\u6216\u6A21\u5F0F\u540E\u9700\u8981\u91CD\u5EFA\u3002", - feat_removing: "\u5220\u9664\u4E2D\u2026", - feat_retry_btn: "\u91CD\u8BD5", - feat_skills_desc: - "\u7BA1\u7406 Vault \u4E2D\u5DF2\u5B89\u88C5\u7684 Agent \u6280\u80FD\u3002\u6BCF\u884C\u5BF9\u5E94\u4E00\u4E2A SKILL.md \u6587\u4EF6\uFF0C\u5173\u95ED\u5F00\u5173\u53EF\u963B\u6B62 Agent \u81EA\u52A8\u8C03\u7528\u8BE5\u6280\u80FD\u3002", - feat_skills_system: - "\u7CFB\u7EDF\u6280\u80FD\u968F PaperForge \u4E00\u540C\u53D1\u5E03\uFF0C\u4F1A\u8DDF\u968F PaperForge \u7248\u672C\u66F4\u65B0\u3002", - feat_skills_user: - "\u7528\u6237\u6280\u80FD\u662F\u4F60\u81EA\u884C\u5B89\u88C5\u6216\u521B\u5EFA\u7684\u81EA\u5B9A\u4E49\u6280\u80FD\u3002", - feat_uninstall_btn: "\u5378\u8F7D", - feat_valid_key: "API Key \u6709\u6548\u3002", - feat_vector_config_label: "\u5411\u91CF\u5E93\u914D\u7F6E", - feat_vector_corrupted: - "\u5411\u91CF\u7D22\u5F15\u5DF2\u635F\u574F \u2014 \u9700\u8981\u5F3A\u5236\u91CD\u5EFA\u3002", - feat_vector_desc: - "\u5411\u91CF\u6570\u636E\u5E93\u901A\u8FC7\u5D4C\u5165\u6A21\u578B\u5B9E\u73B0 OCR \u5168\u6587\u7684\u8BED\u4E49\u641C\u7D22\u3002\u6587\u6863\u88AB\u5207\u5206\u4E3A\u6587\u672C\u5757\uFF08chunk\uFF09\uFF0C\u7F16\u7801\u4E3A\u5411\u91CF\u5B58\u5165 ChromaDB\u3002\u652F\u6301\u672C\u5730\u6A21\u578B\uFF08\u514D\u8D39\uFF0CCPU \u8FD0\u884C\uFF09\u6216 OpenAI API\uFF08\u4ED8\u8D39\uFF0C\u66F4\u5FEB\u901F\uFF09\u3002", - feat_vector_enable: "\u542F\u7528\u5411\u91CF\u68C0\u7D22", - feat_vector_enable_desc: - "\u5BF9 OCR \u5168\u6587\u8FDB\u884C\u8BED\u4E49\u641C\u7D22\u3002\u9700\u5B89\u88C5: pip install chromadb sentence-transformers openai (~500MB)\u3002", - feat_vector_rebuild_force_btn: "\u5F3A\u5236\u91CD\u5EFA", - feat_verify: "\u9A8C\u8BC1", - feat_verify_btn: "\u9A8C\u8BC1", - field_paddleocr: "PaddleOCR API \u5BC6\u94A5", - field_python_custom: "\u81EA\u5B9A\u4E49 Python \u8DEF\u5F84", - field_python_interp: "\u5F53\u524D Python \u89E3\u91CA\u5668", - field_zotero_data: "Zotero \u6570\u636E\u76EE\u5F55", - field_zotero_placeholder: - "\u53EF\u9009\uFF0C\u7528\u4E8E\u81EA\u52A8\u68C0\u6D4B PDF", - guide_ocr: "\u8FD0\u884C OCR", - guide_ocr_desc: - "Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868", - guide_open: "\u6253\u5F00 Dashboard", - guide_open_desc: - "Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807", - guide_sync: "\u540C\u6B65\u6587\u732E", - guide_sync_desc: - "Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0", - header_title: "PaperForge", - install_bootstrapping: - "\u672A\u68C0\u6D4B\u5230 PaperForge Python \u5305\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5\u2026", - install_btn: "\u5F00\u59CB\u5B89\u88C5", - install_btn_retry: "\u91CD\u8BD5", - install_btn_running: "\u6B63\u5728\u5B89\u88C5...", - install_complete: "\u2713 \u5B89\u88C5\u5B8C\u6210\uFF01", - install_failed: "\u2717 \u5B89\u88C5\u5931\u8D25\uFF1A", - install_validating: - "\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u73AF\u5883\u2026", - jump_to_deep_reading: "\u8DF3\u8F6C\u5230\u7CBE\u8BFB", - label_agent: "Agent \u5E73\u53F0", - nav_close: "\u5173\u95ED", - nav_next: "\u4E0B\u4E00\u6B65 \u2192", - nav_prev: "\u2190 \u4E0A\u4E00\u6B65", - no_pending_ocr: "\u6240\u6709 OCR \u4EFB\u52A1\u5DF2\u5B8C\u6210", - not_set: "\u672A\u8BBE\u7F6E", - notice_check_fail: "\u672A\u901A\u8FC7: ", - notice_python_missing: - "Python \u672A\u68C0\u6D4B\u5230\uFF0C\u8BF7\u5148\u5B89\u88C5 Python 3.10+ \u5E76\u52A0\u5165 PATH", - ocr_privacy_title: "OCR \u9690\u79C1\u63D0\u793A", - ocr_privacy_warning: - "OCR \u4F1A\u5C06 PDF \u4E0A\u4F20\u5230 PaddleOCR API \u8FDB\u884C\u5904\u7406\u3002\u8BF7\u4E0D\u8981\u4E0A\u4F20\u5305\u542B\u654F\u611F\u4FE1\u606F\u6216\u65E0\u6CD5\u5916\u4F20\u7684\u6587\u732E\u3002", - ocr_queue_add: "\u52A0\u5165 OCR \u961F\u5217", - ocr_queue_added: "\u5DF2\u52A0\u5165 OCR \u961F\u5217", - ocr_queue_remove: "\u79FB\u51FA OCR \u961F\u5217", - ocr_queue_removed: "\u5DF2\u79FB\u51FA OCR \u961F\u5217", - ocr_understand: "\u6211\u4E86\u89E3\uFF0C\u7EE7\u7EED", - optional_later: - "\uFF08\u7A0D\u540E\u53EF\u5728\u8BBE\u7F6E\u4E2D\u8865\u5145\uFF09", - orphan_delete_failed: "\u6E05\u7406\u5931\u8D25", - orphan_delete_selected: "\u5220\u9664 {count} \u7BC7", - orphan_deleted: - "\u5DF2\u5220\u9664 {count} \u7BC7\u6B8B\u7559\u6587\u732E", - orphan_desc: - "\u8FD9\u4E9B\u6587\u732E\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002", - orphan_deselect_all: "\u53D6\u6D88\u5168\u9009", - orphan_explain: - "\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002\u5DE5\u4F5C\u533A\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u78C1\u76D8\u4E0A\u3002", - orphan_keep_all: "\u4FDD\u7559\u5168\u90E8", - orphan_none_selected: "\u672A\u9009\u62E9\u4EFB\u4F55\u6587\u732E", - orphan_select_all: "\u5168\u9009", - orphan_title: "\u53D1\u73B0 {count} \u7BC7\u6B8B\u7559\u6587\u732E", - panel_actions: "\u5FEB\u6377\u64CD\u4F5C", - prep_bbt: "Better BibTeX", - prep_bbt_desc: - "Zotero \u2192 \u5DE5\u5177 \u2192 \u63D2\u4EF6 \u2192 \u5B89\u88C5 Better BibTeX", - prep_export: "BBT \u81EA\u52A8\u5BFC\u51FA", - prep_export_desc: - "\u53F3\u952E\u6587\u732E\u5B50\u5206\u7C7B \u2192 \u5BFC\u51FA\u5206\u7C7B \u2192 BetterBibTeX JSON \u2192 \u52FE\u9009\u4FDD\u6301\u66F4\u65B0 \u2192 \u5BFC\u51FA\u5230\uFF08JSON \u6587\u4EF6\u540D\u5373\u4E3A Base \u540D\uFF09\uFF1A", - prep_key: "PaddleOCR Key", - prep_key_desc: - "\u5728 https://aistudio.baidu.com/paddleocr \u83B7\u53D6 API Key", - prep_python: "Python 3.10+", - prep_python_desc: - "\u786E\u4FDD Python \u53EF\u547D\u4EE4\u884C\u8C03\u7528\u3002\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u81EA\u52A8\u68C0\u6D4B\u3002", - prep_zotero: "Zotero \u684C\u9762\u7248", - prep_zotero_desc: "\u5B89\u88C5 Zotero (https://www.zotero.org)", - run_in_agent: "\u5728 {0} \u4E2D\u8FD0\u884C", - runtime_health: "\u8FD0\u884C\u65F6\u72B6\u6001", - runtime_health_checking: "\u6B63\u5728\u68C0\u6D4B\u2026", - runtime_health_desc: - "\u68C0\u67E5\u63D2\u4EF6\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u7684\u5339\u914D\u60C5\u51B5\uFF0C\u5E76\u786E\u8BA4\u5DF2\u90E8\u7F72\u7684 skill contract \u662F\u5426\u4E3A\u5F53\u524D\u7248\u672C\u3002", - runtime_health_match: "\u5339\u914D", - runtime_health_mismatch: "\u4E0D\u5339\u914D", - runtime_health_package_ver: "Python \u5305 v{0}", - runtime_health_plugin_ver: "\u63D2\u4EF6 v{0}", - runtime_health_sync: "\u540C\u6B65\u8FD0\u884C\u65F6", - runtime_health_sync_done: - "\u8FD0\u884C\u65F6\u5DF2\u540C\u6B65\u81F3 v{0}", - runtime_health_sync_fail: - "\u8FD0\u884C\u65F6\u540C\u6B65\u5931\u8D25\uFF1A{0}", - runtime_health_syncing: "\u6B63\u5728\u540C\u6B65\u2026", - section_config: "\u5F53\u524D\u914D\u7F6E", - section_guide: "\u64CD\u4F5C\u65B9\u5F0F", - section_prep: "\u5B89\u88C5\u51C6\u5907", - section_prep_desc: - "\u9996\u6B21\u4F7F\u7528\u524D\uFF0C\u8BF7\u4F9D\u6B21\u5B8C\u6210\u4EE5\u4E0B\u51C6\u5907\uFF1A", - setup_done: - "\u2713 PaperForge \u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u6210", - setup_pending: - "\u5C1A\u672A\u5B89\u88C5\uFF0C\u5B8C\u6210\u5B89\u88C5\u51C6\u5907\u540E\u70B9\u51FB\u5B89\u88C5\u5411\u5BFC", - tab_features: "\u529F\u80FD", - tab_setup: "\u5B89\u88C5", - tab_maintenance: "\u7EF4\u62A4", - validate_base: "Base \u76EE\u5F55\u672A\u586B\u5199", - validate_fail: "\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25", - validate_index: "\u7D22\u5F15\u76EE\u5F55\u672A\u586B\u5199", - validate_key: "PaddleOCR API \u5BC6\u94A5\u672A\u586B\u5199", - validate_notes: "\u6B63\u6587\u76EE\u5F55\u672A\u586B\u5199", - validate_resources: "\u8D44\u6E90\u76EE\u5F55\u672A\u586B\u5199", - validate_system: "\u7CFB\u7EDF\u76EE\u5F55\u672A\u586B\u5199", - validate_vault: "Vault \u8DEF\u5F84\u672A\u586B\u5199", - validate_zotero: - "Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879", - wizard_agent_hint: - "\u9009\u62E9\u4F60\u4F7F\u7528\u7684 AI Agent \u5E73\u53F0\uFF0C\u5B89\u88C5\u65F6\u5C06\u6309\u5BF9\u5E94\u683C\u5F0F\u90E8\u7F72\u6280\u80FD\u6587\u4EF6\uFF1A", - wizard_dir_hint: - "\u8D44\u6E90\u76EE\u5F55\u662F\u6587\u732E\u6570\u636E\u7684\u7EDF\u4E00\u6839\u76EE\u5F55\uFF0C\u4EE5\u4E0B\u5B50\u76EE\u5F55\u5C06\u521B\u5EFA\u5728\u5176\u5185\u90E8\uFF1A", - wizard_dir_sub_hint: - "\u8D44\u6E90\u76EE\u5F55\u5185\u7684\u4E24\u4E2A\u5B50\u76EE\u5F55\uFF1A", - wizard_intro: - "\u672C\u5411\u5BFC\u5C06\u5F15\u5BFC\u60A8\u5B8C\u6210 PaperForge \u73AF\u5883\u7684\u5B8C\u6574\u914D\u7F6E\u3002\u5B89\u88C5\u8FC7\u7A0B\u4F1A\u81EA\u52A8\u521B\u5EFA\u6240\u6709\u76EE\u5F55\u7ED3\u6784\uFF0C\u65E0\u9700\u624B\u52A8\u64CD\u4F5C\u3002", - wizard_keys_hint: - "\u4EE5\u4E0B\u4E3A API \u5BC6\u94A5\u4E0E Zotero \u914D\u7F6E\uFF1A", - wizard_preview: - "\u7CFB\u7EDF\u6587\u4EF6\u548C Agent \u914D\u7F6E\u4F4D\u4E8E Vault \u6839\u76EE\u5F55\u4E0B\u3002\u6587\u732E\u6570\u636E\uFF08\u6B63\u6587\u3001\u7D22\u5F15\uFF09\u7EDF\u4E00\u5B58\u653E\u5728\u8D44\u6E90\u76EE\u5F55\u5185\u3002\u5B89\u88C5\u540E\u4ECD\u53EF\u5728\u8BBE\u7F6E\u4E2D\u4FEE\u6539\u3002", - wizard_safety: - "\u5B89\u5168\u8BF4\u660E\uFF1A\u5982\u679C\u4F60\u9009\u62E9\u7684\u76EE\u5F55\u91CC\u5DF2\u7ECF\u6709\u6587\u4EF6\uFF0C\u5B89\u88C5\u5411\u5BFC\u4F1A\u4FDD\u7559\u5DF2\u6709\u5185\u5BB9\uFF0C\u53EA\u8865\u5145\u7F3A\u5931\u7684 PaperForge \u6587\u4EF6\u548C\u76EE\u5F55\u3002", - wizard_step1: "\u6982\u89C8", - wizard_step2: "\u76EE\u5F55", - wizard_step3: "Agent", - wizard_step4: "\u5B89\u88C5", - wizard_step5: "\u5B8C\u6210", - wizard_skip_ocr_desc: - "OCR \u529F\u80FD\u5728\u914D\u7F6E\u6709\u6548\u7684 PaddleOCR API \u5BC6\u94A5\u4E4B\u524D\u4E0D\u53EF\u7528\u3002\u60A8\u53EF\u4EE5\u7EE7\u7EED\u5B8C\u6210\u8BBE\u7F6E\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002", - wizard_skip_ocr_continue: - "\u7EE7\u7EED\uFF0C\u7A0D\u540E\u914D\u7F6E\u5BC6\u94A5", - wizard_skip_ocr_back: "\u8FD4\u56DE\u914D\u7F6E", - wizard_api_hint_skip: - "OCR \u5BC6\u94A5\u4E3A\u9009\u586B\u9879 \u2014 \u53EF\u8DF3\u8FC7\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002", - wizard_sys_hint: - "\u72EC\u7ACB\u4E8E\u8D44\u6E90\u76EE\u5F55\u7684\u7CFB\u7EDF\u6587\u4EF6\uFF1A", - wizard_title: "PaperForge \u5B89\u88C5\u5411\u5BFC", - ocr_maint_no_action: "\u65E0\u9700\u5904\u7406", - ocr_maint_rebuild: "\u5EFA\u8BAE\u91CD\u5EFA", - ocr_maint_failed: "OCR \u5931\u8D25", - ocr_maint_limited: "\u7ED3\u679C\u4E00\u822C", - ocr_maint_needs_attention: "\u9700\u8981\u5904\u7406", - ocr_maint_limitations: "\u7ED3\u679C\u8BF4\u660E", - ocr_maint_hero_ok: "OCR \u6574\u4F53\u6B63\u5E38\u3002", - ocr_maint_hero_warn: - "OCR \u9700\u8981\u5173\u6CE8\uFF1A{rebuild} \u7BC7\u5EFA\u8BAE\u91CD\u5EFA\uFF0C{failed} \u7BC7\u5904\u7406\u5931\u8D25\u3002", - ocr_maint_hero_note: - "\u672C\u9875\u53EA\u63D0\u793A\u7EF4\u62A4\u540E\u5927\u6982\u7387\u4F1A\u6539\u5584\u7684\u95EE\u9898\u3002\u90E8\u5206\u8BBA\u6587\u6548\u679C\u4E00\u822C\uFF0C\u7EF4\u62A4\u672A\u5FC5\u80FD\u6539\u5584\u3002", - ocr_maint_limitations_intro: - "\u8FD9\u7C7B\u8BBA\u6587\u901A\u5E38\u8868\u793A\u7248\u5F0F\u590D\u6742\u6216\u4FE1\u53F7\u504F\u5F31\uFF0CPaperForge \u76EE\u524D\u6CA1\u6709\u9AD8\u7F6E\u4FE1\u5EA6\u7684\u7EF4\u62A4\u5EFA\u8BAE\u3002", - ocr_maint_all_papers: "\u5168\u90E8\u8BBA\u6587", - ocr_maint_rebuild_btn: "\u91CD\u5EFA\u7ED3\u679C", - maintenance_group_retry: "\u9700\u8981\u91CD\u8BD5", - maintenance_group_rebuild: "\u53EF\u91CD\u5EFA\u7ED3\u679C", - maintenance_group_legacy: - "\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09", - maintenance_btn_retry: "\u91CD\u8BD5", - maintenance_btn_rebuild: "\u91CD\u5EFA", - maintenance_btn_upgrade: "\u5347\u7EA7", - maintenance_refresh_spinning: "\u6B63\u5728\u66F4\u65B0\u2026", - maintenance_all_good: "\u2705 \u5168\u90E8\u6B63\u5E38", - maintenance_n_pending: "{n} \u7BC7\u9700\u8981\u5904\u7406", - version_panel_title: "\u7248\u672C\u5386\u53F2", - version_panel_back: "\u8FD4\u56DE", - version_filter_placeholder: "\u641C\u7D22\u8BBA\u6587...", - version_papers_count: "{n} \u7BC7\u8BBA\u6587", - version_current: "\u5F53\u524D", - version_restore_btn: "\u6062\u590D", - version_compare_btn: "\u5BF9\u6BD4", - version_restore_selected: "\u6062\u590D\u9009\u4E2D\u7248\u672C", - version_clear_old: "\u6E05\u9664\u65E7\u7248\u672C (\u91CA\u653E {size})", - version_no_backups: - "\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5386\u53F2\u7248\u672C", - version_restore_confirm: - "\u786E\u8BA4\u5C06 {paper} \u6062\u590D\u5230 {label}\uFF1F", - version_restore_done: "\u5DF2\u6062\u590D\u5230 {label}", - version_compare_title: "{vA} vs {vB}", - version_compare_paragraphs: "{n} \u6BB5\u6709\u53D8\u5316", - version_error_read: "\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C\u6570\u636E", - }, - }, - kr = null; -function Js(_) { - try { - let y = _.vault; - if (typeof y.getConfig == "function") { - let r = y.getConfig("language"); - if (r && String(r).startsWith("zh")) return "zh"; - } - } catch (y) {} - try { - if (typeof localStorage != "undefined") { - let y = localStorage.getItem("language"); - if (y && String(y).startsWith("zh")) return "zh"; - } - } catch (y) {} - return "en"; -} -function kn(_) { - kr = Js(_) === "zh" ? wr.zh : wr.en; -} -function f(_) { - return (kr && kr[_]) || wr.en[_] || _; -} -var z = require("obsidian"), - ie = ae(require("fs")), - me = ae(require("path")), - Vn = ae(require("os")), - oe = require("child_process"); -var qn = ae(Sr()); -var Ve = ae(require("fs")), - $e = ae(require("path")), - Pn = ae(require("os")), - Ke = require("child_process"), - Pr = null, - Sn = !1; -function re(_, y, r, n) { - let i = r || Ve, - a = n || Ke.execFileSync; - if (y && y.python_path && y.python_path.trim()) { - let u = y.python_path.trim(); - if (i.existsSync(u)) return { path: u, source: "manual", extraArgs: [] }; - } - let c = [ - $e.join(_, ".paperforge-test-venv", "Scripts", "python.exe"), - $e.join(_, ".venv", "Scripts", "python.exe"), - $e.join(_, "venv", "Scripts", "python.exe"), - ]; - for (let u of c) - try { - if (i.existsSync(u)) - return { path: u, source: "auto-detected", extraArgs: [] }; - } catch (p) {} - let l = [ - { path: "py", extraArgs: ["-3"] }, - { path: "python", extraArgs: [] }, - { path: "python3", extraArgs: [] }, - ]; - for (let u of l) - try { - let p = a(u.path, [...u.extraArgs, "--version"], { - encoding: "utf-8", - timeout: 5e3, - windowsHide: !0, - }); - if (p && p.toLowerCase().includes("python")) - return { - path: u.path, - source: "auto-detected", - extraArgs: u.extraArgs, - }; - } catch (p) {} - return { path: "python", source: "auto-detected", extraArgs: [] }; -} -function Cn(_, y, r, n, i) { - n === void 0 && (n = 1e4); - let a = i || Ke.execFile; - return new Promise((c) => { - a( - _, - ["-c", "import paperforge; print(paperforge.__version__)"], - { cwd: r, timeout: n }, - (l, u) => { - if (l) { - c({ - status: "not-installed", - pyVersion: null, - pluginVersion: y, - error: l.message, - }); - return; - } - let p = (u && u.trim()) || null; - c( - p === y - ? { status: "match", pyVersion: p, pluginVersion: y, error: null } - : { - status: "mismatch", - pyVersion: p, - pluginVersion: y, - error: null, - } - ); - } - ); - }); -} -function Fn(_, y, r) { - r === void 0 && (r = []); - let n = `paperforge==${y}`, - i = `git+https://github.com/LLLin000/PaperForge.git@${y}`, - a = [...r, "-m", "pip", "install", "--upgrade", n], - c = [...r, "-m", "pip", "install", "--upgrade", i]; - return { cmd: _, url: i, args: c, pypiArgs: a, gitArgs: c, timeout: 12e4 }; -} -function Rn(_, y, r, n, i, a) { - let c = i || Ke.spawn; - return new Promise((l) => { - let u = Date.now(), - p = { cwd: r, timeout: n, windowsHide: !0 }; - a && (p.env = a); - let h = c(_, y, p), - b = [], - k = []; - (h.stdout.on("data", (g) => { - b.push(g.toString("utf-8")); - }), - h.stderr.on("data", (g) => { - k.push(g.toString("utf-8")); - }), - h.on("close", (g) => { - l({ - stdout: b.join(""), - stderr: k.join(""), - exitCode: g, - elapsed: Date.now() - u, - }); - }), - h.on("error", (g) => { - l({ - stdout: b.join(""), - stderr: - k.join("") + - ` -` + - g.message, - exitCode: -1, - elapsed: Date.now() - u, - }); - })); - }); -} -function Cr() { - if (Sn) return Pr; - Sn = !0; - try { - let _; - if (process.platform === "win32") { - let y = process.env.ComSpec || "C:\\Windows\\System32\\cmd.exe"; - _ = (0, Ke.execFileSync)(y, ["/c", "where", "git"], { - timeout: 5e3, - windowsHide: !0, - encoding: "utf-8", - }); - } else - _ = (0, Ke.execFileSync)("which", ["git"], { - timeout: 5e3, - encoding: "utf-8", - }); - if (_) { - let y = _.split( - ` -` - )[0].trim(); - y && (Pr = $e.dirname(y)); - } - } catch (_) {} - return Pr; -} -function ot() { - let _ = { ...process.env }, - y = process.platform, - r = Pn.homedir(), - n = [], - i = Cr(); - (i && n.push(i), - y === "darwin" - ? n.push( - "/opt/homebrew/bin", - "/usr/local/bin", - "/usr/bin", - `${r}/.local/bin` - ) - : y === "linux" && - n.push("/usr/local/bin", "/usr/bin", `${r}/.local/bin`)); - let a = _.PATH || ""; - return ((_.PATH = [...n, a].filter(Boolean).join($e.delimiter)), _); -} -function Tn(_) { - return String(_) - .toLowerCase() - .replace(/[^a-z0-9]/g, "") - .includes("betterbibtex"); -} -function Fr(_) { - if (!_) return !1; - try { - if (!Ve.existsSync(_)) return !1; - for (let y of Ve.readdirSync(_)) if (Tn(y)) return !0; - } catch (y) {} - return !1; -} -function Jt(_) { - if (!_) return !1; - try { - if (!Ve.existsSync(_)) return !1; - for (let y of Ve.readdirSync(_)) { - let r = $e.join(_, y, "extensions"); - try { - if (!Ve.existsSync(r)) continue; - for (let n of Ve.readdirSync(r)) if (Tn(n)) return !0; - } catch (n) {} - } - } catch (y) {} - return !1; -} -var lt = ae(require("fs")), - he = ae(require("path")), - Dn = require("child_process"), - qe = null; -function Qs(_, y) { - let r = y || lt, - n = he.join(_, "paperforge.json"), - i = { - system_dir: "System", - resources_dir: "Resources", - literature_dir: "Literature", - base_dir: "Bases", - }; - try { - if (!r.existsSync(n)) - return { ...i, _warning: "paperforge.json not found; using defaults" }; - let a = r.readFileSync(n, "utf-8"), - c = JSON.parse(a), - l = c.vault_config || {}; - return { - system_dir: l.system_dir || c.system_dir || i.system_dir, - resources_dir: l.resources_dir || c.resources_dir || i.resources_dir, - literature_dir: l.literature_dir || c.literature_dir || i.literature_dir, - base_dir: l.base_dir || c.base_dir || i.base_dir, - _warning: null, - }; - } catch (a) { - return ( - console.warn( - "PaperForge: Failed to read paperforge.json, using defaults", - a - ), - { ...i, _warning: "paperforge.json invalid; using defaults" } - ); - } -} -function Te(_, y) { - let r = Qs(_, y), - n = he.join(_, r.system_dir, "PaperForge"); - return { - vault: _, - systemDir: n, - indexesDir: he.join(n, "indexes"), - logsDir: he.join(n, "logs"), - dbPath: he.join(n, "indexes", "paperforge.db"), - memoryStatePath: he.join(n, "indexes", "memory-runtime-state.json"), - vectorStatePath: he.join(n, "indexes", "vector-runtime-state.json"), - healthStatePath: he.join(n, "indexes", "runtime-health.json"), - buildStatePath: he.join(n, "indexes", "vector-build-state.json"), - orphanStatePath: he.join(n, "indexes", "sync-orphan-state.json"), - exportsDir: he.join(n, "exports"), - ocrDir: he.join(n, "ocr"), - pluginDataPath: he.join( - _, - ".obsidian", - "plugins", - "paperforge", - "data.json" - ), - pfJsonPath: he.join(_, "paperforge.json"), - configWarning: r._warning, - }; -} -function Rr(_) { - try { - return lt.existsSync(_) ? JSON.parse(lt.readFileSync(_, "utf-8")) : null; - } catch (y) { - return null; - } -} -function Xs(_) { - let y = Te(_); - return Rr(y.memoryStatePath); -} -function Rt(_) { - let y = Te(_); - return Rr(y.vectorStatePath); -} -function Tr(_) { - let y = Te(_); - return Rr(y.healthStatePath); -} -function An(_) { - var r; - let y = Tr(_); - return !!(y && ((r = y.summary) == null ? void 0 : r.status) === "ok"); -} -function Gt(_) { - let y = Xs(_); - return !y || y.paper_count_db === 0 - ? "DB not found. Run paperforge memory build." - : "Papers: " + y.paper_count_db + " | " + (y.fresh ? "fresh" : "stale"); -} -function gt(_) { - var n, i, a; - let y = Rt(_); - return y - ? y.healthy === !1 - ? "Vector index unreadable - rebuild required" - : "Chunks: " + - (((n = y.chunk_count) != null ? n : 0) + - ((i = y.body_chunk_count) != null ? i : 0) + - ((a = y.object_chunk_count) != null ? a : 0)) + - " | " + - y.model + - " | " + - y.mode - : "Status unavailable"; -} -function Ue(_, y) { - if (qe) return qe; - if (y && y.python_path && y.python_path.trim()) { - let i = y.python_path.trim(); - if (lt.existsSync(i)) - return ((qe = { path: i, source: "manual", extraArgs: [] }), qe); - } - let r = [ - he.join(_, ".paperforge-test-venv", "Scripts", "python.exe"), - he.join(_, ".venv", "Scripts", "python.exe"), - he.join(_, "venv", "Scripts", "python.exe"), - ]; - for (let i = 0; i < r.length; i++) - if (lt.existsSync(r[i])) - return ( - (qe = { path: r[i], source: "auto-detected", extraArgs: [] }), - qe - ); - let n = [ - { path: "py", extraArgs: ["-3"] }, - { path: "python", extraArgs: [] }, - { path: "python3", extraArgs: [] }, - ]; - for (let i = 0; i < n.length; i++) - try { - let a = n[i], - c = (0, Dn.execFileSync)(a.path, a.extraArgs.concat(["--version"]), { - encoding: "utf-8", - timeout: 5e3, - windowsHide: !0, - }); - if (c && c.toLowerCase().indexOf("python") !== -1) - return ( - (qe = { - path: a.path, - source: "auto-detected", - extraArgs: a.extraArgs, - }), - qe - ); - } catch (a) {} - return ( - (qe = { path: "python", source: "auto-detected", extraArgs: [] }), - qe - ); -} -function Dr(_, y, r) { - return !_ || - typeof _ != "object" || - !Object.prototype.hasOwnProperty.call(_, y) - ? !!r - : !!_[y]; -} -function Bn(_, y, r) { - let n = !Dr(_, y, r); - return (_ && typeof _ == "object" && (_[y] = n), n); -} -var xe = require("obsidian"), - Me = ae(require("fs")), - Mn = ae(require("path")), - Ln = ae(require("https")), - Dt = require("child_process"); -function On(_, y) { - return !y || !y.trim() - ? { blocked: !0, reason: "zotero" } - : _ - ? { blocked: !1 } - : { blocked: !0, reason: "ocr" }; -} -var Ar = class extends xe.Modal { - constructor(r, n, i, a) { - super(r); - this._rowEls = []; - ((this.orphans = n.map((c, l) => ({ ...c, _selected: !0, _idx: l }))), - (this.vaultPath = i), - (this.py = a)); - } - _updateUI() { - let r = this.orphans.filter((n) => n._selected); - (this._countEl.setText( - f("orphan_delete_selected").replace("{count}", String(r.length)) - ), - this._selectAllBtn.setText( - r.length === this.orphans.length - ? f("orphan_deselect_all") - : f("orphan_select_all") - )); - for (let n of this.orphans) { - let i = this._rowEls[n._idx]; - i && i.toggleClass("paperforge-orphan-dimmed", !n._selected); - } - } - onOpen() { - let { contentEl: r } = this; - (r.addClass("paperforge-modal"), - r.createEl("h2", { - text: f("orphan_title").replace("{count}", String(this.orphans.length)), - }), - r.createEl("p", { cls: "paperforge-modal-desc", text: f("orphan_desc") }), - (this._rowEls = [])); - let n = r.createEl("div", { cls: "paperforge-orphan-list" }); - for (let a of this.orphans) { - let c = n.createEl("div", { - cls: - "paperforge-orphan-row" + - (a._selected ? "" : " paperforge-orphan-dimmed"), - }); - this._rowEls.push(c); - let l = c.createEl("div", { cls: "paperforge-orphan-info" }), - u = l.createEl("div", { cls: "paperforge-orphan-header" }); - u.createEl("span", { - cls: "paperforge-orphan-key", - text: a.citation_key || a.key, - }); - let p = u.createEl("span", { cls: "paperforge-orphan-tags" }); - (p.createEl("span", { - cls: "paperforge-tag " + (a.has_pdf ? "tag-pdf" : "tag-nopdf"), - text: a.has_pdf ? "PDF" : "no PDF", - }), - a.collection_path && - p.createEl("span", { - cls: "paperforge-tag tag-collection", - text: a.collection_path, - }), - a.title && - l.createEl("div", { cls: "paperforge-orphan-title", text: a.title })); - let h = []; - (a.authors && h.push(a.authors), - a.year && h.push(a.year), - h.length > 0 && - l.createEl("div", { - cls: "paperforge-orphan-meta", - text: h.join(" \xB7 "), - }), - l.createEl("div", { - cls: "paperforge-orphan-explain", - text: f("orphan_explain"), - }), - c.addEventListener("click", () => { - ((a._selected = !a._selected), this._updateUI()); - })); - } - let i = r.createEl("div", { cls: "paperforge-modal-actions" }); - ((this._selectAllBtn = i.createEl("button", { - cls: "paperforge-step-btn", - text: "Deselect all", - })), - this._selectAllBtn.addEventListener("click", () => { - let a = this.orphans.every((c) => c._selected); - for (let c of this.orphans) c._selected = !a; - this._updateUI(); - }), - (this._countEl = i.createEl("button", { - cls: "paperforge-step-btn mod-cta", - text: "Delete " + this.orphans.length + " selected", - })), - i - .createEl("button", { cls: "paperforge-step-btn", text: "Keep all" }) - .addEventListener("click", () => this.close()), - this._countEl.addEventListener("click", () => { - let a = this.orphans.filter((l) => l._selected); - if (a.length === 0) { - new xe.Notice(f("orphan_none_selected")); - return; - } - if ( - (this._countEl.setText("Deleting..."), - this._countEl.setAttr("disabled", ""), - this._selectAllBtn.setAttr("disabled", ""), - !this.py || !this.py.path) - ) { - (new xe.Notice("PaperForge: Python not found"), this.close()); - return; - } - let c = a.map((l) => l.key); - (0, Dt.execFile)( - this.py.path, - [ - ...this.py.extraArgs, - "-m", - "paperforge", - "--vault", - this.vaultPath, - "prune", - "--force", - "--json", - ...c, - ], - { cwd: this.vaultPath, timeout: 6e4 }, - (l, u) => { - if (l) { - (new xe.Notice("PaperForge: prune failed"), this.close()); - return; - } - try { - let p = JSON.parse(u), - h = (p.data && p.data.deleted) || []; - new xe.Notice("Deleted " + h.length + " orphan workspace(s)"); - } catch (p) { - new xe.Notice("PaperForge: prune done"); - } - this.close(); - } - ); - })); - } - onClose() { - this.contentEl.empty(); - } -}; -function Qt(_, y, r) { - console.log("[PF] checkOrphanState called"); - try { - let i = Te(r).orphanStatePath; - if (!Me.existsSync(i)) { - console.log("[PF] orphan file NOT FOUND"); - return; - } - console.log("[PF] orphan file FOUND"); - let a = Me.readFileSync(i, "utf-8"), - l = JSON.parse(a).orphans || []; - if ((console.log("[PF] orphans count:", l.length), l.length === 0)) return; - let u = Ue(r, y.settings); - (console.log("[PF] py.path:", u ? u.path : "null"), - new Ar(_, l, r, u).open(), - Me.unlinkSync(i), - console.log("[PF] orphan file cleaned")); - } catch (n) { - console.log("[PF] checkOrphanState exception:", n.message || n); - } -} -var Tt = class extends xe.Modal { - constructor(r, n) { - super(r); - this._pendingSave = null; - this._showSkipConfirm = !1; - ((this.plugin = n), (this._step = 1)); - } - onOpen() { - this._render(); - } - onClose() { - this.contentEl.empty(); - } - _render() { - let { contentEl: r } = this; - (r.empty(), - r.addClass("paperforge-modal"), - this._renderStepIndicator(), - this._renderStepContent(), - this._renderNavigation()); - } - _renderStepIndicator() { - let r = [ - f("wizard_step1"), - f("wizard_step2"), - f("wizard_step3"), - f("wizard_step4"), - f("wizard_step5"), - ], - n = this.contentEl.createEl("div", { cls: "paperforge-step-bar" }); - r.forEach((i, a) => { - let c = a + 1, - l = n.createEl("div", { - cls: `paperforge-step-dot ${c === this._step ? "active" : ""} ${c < this._step ? "done" : ""}`, - }); - (l.createEl("span", { cls: "paperforge-step-num", text: `${c}` }), - l.createEl("span", { cls: "paperforge-step-label", text: i })); - }); - } - _renderStepContent() { - let r = this.contentEl.createEl("div", { cls: "paperforge-step-content" }); - switch (this._step) { - case 1: - this._stepOverview(r); - break; - case 2: - this._stepDirectories(r); - break; - case 3: - this._stepKeys(r); - break; - case 4: - this._stepInstall(r); - break; - case 5: - this._stepComplete(r); - break; - } - } - _renderNavigation() { - let r = this.contentEl.createEl("div", { cls: "paperforge-step-nav" }); - (this._step > 1 && - r - .createEl("button", { cls: "paperforge-step-btn", text: f("nav_prev") }) - .addEventListener("click", () => { - (this._step--, (this._showSkipConfirm = !1), this._render()); - }), - this._step < 5 - ? r - .createEl("button", { - cls: "paperforge-step-btn mod-cta", - text: f("nav_next"), - }) - .addEventListener("click", () => { - if (this._step === 3) { - let i = this._validateStep3(); - if (i.blocked) { - if (i.reason === "zotero") return; - if (i.reason === "ocr") { - ((this._showSkipConfirm = !0), this._render()); - return; - } - } - } - (this._step++, (this._showSkipConfirm = !1), this._render()); - }) - : r - .createEl("button", { - cls: "paperforge-step-btn", - text: f("nav_close"), - }) - .addEventListener("click", () => this.close())); - } - _validateStep3() { - let r = this.plugin.settings, - n = On(this._apiKeyValidated, r.zotero_data_dir); - if (n.reason === "ocr") return n; - let i = (r.zotero_data_dir || "").trim(); - if (!i) - return ( - new xe.Notice( - "Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879\uFF0C\u8BF7\u586B\u5199\u8DEF\u5F84" - ), - { blocked: !0, reason: "zotero" } - ); - if (!Me.existsSync(i)) - return ( - new xe.Notice( - "Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u5B58\u5728" - ), - { blocked: !0, reason: "zotero" } - ); - if (!Me.statSync(i).isDirectory()) - return ( - new xe.Notice( - "Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u662F\u4E00\u4E2A\u76EE\u5F55" - ), - { blocked: !0, reason: "zotero" } - ); - let a = Mn.join(i, "storage"); - return !Me.existsSync(a) || !Me.statSync(a).isDirectory() - ? (new xe.Notice( - "Zotero \u6570\u636E\u76EE\u5F55\u4E2D\u672A\u627E\u5230 storage/ \u5B50\u76EE\u5F55" - ), - { blocked: !0, reason: "zotero" }) - : { blocked: !1 }; - } - _stepOverview(r) { - (r.createEl("h2", { text: f("wizard_title") }), - r.createEl("p", { text: f("wizard_intro") })); - let n = this.plugin.settings, - i = this.app.vault.adapter.basePath, - a = r.createEl("div", { cls: "paperforge-dir-tree" }), - c = a.createEl("div", { cls: "paperforge-dir-node root" }); - c.textContent = `\u{1F4C1} Vault (${i})`; - let l = a.createEl("div", { cls: "paperforge-dir-children" }), - u = l.createEl("div", { cls: "paperforge-dir-node folder" }); - ((u.textContent = `\u{1F4C1} ${n.resources_dir || "Resources"}/ \u2014 \u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08Base \u6570\u636E\u6765\u6E90\uFF09`), - u - .createEl("div", { cls: "paperforge-dir-children" }) - .createEl("div", { - cls: "paperforge-dir-node file", - text: `\u{1F4C1} ${n.literature_dir || "Literature"}/ \u2014 \u6587\u732E\u5361\u7247`, - }), - l.createEl("div", { - cls: "paperforge-dir-node folder", - text: `\u{1F4C1} ${n.base_dir || "Bases"}/ \u2014 \u6570\u636E\u7BA1\u7406\u9762\u677F`, - }), - l.createEl("div", { - cls: "paperforge-dir-node folder", - text: `\u{1F4C1} ${n.system_dir || "System"}/ \u2014 Zotero \u8F6F\u94FE\u63A5 + PaperForge \u7CFB\u7EDF\u6587\u4EF6\u5939`, - }), - r.createEl("p", { - text: f("wizard_preview"), - cls: "paperforge-modal-hint", - }), - r.createEl("p", { - text: f("wizard_safety"), - cls: "paperforge-modal-hint", - })); - let h = r.createEl("div", { cls: "paperforge-summary" }), - b = [ - { - label: f("dir_resources"), - val: `${i}/${n.resources_dir || "Resources"}`, - }, - { - label: f("dir_notes"), - val: `${i}/${n.resources_dir || "Resources"}/${n.literature_dir || "Literature"}`, - }, - { label: f("dir_base"), val: `${i}/${n.base_dir || "Bases"}` }, - { label: f("dir_system"), val: `${i}/${n.system_dir || "System"}` }, - ]; - for (let k of b) { - let g = h.createEl("div", { cls: "paperforge-summary-row" }); - (g.createEl("span", { cls: "paperforge-summary-label", text: k.label }), - g.createEl("span", { cls: "paperforge-summary-value", text: k.val })); - } - } - _stepDirectories(r) { - (r.createEl("h2", { text: f("wizard_step2") }), - r.createEl("p", { text: f("wizard_intro") })); - let n = this.plugin.settings, - i = this.app.vault.adapter.basePath; - (this._modalField(r, f("dir_vault"), i, !0), - r.createEl("p", { - text: f("wizard_dir_hint"), - cls: "paperforge-modal-hint", - }), - this._modalInput( - r, - "\u8D44\u6E90\u76EE\u5F55\uFF08\u521B\u5EFA\u6587\u732E\u5361\u7247\u76EE\u5F55\u7684\u5730\u65B9\uFF09", - "resources_dir", - n.resources_dir, - "Resources" - ), - r.createEl("p", { - text: f("wizard_dir_sub_hint"), - cls: "paperforge-modal-hint", - }), - this._modalInput( - r, - "\u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08\u5B58\u653E\u6587\u732E\u5361\u7247\u7684\u5730\u65B9\uFF0CBase \u6570\u636E\u6765\u6E90\uFF09", - "literature_dir", - n.literature_dir, - "Literature" - ), - r.createEl("p", { - text: f("wizard_sys_hint"), - cls: "paperforge-modal-hint", - }), - this._modalInput( - r, - "\u7CFB\u7EDF\u76EE\u5F55\uFF08\u5B58\u653E Zotero \u8F6F\u94FE\u63A5\u548C PaperForge \u7CFB\u7EDF\u6587\u4EF6\uFF09", - "system_dir", - n.system_dir, - "System" - ), - this._modalInput( - r, - "Base \u76EE\u5F55\uFF08\u5B58\u653E\u6570\u636E\u7BA1\u7406\u9762\u677F\u7684\u5730\u65B9\uFF09", - "base_dir", - n.base_dir, - "Bases" - ), - r.createEl("p", { - text: f("wizard_safety"), - cls: "paperforge-modal-hint", - })); - let a = r.createEl("div", { cls: "paperforge-summary" }), - c = [ - { label: f("dir_resources"), val: `${i}/${n.resources_dir || ""}` }, - { - label: f("dir_notes"), - val: `${i}/${n.resources_dir || ""}/${n.literature_dir || ""}`, - }, - { label: f("dir_system"), val: `${i}/${n.system_dir || ""}` }, - { label: f("dir_base"), val: `${i}/${n.base_dir || ""}` }, - ]; - for (let l of c) { - let u = a.createEl("div", { cls: "paperforge-summary-row" }); - (u.createEl("span", { cls: "paperforge-summary-label", text: l.label }), - u.createEl("span", { cls: "paperforge-summary-value", text: l.val })); - } - } - _stepKeys(r) { - if ( - (r.createEl("h2", { text: f("wizard_step3") }), this._showSkipConfirm) - ) { - this._renderSkipConfirm(r); - return; - } - let n = this.plugin.settings; - r.createEl("p", { - text: f("wizard_agent_hint"), - cls: "paperforge-modal-hint", - }); - let i = [ - { key: "opencode", name: "OpenCode" }, - { key: "claude", name: "Claude Code" }, - { key: "cursor", name: "Cursor" }, - { key: "github_copilot", name: "GitHub Copilot" }, - { key: "windsurf", name: "Windsurf" }, - { key: "codex", name: "Codex" }, - { key: "gemini", name: "Gemini CLI" }, - { key: "cline", name: "Cline" }, - ], - a = r.createEl("div", { cls: "paperforge-modal-field" }); - a.createEl("label", { - cls: "paperforge-modal-label", - text: f("label_agent"), - }); - let c = a.createEl("select", { cls: "paperforge-modal-select" }); - for (let k of i) { - let g = c.createEl("option", { text: k.name, attr: { value: k.key } }); - k.key === (n.agent_platform || "opencode") && (g.selected = !0); - } - (c.addEventListener("change", () => { - ((n.agent_platform = c.value), - this._pendingSave && clearTimeout(this._pendingSave), - (this._pendingSave = setTimeout(() => { - (this.plugin.saveSettings(), (this._pendingSave = null)); - }, 500))); - }), - r.createEl("p", { - text: f("wizard_keys_hint"), - cls: "paperforge-modal-hint", - })); - let l = r.createEl("div", { cls: "paperforge-modal-field" }); - l.createEl("label", { - cls: "paperforge-modal-label", - text: f("field_paddleocr"), - }); - let u = l.createEl("input", { - cls: "paperforge-modal-input", - attr: { type: "password", placeholder: "API Key" }, - }); - ((u.value = n.paddleocr_api_key || ""), - (this._apiKeyValidated = !1), - (this._apiKeyStatus = l.createEl("span", { - cls: "paperforge-apikey-status", - text: "", - }))); - let p = l.createEl("button", { - cls: "paperforge-step-btn", - text: "\u9A8C\u8BC1", - }); - (p.addEventListener("click", () => this._validateApiKey(u.value, p)), - u.addEventListener("input", () => { - ((n.paddleocr_api_key = u.value), - (this._apiKeyValidated = !1), - (this._apiKeyStatus.textContent = ""), - (this._apiKeyStatus.className = "paperforge-apikey-status")); - }), - this._pendingSave && clearTimeout(this._pendingSave), - (this._pendingSave = setTimeout(() => { - (this.plugin.saveSettings(), (this._pendingSave = null)); - }, 500)), - r.createEl("p", { - text: f("wizard_api_hint_skip"), - cls: "paperforge-modal-hint", - })); - let h = r.createEl("div", { cls: "paperforge-modal-field" }); - h.createEl("label", { - cls: "paperforge-modal-label", - text: f("field_zotero_data"), - }); - let b = h.createEl("input", { - cls: "paperforge-modal-input", - attr: { type: "text", placeholder: f("field_zotero_placeholder") }, - }); - ((b.value = n.zotero_data_dir || ""), - b.addEventListener("input", () => { - ((n.zotero_data_dir = b.value), - this._pendingSave && clearTimeout(this._pendingSave), - (this._pendingSave = setTimeout(() => { - (this.plugin.saveSettings(), (this._pendingSave = null)); - }, 500))); - })); - } - _validateApiKey(r, n) { - if (!r || r.length < 10) { - ((this._apiKeyStatus.textContent = - "\u5BC6\u94A5\u683C\u5F0F\u4E0D\u6B63\u786E\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002"), - (this._apiKeyStatus.className = "paperforge-apikey-status error")); - return; - } - ((n.disabled = !0), - (n.textContent = "\u9A8C\u8BC1\u4E2D\u2026"), - (this._apiKeyStatus.textContent = "\u6B63\u5728\u9A8C\u8BC1\u2026"), - (this._apiKeyStatus.className = "paperforge-apikey-status")); - let i = JSON.stringify({ model: "PaddleOCR-VL-1.5" }), - a = { - hostname: "paddleocr.aistudio-app.com", - path: "/api/v2/ocr/jobs", - method: "POST", - headers: { - Authorization: "bearer " + r, - "Content-Type": "application/json", - "Content-Length": Buffer.byteLength(i), - }, - timeout: 1e4, - }, - c = Ln.request(a, (l) => { - ((n.disabled = !1), (n.textContent = "\u9A8C\u8BC1")); - let u = ""; - (l.on("data", (p) => (u += p)), - l.on("end", () => { - try { - let p = JSON.parse(u); - l.statusCode === 400 && p.code === 10001 - ? ((this._apiKeyStatus.textContent = - "\u2713 \u5BC6\u94A5\u6709\u6548"), - (this._apiKeyStatus.className = - "paperforge-apikey-status ok"), - (this._apiKeyValidated = !0)) - : l.statusCode === 401 - ? ((this._apiKeyStatus.textContent = - "\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5BC6\u94A5\u65E0\u6548\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002"), - (this._apiKeyStatus.className = - "paperforge-apikey-status error"), - (this._apiKeyValidated = !1)) - : ((this._apiKeyStatus.textContent = - "\u9A8C\u8BC1\u5931\u8D25\uFF1AAPI \u8FD4\u56DE " + - l.statusCode + - "\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002"), - (this._apiKeyStatus.className = - "paperforge-apikey-status error"), - (this._apiKeyValidated = !1)); - } catch (p) { - ((this._apiKeyStatus.textContent = - "\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u89E3\u6790\u54CD\u5E94\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002"), - (this._apiKeyStatus.className = - "paperforge-apikey-status error"), - (this._apiKeyValidated = !1)); - } - })); - }); - (c.on("error", (l) => { - ((n.disabled = !1), - (n.textContent = "\u9A8C\u8BC1"), - (this._apiKeyStatus.textContent = - "\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u8FDE\u63A5 (" + - l.message + - ")\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002"), - (this._apiKeyStatus.className = "paperforge-apikey-status error"), - (this._apiKeyValidated = !1)); - }), - c.write(i), - c.end()); - } - _renderSkipConfirm(r) { - r.createEl("p", { - text: f("wizard_skip_ocr_desc"), - cls: "paperforge-modal-desc", - }); - let n = r.createEl("div", { cls: "paperforge-modal-actions" }); - (n - .createEl("button", { - cls: "paperforge-step-btn mod-cta", - text: f("wizard_skip_ocr_continue"), - }) - .addEventListener("click", () => { - ((this._showSkipConfirm = !1), this._step++, this._render()); - }), - n - .createEl("button", { - cls: "paperforge-step-btn", - text: f("wizard_skip_ocr_back"), - }) - .addEventListener("click", () => { - ((this._showSkipConfirm = !1), this._render()); - })); - } - _modalField(r, n, i, a) { - let c = r.createEl("div", { cls: "paperforge-modal-field" }); - c.createEl("label", { cls: "paperforge-modal-label", text: n }); - let l = c.createEl("input", { - cls: "paperforge-modal-input", - attr: { type: "text" }, - }); - ((l.value = i), (l.disabled = !!a)); - } - _modalInput(r, n, i, a, c) { - let l = r.createEl("div", { cls: "paperforge-modal-field" }); - l.createEl("label", { cls: "paperforge-modal-label", text: n }); - let u = l.createEl("input", { - cls: "paperforge-modal-input", - attr: { type: "text", placeholder: c || "" }, - }); - u.value = a; - let p = this.plugin.settings; - u.addEventListener("input", () => { - ((p[i] = u.value), - this._pendingSave && clearTimeout(this._pendingSave), - (this._pendingSave = setTimeout(() => { - (this.plugin.saveSettings(), (this._pendingSave = null)); - }, 500))); - }); - } - _modalSecret(r, n, i, a, c) { - let l = r.createEl("div", { cls: "paperforge-modal-field" }); - l.createEl("label", { cls: "paperforge-modal-label", text: n }); - let u = l.createEl("input", { - cls: "paperforge-modal-input", - attr: { type: "password", placeholder: c || "" }, - }); - u.value = a; - let p = this.plugin.settings; - u.addEventListener("input", () => { - ((p[i] = u.value), - this._pendingSave && clearTimeout(this._pendingSave), - (this._pendingSave = setTimeout(() => { - (this.plugin.saveSettings(), (this._pendingSave = null)); - }, 500))); - }); - } - _stepInstall(r) { - (r.createEl("h2", { text: f("wizard_step4") }), - (this._installLog = r.createEl("div", { - cls: "paperforge-install-log", - }))); - let n = r.createEl("button", { - cls: "paperforge-step-btn mod-cta", - text: f("install_btn"), - }); - n.addEventListener("click", () => this._runInstall(n)); - } - async _runInstall(r) { - var l, u, p, h, b, k; - ((r.disabled = !0), - (r.textContent = f("install_btn_running")), - this._installLog.setText( - f("install_validating") + - ` -` - ), - this._log(f("install_validating"))); - let n = this.plugin.settings, - i = this._validate(); - if (i.length > 0) { - (this._log(f("validate_fail") + ":"), - i.forEach((g) => this._log(" \u2717 " + g)), - (r.disabled = !1), - (r.textContent = f("install_btn_retry"))); - return; - } - let a = (g, x = {}) => - new Promise((C, R) => { - let { path: S, extraArgs: F = [] } = re( - n.vault_path.trim(), - this.plugin.settings, - void 0, - void 0 - ), - B = (0, Dt.spawn)(S, [...F, ...g], { - cwd: n.vault_path.trim(), - env: ot(), - timeout: 12e4, - ...x, - }), - A = "", - v = ""; - (B.stdout.on("data", (w) => { - let O = w.toString("utf-8"); - ((A += O), x.logStdout && this._processSetupOutput(O)); - }), - B.stderr.on("data", (w) => { - let O = w.toString("utf-8"); - ((v += O), this._log("[stderr] " + O.trim())); - }), - B.on("close", (w) => { - w === 0 - ? C({ stdout: A, stderr: v }) - : R(new Error(v.trim() || A.trim() || `exit code ${w}`)); - }), - B.on("error", (w) => R(w))); - }), - c = [ - "-m", - "paperforge", - "--vault", - n.vault_path.trim(), - "setup", - "--headless", - "--system-dir", - n.system_dir.trim(), - "--resources-dir", - n.resources_dir.trim(), - "--literature-dir", - n.literature_dir.trim(), - "--base-dir", - n.base_dir.trim(), - "--agent", - n.agent_platform || "opencode", - ]; - (n.zotero_data_dir && - n.zotero_data_dir.trim() && - c.push("--zotero-data", n.zotero_data_dir.trim()), - n.paddleocr_api_key && - n.paddleocr_api_key.trim() && - c.push("--paddleocr-key", n.paddleocr_api_key.trim())); - try { - let g = !0; - try { - await a(["-c", "import paperforge"]); - } catch (x) { - g = !1; - } - if (!g) { - this._log(f("install_bootstrapping")); - let x = this.plugin.manifest.version; - this._log(`[install] Trying PyPI: pip install paperforge==${x}`); - let C = ["-m", "pip", "install", "--upgrade"]; - (process.platform !== "win32" && C.push("--user"), - C.push(`paperforge==${x}`)); - try { - await a(C, { logStdout: !0 }); - } catch (R) { - (this._log( - `[install] PyPI failed, falling back to git: git+https://...@v${x}` - ), - console.warn( - "[PaperForge] PyPI install failed, falling back to git:", - (l = R.message) == null ? void 0 : l.slice(0, 200) - )); - let S = ["-m", "pip", "install", "--upgrade"]; - (process.platform !== "win32" && S.push("--user"), - S.push(`git+https://github.com/LLLin000/PaperForge.git@v${x}`), - await a(S, { logStdout: !0 })); - } - } - (await a(c, { logStdout: !0, env: ot() }), - this._log(f("install_complete")), - (n.setup_complete = !0), - await this.plugin.saveSettings(), - setTimeout(() => { - ((this._step = 5), this._render()); - }, 800)); - } catch (g) { - console.error("PaperForge setup failed:", g.message); - let x = this._formatSetupError(g.message); - this._log(f("install_failed") + x); - let C = - (u = this._installLog.parentElement) == null - ? void 0 - : u.createEl("button", { - cls: "paperforge-copy-diag-btn", - text: f("error_copy_diagnostic") || "Copy diagnostic", - }); - if (C) { - let R = g.message, - S = - ((h = (p = this.plugin) == null ? void 0 : p.settings) == null - ? void 0 - : h.python_path) || "auto", - F = - ((k = (b = this.plugin) == null ? void 0 : b.manifest) == null - ? void 0 - : k.version) || "?", - B = process.platform + " " + process.arch, - A, - v; - try { - A = Cr() || "(not found)"; - } catch (I) { - A = "(error)"; - } - try { - v = re(n.vault_path.trim(), this.plugin.settings, void 0, void 0); - } catch (I) { - v = null; - } - let w = (process.env.PATH || "").length, - O = (process.env.PATH || "").toLowerCase().includes("git"), - M = [ - "[PaperForge Diagnostic]", - "Category: " + x, - "Plugin version: " + F, - "Python: " + S, - "Resolved Python: " + ((v == null ? void 0 : v.path) || "?"), - "OS: " + B, - "Vault path: " + (n.vault_path || "?"), - "--- Git ---", - "Git dir (resolved): " + A, - "PATH length: " + w + " chars", - "PATH contains git: " + O, - "--- Raw error ---", - R.slice(0, 2e3), - ].join(` -`); - C.addEventListener("click", () => { - navigator.clipboard - .writeText(M) - .then(() => { - (C.setText(f("error_copied") || "Copied!"), - setTimeout(() => { - C.setText(f("error_copy_diagnostic") || "Copy diagnostic"); - }, 3e3)); - }) - .catch(() => { - new xe.Notice("[!!] Clipboard write failed", 6e3); - }); - }); - } - ((r.disabled = !1), (r.textContent = f("install_btn_retry"))); - } - } - _log(r) { - this._installLog && - this._installLog.setText( - this._installLog.textContent + - r + - ` -` - ); - } - _validate() { - let r = [], - n = this.plugin.settings; - return ( - (!n.vault_path || !n.vault_path.trim()) && r.push(f("validate_vault")), - (!n.resources_dir || !n.resources_dir.trim()) && - r.push(f("validate_resources")), - (!n.literature_dir || !n.literature_dir.trim()) && - r.push(f("validate_notes")), - (!n.base_dir || !n.base_dir.trim()) && r.push(f("validate_base")), - (!n.paddleocr_api_key || !n.paddleocr_api_key.trim()) && - this._log(" ! " + f("validate_key") + " " + f("optional_later")), - (!n.zotero_data_dir || !n.zotero_data_dir.trim()) && - this._log(" ! " + f("validate_zotero") + " " + f("optional_later")), - r - ); - } - _processSetupOutput(r) { - let n = r - .split( - ` -` - ) - .filter(Boolean); - for (let i of n) - if (i.includes("[*]") || i.includes("[OK]") || i.includes("[FAIL]")) { - let a = i - .replace(/^\[\*\].*\d+:?\s*/, "") - .replace(/^\[OK\]\s*/, "") - .replace(/^\[FAIL\]\s*/, ""); - this._log(" " + a); - } - } - _formatSetupError(r) { - if ( - process.platform === "darwin" && - /No module named ['"]?paperforge/i.test(r) - ) - return "PaperForge not installed \u2014 install Python from Homebrew or python.org (Apple CLT /Library/Developer/CommandLineTools python often fails); then: python3 -m pip install --user git+https://github.com/LLLin000/PaperForge.git"; - let n = [ - { - match: /pip.*not found|No module named.*pip|command not found.*pip/i, - msg: "pip not found", - }, - { - match: /command not found|No such file|not recognized/i, - msg: "Python not found", - }, - { - match: - /resolve host|getaddrinfo.*nodename|connect ETIMEDOUT|connect ECONNREFUSED|fetch failed|Network error|ENOTFOUND|ECONNREFUSED|ECONNRESET/i, - msg: "Network error", - }, - { - match: - /certificate verify failed|SSL.*certificate|self.signed.cert|CERTIFICATE_VERIFY_FAILED/i, - msg: "SSL certificate error", - }, - { match: /No space left on device|disk full|ENOSPC/i, msg: "Disk full" }, - { - match: - /paperforge.*not found|cannot import|ModuleNotFoundError|No module named/i, - msg: "PaperForge not installed", - }, - { match: /permission denied|EACCES|EPERM/i, msg: "Permission denied" }, - { match: /ENOENT/i, msg: "Path not found" }, - { match: /timeout|timed out/i, msg: "Timeout" }, - ]; - for (let a of n) if (a.match.test(r)) return a.msg; - return ( - r - .split( - ` -` - ) - .filter(Boolean) - .slice(0, 3) - .join(" | ") - .slice(0, 200) || "Unknown error" - ); - } - _stepComplete(r) { - r.createEl("h2", { text: f("complete_title") }); - let n = r.createEl("div", { cls: "paperforge-summary" }); - n.createEl("div", { - cls: "paperforge-summary-title", - text: f("complete_summary"), - }); - let i = this.plugin.settings, - a = this.app.vault.adapter.basePath, - c = [ - { label: f("dir_vault"), val: a }, - { label: f("dir_resources"), val: `${a}/${i.resources_dir}` }, - { - label: f("dir_notes"), - val: `${a}/${i.resources_dir}/${i.literature_dir}`, - }, - { label: f("dir_base"), val: `${a}/${i.base_dir}` }, - { label: f("dir_system"), val: `${a}/${i.system_dir}` }, - { - label: "API Key", - val: i.paddleocr_api_key ? f("api_key_set") : f("api_key_missing"), - }, - { - label: f("field_zotero_data"), - val: i.zotero_data_dir || f("not_set"), - }, - ]; - for (let b of c) { - let k = n.createEl("div", { cls: "paperforge-summary-row" }); - (k.createEl("span", { cls: "paperforge-summary-label", text: b.label }), - k.createEl("span", { cls: "paperforge-summary-value", text: b.val })); - } - let l = n.createEl("div", { cls: "paperforge-summary-row" }); - l.createEl("span", { cls: "paperforge-summary-label", text: "PaperForge" }); - let u = l.createEl("span", { - cls: "paperforge-summary-value", - text: "\u2014", - }); - { - let b = a, - { path: k, extraArgs: g = [] } = re( - b, - this.plugin.settings, - void 0, - void 0 - ); - (0, Dt.execFile)( - k, - [...g, "-c", "import paperforge; print(paperforge.__version__)"], - { cwd: b, timeout: 1e4 }, - (x, C) => { - !x && C && (u.textContent = "v" + C.trim()); - } - ); - } - for (let b of c) { - let k = n.createEl("div", { cls: "paperforge-summary-row" }); - (k.createEl("span", { cls: "paperforge-summary-label", text: b.label }), - k.createEl("span", { cls: "paperforge-summary-value", text: b.val })); - } - r.createEl("h3", { text: f("complete_next") }); - let p = r.createEl("div", { cls: "paperforge-nextsteps" }), - h = [ - [f("complete_step4"), f("complete_step4_desc")], - [ - "", - `${f("complete_export_path")} ${a}/${i.system_dir}/PaperForge/exports/`, - ], - [f("complete_step1"), f("complete_step1_desc")], - [f("complete_step2"), f("complete_step2_desc")], - [f("complete_step3"), f("complete_step3_desc")], - ]; - for (let [b, k] of h) { - let g = p.createEl("div", { cls: "paperforge-nextstep-item" }); - (b && g.createEl("strong", { text: b }), g.createEl("span", { text: k })); - } - } -}; -var _t = ae(require("fs")), - Xt = ae(require("path")), - Nn = require("child_process"); -function jn(_) { - return Xt.join(_, "System", "PaperForge", "cache", "ocr_maintenance.json"); -} -function zn(_) { - try { - let y = jn(_), - r = _t.readFileSync(y, "utf-8"); - return JSON.parse(r); - } catch (y) { - return null; - } -} -function Yt(_, y) { - let r = jn(_), - n = Xt.dirname(r); - (_t.mkdirSync(n, { recursive: !0 }), - _t.writeFileSync(r, JSON.stringify(y, null, 2), "utf-8")); -} -function In(_, y, r) { - return new Promise((n, i) => { - (0, Nn.execFile)(_, y, r, (a, c) => { - a ? i(a) : n(c); - }); - }); -} -async function $n(_, y, r, n) { - let i = await In(y, [...r, "-m", "paperforge", "ocr", "list", "--manifest"], { - cwd: _, - timeout: 3e4, - }), - a = JSON.parse(i); - if (n) { - let b = Object.keys(n.manifest), - k = Object.keys(a); - if (b.length === k.length && b.every((x) => n.manifest[x] === a[x])) - return { - data: Object.values(n.papers).filter((C) => C.visible_in_maintenance), - changed: !1, - }; - } - let c = Object.keys(a).filter( - (b) => !(n != null && n.manifest[b]) || n.manifest[b] !== a[b] - ), - l = await In( - y, - [...r, "-m", "paperforge", "ocr", "list", "--json", "--keys", ...c], - { cwd: _, timeout: 3e4 } - ), - u = JSON.parse(l), - p = { manifest: a, papers: {}, cached_at: new Date().toISOString() }; - if (n != null && n.papers) - for (let b of Object.keys(a)) n.papers[b] && (p.papers[b] = n.papers[b]); - for (let b of u) p.papers[b.key] = b; - return ( - Yt(_, p), - { - data: Object.values(p.papers).filter((b) => b.visible_in_maintenance), - changed: !0, - } - ); -} -var er = class extends z.PluginSettingTab { - constructor(r, n) { - super(r, n); - this._saveTimeout = null; - this._pfConfig = null; - this._lastSyncTime = null; - this._memoryStatusText = null; - this._vectorDepsOk = null; - this._embedStatusText = null; - this._skillsCollapsed = { user: !0 }; - this._featurePanelsCollapsed = {}; - this._advCollapsed = !0; - this._refreshPending = !1; - this._pythonInterpDescEl = null; - this._customPathDescEl = null; - this._checkEl = null; - this.activeTab = "setup"; - this.plugin = n; - } - _refreshPfConfig() { - this._pfConfig = this.plugin.readPaperforgeJson(); - } - display() { - let { containerEl: r } = this; - if ( - (r.empty(), - this._refreshPfConfig(), - !document.getElementById("paperforge-tab-styles")) - ) { - let c = document.createElement("style"); - ((c.id = "paperforge-tab-styles"), - (c.textContent = ` +"use strict";var Rt=Object.create;var Le=Object.defineProperty;var Tt=Object.getOwnPropertyDescriptor;var Dt=Object.getOwnPropertyNames;var Bt=Object.getPrototypeOf,At=Object.prototype.hasOwnProperty;var Ot=(h,u)=>()=>(u||h((u={exports:{}}).exports,u),u.exports),Lt=(h,u)=>{for(var e in u)Le(h,e,{get:u[e],enumerable:!0})},rt=(h,u,e,t)=>{if(u&&typeof u=="object"||typeof u=="function")for(let r of Dt(u))!At.call(h,r)&&r!==e&&Le(h,r,{get:()=>u[r],enumerable:!(t=Tt(u,r))||t.enumerable});return h};var $=(h,u,e)=>(e=h!=null?Rt(Bt(h)):{},rt(u||!h||!h.__esModule?Le(e,"default",{value:h,enumerable:!0}):e,h)),Mt=h=>rt(Le({},"__esModule",{value:!0}),h);var qe=Ot((qt,Nt)=>{Nt.exports={versions:[{version:"1.5.15",date:"2026-06-01",title:"\u5168\u6587\u5B58\u50A8\u91CD\u6784 + OCR \u9605\u8BFB\u987A\u5E8F\u4FEE\u590D + Redo \u4E00\u952E\u91CD\u505A",breaking_or_migration:["\u5168\u6587\u6587\u4EF6\u73B0\u5728\u7EDF\u4E00\u5B58\u653E\u4E8E System/PaperForge/ocr/ \u4E0B\uFF0C\u4E0D\u518D\u5728\u5DE5\u4F5C\u533A\u4FDD\u7559\u526F\u672C","Redo OCR \u73B0\u5728\u4F1A\u7ACB\u5373\u6267\u884C\uFF08\u4E00\u952E\u5B8C\u6210\uFF09\uFF0C\u4E0D\u518D\u9700\u8981\u624B\u52A8\u518D\u8DD1\u4E00\u6B21"],new_features:["Redo OCR \u4E00\u952E\u95ED\u73AF\uFF1A\u52FE\u9009 \u2192 \u70B9\u6309\u94AE \u2192 \u81EA\u52A8\u5B8C\u6210\u5168\u90E8\u6D41\u7A0B","\u8BBE\u7F6E\u9875\u65B0\u589E\u300C\u66F4\u65B0\u4E0E\u624B\u518C\u300D\u6807\u7B7E\u9875\uFF0C\u53EF\u968F\u65F6\u67E5\u770B\u7248\u672C\u66F4\u65B0\u8BB0\u5F55\u548C\u4F7F\u7528\u624B\u518C","\u63D2\u4EF6\u66F4\u65B0\u540E\u81EA\u52A8\u5F39\u51FA\u66F4\u65B0\u8BF4\u660E"],fixes:["\u4FEE\u590D\u5168\u6587\u9605\u8BFB\u987A\u5E8F\u6DF7\u4E71\uFF0C\u4F18\u5316\u6574\u4F53\u6392\u7248\u4F53\u9A8C","\u4FEE\u590D\u7AE0\u8282\u6807\u9898\u548C\u6B63\u6587\u6BB5\u843D\u9519\u4F4D\u65AD\u5F00\u7684\u95EE\u9898","\u4FEE\u590D\u56FE\u8868\u548C\u5BF9\u5E94\u56FE\u6CE8\u88AB\u5206\u5F00\u7684\u95EE\u9898","\u4FEE\u590D\u9996\u9875\u6458\u8981\u533A\u5757\u6392\u5E8F\u5F02\u5E38","\u4FEE\u590D\u5E76\u6392\u56FE\u7247\u672A\u80FD\u81EA\u52A8\u5408\u5E76\u7684\u95EE\u9898","Dashboard \u73B0\u5728\u80FD\u6B63\u786E\u8BC6\u522B\u65B0\u7684\u5168\u6587\u6587\u4EF6\u4F4D\u7F6E"],recommended_actions:["\u65E7\u7248 OCR \u5168\u6587\u53EF\u80FD\u5B58\u5728\u9605\u8BFB\u987A\u5E8F\u95EE\u9898\uFF0C\u5EFA\u8BAE\u5BF9\u91CD\u8981\u8BBA\u6587\u6267\u884C\u4E00\u6B21 Redo OCR","\u6253\u5F00\u5168\u6587\u8BF7\u76F4\u63A5\u4F7F\u7528 Dashboard \u7684\u300C\u6253\u5F00\u5168\u6587\u300D\u6309\u94AE"]}]}});var Vt={};Lt(Vt,{default:()=>He});module.exports=Mt(Vt);var K=require("obsidian"),H=$(require("fs")),ke=$(require("path")),ie=require("child_process");var _e="paperforge-status",Ce="paperforge",st='',Y=[{id:"paperforge-sync",title:"Sync Library",desc:"Pull new references from Zotero and generate literature notes",icon:"\u21BB",cmd:"sync",okMsg:"Sync complete"},{id:"paperforge-ocr",title:"Run OCR",desc:"Extract full text and figures from PDFs via PaddleOCR",icon:"\u229E",cmd:"ocr",okMsg:"OCR started"},{id:"paperforge-doctor",title:"Run Doctor",desc:"Verify PaperForge setup \u2014 check configs, Zotero, paths, and index health",icon:"\u2695",cmd:"doctor",okMsg:"Doctor complete"},{id:"paperforge-repair",title:"Repair Issues",desc:"Fix three-way state divergence, path errors, and rebuild index",icon:"\u21BA",cmd:"repair",args:["--fix","--fix-paths"],okMsg:"Repair complete"},{id:"paperforge-ocr-redo",title:"Redo OCR",desc:"Re-run OCR for papers marked ocr_redo: true",icon:"\u21BA",cmd:"ocr",args:["redo"],okMsg:"OCR redo started"}],Fe={vault_path:"",setup_complete:!1,auto_update:!0,auto_update_on_startup:!0,agent_platform:"opencode",language:"",paddleocr_api_key:"",zotero_data_dir:"",python_path:"",features:{memory_layer:!0,vector_db:!1},selected_skill_platform:"opencode",vector_db_api_key:"",vector_db_api_base:"",vector_db_api_model:"text-embedding-3-small",frozen_skills:{},system_dir:"",resources_dir:"",literature_dir:"",base_dir:"",last_seen_version:""};function nt(h,u){if(!u||!u.note_path)return u;let e=h.vault.getAbstractFileByPath(u.note_path);if(!e)return u;let t=h.metadataCache.getFileCache(e),r=t&&t.frontmatter;if(!r)return u;let n={...u};for(let a of["do_ocr","analyze","ocr_status","ocr_redo","deep_reading_status"])Object.prototype.hasOwnProperty.call(r,a)&&(n[a]=r[a]);return n}function Ke(h,u){return h&&{...h,...u}}var We={en:{action_running:"Running ",api_key_missing:"Missing",api_key_set:"Entered",btn_install:"Open Setup Wizard",btn_install_desc:"Check whether the environment is ready, then open the step-by-step setup wizard",btn_reconfig:"Reconfigure",btn_reconfig_desc:"Open the setup wizard again to change directories, platform, or API keys",btn_validate:"Validate",check_bbt_fail:"Not detected",check_bbt_ok:"Installed",check_python_fail:"Not found",check_python_ok:"Ready",check_zotero_fail:"Not detected",check_zotero_ok:"Found",complete_export_path:"Save Better BibTeX JSON exports into:",complete_next:"Recommended next steps",complete_step1:"Open Dashboard",complete_step1_desc:'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.',complete_step2:"Sync Literature",complete_step2_desc:"In the main panel, click Sync Library to bring papers from Zotero into Obsidian and generate notes.",complete_step3:"Run OCR",complete_step3_desc:"In the Obsidian Base view, mark do_ocr:true on papers, then run OCR in the main panel.",complete_step4:"Configure Better BibTeX Auto-export",complete_step4_desc:'In Zotero, right-click the library or collection you want to sync -> Export -> Better BibTeX JSON -> enable "Keep updated".',complete_summary:"Saved Configuration",complete_title:"Setup Complete",copied:"Copied!",copy_pf_deep_cmd:"Copy /pf-deep Command",dashboard_drift_warning:"PaperForge CLI (v{0}) differs from plugin (v{1}). Open Settings \u2192 Runtime Health to sync.",deep_reading_not_found:"Deep reading file not found",desc:"Obsidian + Zotero literature pipeline. Sync papers, generate notes, run OCR, and read deeply in one place.",dir_base:"Base Dir",dir_index:"Index Dir",dir_notes:"Notes Dir",dir_resources:"Resource Dir",dir_system:"System Dir",dir_vault:"Vault Path",error_copied:"Copied!",error_copy_diagnostic:"Copy diagnostic",feat_agent_platform:"Agent Platform",feat_agent_platform_desc:"Select which agent platform to manage skills for.",feat_api_base_url:"API Base URL",feat_api_base_url_desc:"Custom OpenAI-compatible API endpoint. Leave empty for default.",feat_api_model:"API Model",feat_api_model_desc:"Embedding model name for this endpoint.",feat_build_btn:"Build",feat_build_complete:"Vector build complete.",feat_build_failed:"Build failed. See terminal output.",feat_building:"Building...",feat_cache_remove_failed:"Failed: {0}",feat_cache_removed:"Model cache removed.",feat_checking:"Checking...",feat_checking_btn:"Checking...",feat_deps_checking:"Checking dependencies...",feat_deps_missing:"Dependencies not installed. Required: chromadb, openai.",feat_enter_key:"Enter a valid OpenAI API key.",feat_install_btn:"Install",feat_install_deps:"Install Dependencies",feat_install_deps_desc:"pip install chromadb openai (~35MB).",feat_install_done:"Dependencies installed. Building vectors...",feat_install_failed:"Install failed: ",feat_installing:"Installing...",feat_installing_pkgs:"Installing {pkgs}...",feat_key_rejected:"API key rejected.",feat_memory_desc:"The Memory Layer is the core data engine of PaperForge, powered by SQLite. It integrates literature metadata (papers, assets, aliases, reading events), provides FTS5 metadata search across titles, abstracts, authors, domains, and collections, and powers agent-context and paper-status. Always active \u2014 no toggle needed.",feat_memory_rebuild_btn:"Rebuild",feat_memory_rebuild_done:"Memory DB rebuilt.",feat_memory_rebuild_failed:"Rebuild failed.",feat_memory_rebuilding:"Rebuilding...",feat_model_changed_warn:"Model changed ({0} -> {1}). Existing vectors are incompatible \u2014 rebuild required.",feat_network_error:"Network error: ",feat_no_python:"No Python found. Check Installation tab.",feat_not_cached:"Not cached",feat_openai_key:"OpenAI API Key",feat_openai_key_desc:"Used for API embedding calls. Model is defined below.",feat_output_copied:"Output copied to clipboard.",feat_rebuild_btn:"Rebuild",feat_rebuild_vectors:"Rebuild Vectors",feat_rebuild_vectors_changed:"Model changed \u2014 rebuild to update all vectors.",feat_rebuild_vectors_desc:"Rebuild all OCR fulltext vectors. Required after model or mode change.",feat_removing:"Removing...",feat_retry_btn:"Retry",feat_skills_desc:"Manage and enable/disable agent skills installed in your vault. Each row corresponds to a SKILL.md file \u2014 toggle off to prevent the agent from auto-invoking that skill.",feat_skills_system:"System Skills ship with PaperForge and are updated alongside PaperForge.",feat_skills_user:"User Skills are custom skills you install from community or create yourself.",feat_uninstall_btn:"Uninstall",feat_valid_key:"API key valid.",feat_vector_config_label:"Vector Settings",feat_vector_corrupted:"Vector index corrupted \u2014 needs force rebuild.",feat_vector_desc:"Vector Database enables semantic search across OCR-extracted fulltext via API embedding. Documents are split into chunks, embedded via OpenAI-compatible API, and stored in ChromaDB.",feat_vector_enable:"Enable Vector Retrieval",feat_vector_enable_desc:"Semantic search across OCR fulltext. Requires: pip install openai chromadb (~35MB).",feat_vector_rebuild_force_btn:"Force Rebuild",feat_verify:"Verify",feat_verify_btn:"Verify",field_paddleocr:"PaddleOCR API Key",field_python_custom:"Custom Path",field_python_interp:"Python Interpreter",field_zotero_data:"Zotero Data Dir",field_zotero_placeholder:"Required. Path to Zotero data directory for PDF attachment resolution.",guide_ocr:"Run OCR",guide_ocr_desc:"In the main panel, click Run OCR to extract full text and figures from PDFs for later reading and analysis.",guide_open:"Open Main Panel",guide_open_desc:'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.',guide_sync:"Sync Literature",guide_sync_desc:"After Better BibTeX JSON export is configured, click Sync Library to import papers from Zotero into Obsidian and generate notes automatically.",header_title:"PaperForge",install_bootstrapping:"PaperForge Python package not found. Installing automatically...",install_btn:"Start Install",install_btn_retry:"Retry",install_btn_running:"Installing...",install_complete:"Installation complete!",install_failed:"Installation failed: ",install_validating:"Validating setup...",jump_to_deep_reading:"Open Deep Reading",label_agent:"Agent Platform",nav_close:"Close",nav_next:"Next",nav_prev:"Back",not_set:"Not entered",notice_check_fail:"Missing: ",notice_python_missing:"Python was not detected. Install Python 3.10+ and add it to PATH.",ocr_privacy_title:"OCR Privacy Notice",ocr_privacy_warning:"OCR will upload PDFs to the PaddleOCR API. Do not upload sensitive or confidential documents.",ocr_queue_add:"Add to OCR Queue",ocr_queue_added:"Added to OCR queue",ocr_queue_remove:"Remove from OCR Queue",ocr_queue_removed:"Removed from OCR queue",ocr_understand:"I understand, continue",optional_later:"(can be set later in Settings)",orphan_delete_failed:"Prune failed",orphan_delete_selected:"Delete {count} selected",orphan_deleted:"Deleted {count} orphan workspace(s)",orphan_desc:"These papers are no longer in your Zotero library.",orphan_deselect_all:"Deselect all",orphan_explain:"Removed from Zotero. Workspace files remain on disk.",orphan_keep_all:"Keep all",orphan_none_selected:"No papers selected for deletion",orphan_select_all:"Select all",orphan_title:"Found {count} orphan paper(s)",panel_actions:"Quick Actions",prep_bbt:"Better BibTeX",prep_bbt_desc:"In Zotero: Tools -> Add-ons -> install Better BibTeX.",prep_export:"Better BibTeX Auto-export",prep_export_desc:'In Zotero, right-click the collection you want to sync -> Export Collection -> BetterBibTeX JSON -> enable "Keep updated" -> save the JSON file into the exports folder shown below. Obsidian Base views will use the JSON filename as the Base name:',prep_export_path_label:"Save the exported JSON file into this folder:",prep_key:"PaddleOCR Key",prep_key_desc:"Get your API key from https://aistudio.baidu.com/paddleocr",prep_python:"Python 3.10+",prep_python_desc:"Python must be available from the command line. If you are not sure, click below to auto-detect.",prep_zotero:"Zotero Desktop",prep_zotero_desc:"Install Zotero from https://www.zotero.org",run_in_agent:"Run in {0}",runtime_health:"Runtime Health",runtime_health_checking:"Checking...",runtime_health_desc:"Check whether the installed paperforge Python package matches the plugin version and whether the deployed skill contract is current.",runtime_health_match:"Match",runtime_health_mismatch:"Mismatch",runtime_health_package_ver:"Python package v{0}",runtime_health_plugin_ver:"Plugin v{0}",runtime_health_sync:"Sync Runtime",runtime_health_sync_done:"Runtime synced to v{0}",runtime_health_sync_fail:"Sync failed: {0}",runtime_health_syncing:"Syncing...",section_config:"Current Configuration",section_guide:"How To Use",section_prep:"Preparation",section_prep_desc:"Before first use, finish these 4 preparation items. Better BibTeX auto-export is configured after setup:",setup_done:"PaperForge environment is ready",setup_pending:"Not installed yet. Finish the preparation items below, then open the wizard.",tab_features:"Features",tab_setup:"Installation",tab_maintenance:"Maintenance",validate_base:"Base directory is required",validate_fail:"Please complete the required fields below",validate_index:"Index directory is required",validate_key:"PaddleOCR API key (optional, needed for OCR)",validate_notes:"Notes directory is required",validate_resources:"Resources directory is required",validate_system:"System directory is required",validate_vault:"Vault path is required",validate_zotero:"Zotero data directory (optional, needed for PDF linking)",wizard_agent_hint:"Choose the AI agent platform you use most often. PaperForge will place the matching command and skill files in the correct location.",wizard_dir_hint:"PaperForge stores user-facing literature data under the resources directory. These folders will live there:",wizard_dir_sub_hint:"Resolved folder preview based on the names below:",wizard_intro:"This wizard walks you through the full setup. In most cases, the default values are fine to keep.",wizard_keys_hint:"Enter your PaddleOCR API key below. If you want PaperForge to auto-locate Zotero PDFs, you can also fill in the Zotero data directory.",wizard_preview:"After installation, system files stay at the vault root while literature data stays under the resources directory.",wizard_safety:"Safety: if the selected folders already contain files, setup preserves existing files and only creates missing PaperForge folders and files.",wizard_step1:"Overview",wizard_step2:"Directory Setup",wizard_step3:"Platform & Keys",wizard_step4:"Install",wizard_step5:"Done",wizard_skip_ocr_desc:"OCR will not be available until you configure a valid PaddleOCR API key. You can continue setup now and configure it later in Settings.",wizard_skip_ocr_continue:"Continue without OCR key",wizard_skip_ocr_back:"Back to configure",wizard_api_hint_skip:"OCR key is optional \u2014 you may skip it and configure later.",wizard_sys_hint:"These folders live at the vault root, outside the resources directory:",wizard_title:"PaperForge Setup Wizard",ocr_maint_no_action:"No Action Needed",ocr_maint_rebuild:"Rebuild Recommended",ocr_maint_failed:"OCR Failed",ocr_maint_limited:"Result Limited",ocr_maint_needs_attention:"Needs Attention",ocr_maint_limitations:"Result Limitations",ocr_maint_hero_ok:"OCR looks usable overall.",ocr_maint_hero_warn:"OCR needs attention: {rebuild} rebuild recommended, {failed} failed.",ocr_maint_hero_note:"This page only promotes issues where maintenance is likely to help. Some papers may have limitations that maintenance will not improve.",ocr_maint_limitations_intro:"These papers look less certain, but PaperForge does not currently have a high-confidence maintenance action to recommend.",ocr_maint_all_papers:"All Papers",ocr_maint_rebuild_btn:"Rebuild results",ocr_maint_redo_btn:"Rerun OCR",maintenance_group_retry:"Needs Retry",maintenance_group_rebuild:"Can Rebuild",maintenance_group_legacy:"Upgrade Available (Optional)",maintenance_btn_retry:"Retry",maintenance_btn_rebuild:"Rebuild",maintenance_btn_upgrade:"Upgrade",maintenance_refresh_spinning:"Updating\u2026",maintenance_all_good:"\u2705 All good \u2014 no action needed",maintenance_n_pending:"{n} need attention",version_panel_title:"Version History",version_panel_back:"Back",version_filter_placeholder:"Filter papers...",version_papers_count:"{n} papers",version_current:"current",version_restore_btn:"Restore",version_compare_btn:"Compare",version_restore_selected:"Restore selected",version_clear_old:"Clear old versions (free {size})",version_no_backups:"No version history available",version_restore_confirm:"Restore {label} for {paper}?",version_restore_done:"Restored {label}",version_compare_title:"{vA} vs {vB}",version_compare_paragraphs:"{n} paragraphs changed",version_error_read:"Cannot read version data"},zh:{action_running:"\u6B63\u5728\u6267\u884C ",api_key_missing:"\u672A\u914D\u7F6E \u2717",api_key_set:"\u5DF2\u914D\u7F6E \u2713",btn_install:"\u6253\u5F00\u5B89\u88C5\u5411\u5BFC",btn_install_desc:"\u81EA\u52A8\u68C0\u6D4B Python + \u524D\u7F6E\u73AF\u5883\uFF0C\u901A\u8FC7\u540E\u6253\u5F00\u5206\u6B65\u5B89\u88C5\u5411\u5BFC",btn_reconfig:"\u91CD\u65B0\u914D\u7F6E",btn_reconfig_desc:"\u91CD\u65B0\u8FD0\u884C\u5B89\u88C5\u5411\u5BFC\uFF0C\u4FEE\u6539\u76EE\u5F55\u6216\u5BC6\u94A5\u914D\u7F6E",btn_validate:"\u9A8C\u8BC1",check_bbt_fail:"\u672A\u68C0\u6D4B\u5230",check_bbt_ok:"\u5DF2\u5B89\u88C5",check_python_fail:"\u672A\u5B89\u88C5",check_python_ok:"\u5DF2\u5C31\u7EEA",check_zotero_fail:"\u672A\u68C0\u6D4B\u5230",check_zotero_ok:"\u5DF2\u5B89\u88C5",complete_next:"\u4E0B\u4E00\u6B65\u64CD\u4F5C",complete_step1:"\u6253\u5F00 PaperForge Dashboard",complete_step1_desc:"Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807",complete_step2:"\u540C\u6B65\u6587\u732E",complete_step2_desc:"Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0",complete_step3:"\u8FD0\u884C OCR",complete_step3_desc:"Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868",complete_step4:"\u914D\u7F6E BBT \u81EA\u52A8\u5BFC\u51FA",complete_summary:"\u5F53\u524D\u5B8C\u6574\u914D\u7F6E",complete_title:"\u2713 PaperForge \u5B89\u88C5\u5B8C\u6210",copied:"\u5DF2\u590D\u5236\uFF01",copy_pf_deep_cmd:"\u590D\u5236 /pf-deep \u547D\u4EE4",dashboard_drift_warning:'\u63D2\u4EF6\u7248\u672C\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u4E0D\u5339\u914D\u3002\u8BF7\u5728\u8BBE\u7F6E\u4E2D\u70B9\u51FB"\u540C\u6B65\u8FD0\u884C\u65F6"\u3002',deep_reading_not_found:"\u7CBE\u8BFB\u6587\u4EF6\u672A\u627E\u5230",desc:"Obsidian + Zotero \u6587\u732E\u7BA1\u7406\u6D41\u6C34\u7EBF\u3002\u81EA\u52A8\u540C\u6B65\u6587\u732E\u3001\u751F\u6210\u7B14\u8BB0\u3001OCR \u63D0\u53D6\u5168\u6587\uFF0C\u4E00\u7AD9\u5F0F\u6587\u732E\u7CBE\u8BFB\u5DE5\u4F5C\u6D41\u3002",dir_base:"Base \u76EE\u5F55",dir_index:"\u7D22\u5F15\u76EE\u5F55",dir_notes:"\u6B63\u6587\u76EE\u5F55",dir_resources:"\u8D44\u6E90\u76EE\u5F55",dir_system:"\u7CFB\u7EDF\u76EE\u5F55",dir_vault:"Vault \u8DEF\u5F84",error_copied:"\u5DF2\u590D\u5236\uFF01",error_copy_diagnostic:"\u590D\u5236\u8BCA\u65AD\u4FE1\u606F",feat_agent_platform:"Agent \u5E73\u53F0",feat_agent_platform_desc:"\u9009\u62E9\u8981\u7BA1\u7406\u7684 Agent \u5E73\u53F0\u3002",feat_api_base_url:"API \u5730\u5740",feat_api_base_url_desc:"\u81EA\u5B9A\u4E49 OpenAI \u517C\u5BB9 API \u7AEF\u70B9\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u5730\u5740\u3002",feat_api_model:"API \u6A21\u578B",feat_api_model_desc:"\u8BE5\u7AEF\u70B9\u4F7F\u7528\u7684\u5D4C\u5165\u6A21\u578B\u540D\u79F0\u3002",feat_build_btn:"\u6784\u5EFA",feat_build_complete:"\u5411\u91CF\u6784\u5EFA\u5B8C\u6210\u3002",feat_build_failed:"\u6784\u5EFA\u5931\u8D25\u3002\u8BF7\u67E5\u770B\u7EC8\u7AEF\u8F93\u51FA\u3002",feat_building:"\u6784\u5EFA\u4E2D\u2026",feat_cache_remove_failed:"\u5931\u8D25\uFF1A{0}",feat_cache_removed:"\u6A21\u578B\u7F13\u5B58\u5DF2\u6E05\u9664\u3002",feat_checking:"\u68C0\u6D4B\u4E2D\u2026",feat_checking_btn:"\u68C0\u6D4B\u4E2D\u2026",feat_deps_checking:"\u6B63\u5728\u68C0\u6D4B\u4F9D\u8D56\u2026",feat_deps_missing:"\u4F9D\u8D56\u672A\u5B89\u88C5\u3002\u9700\u8981\uFF1Achromadb, openai\u3002",feat_enter_key:"\u8BF7\u8F93\u5165\u6709\u6548\u7684 OpenAI API Key\u3002",feat_install_btn:"\u5B89\u88C5",feat_install_deps:"\u5B89\u88C5\u4F9D\u8D56",feat_install_done:"\u4F9D\u8D56\u5DF2\u5B89\u88C5\u3002\u6B63\u5728\u6784\u5EFA\u5411\u91CF\u2026",feat_install_failed:"\u5B89\u88C5\u5931\u8D25\uFF1A",feat_installing:"\u5B89\u88C5\u4E2D\u2026",feat_installing_pkgs:"\u6B63\u5728\u5B89\u88C5 {pkgs}...",feat_key_rejected:"API Key \u88AB\u62D2\u7EDD\u3002",feat_memory_desc:"\u8BB0\u5FC6\u5C42\u662F PaperForge \u7684\u6838\u5FC3\u6570\u636E\u5F15\u64CE\uFF0C\u57FA\u4E8E SQLite \u6784\u5EFA\u3002\u5B83\u6574\u5408\u4E86\u6587\u732E\u5143\u6570\u636E\uFF08\u8BBA\u6587\u3001\u8D44\u6E90\u6587\u4EF6\u3001\u522B\u540D\u3001\u9605\u8BFB\u4E8B\u4EF6\uFF09\uFF0C\u652F\u6301 FTS5 \u5143\u6570\u636E\u68C0\u7D22\uFF08\u6807\u9898\u3001\u6458\u8981\u3001\u4F5C\u8005\u3001domain\u3001collection\uFF09\uFF0C\u5E76\u4E3A agent-context \u548C paper-status \u547D\u4EE4\u63D0\u4F9B\u6570\u636E\u652F\u6491\u3002\u59CB\u7EC8\u8FD0\u884C\uFF0C\u65E0\u9700\u624B\u52A8\u5F00\u542F\u3002",feat_memory_rebuild_btn:"\u91CD\u5EFA\u6570\u636E\u5E93",feat_memory_rebuild_done:"\u8BB0\u5FC6\u6570\u636E\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002",feat_memory_rebuild_failed:"\u91CD\u5EFA\u5931\u8D25\u3002",feat_memory_rebuilding:"\u91CD\u5EFA\u4E2D\u2026",feat_model:"\u6A21\u578B",feat_model_changed_warn:"\u6A21\u578B\u5DF2\u66F4\u6362\uFF08{0} -> {1}\uFF09\u3002\u5DF2\u6709\u5411\u91CF\u4E0D\u517C\u5BB9\u2014\u2014\u9700\u8981\u91CD\u5EFA\u3002",feat_network_error:"\u7F51\u7EDC\u9519\u8BEF\uFF1A",feat_no_python:"\u672A\u627E\u5230 Python\u3002\u8BF7\u67E5\u770B\u5B89\u88C5\u6807\u7B7E\u9875\u3002",feat_not_cached:"\u672A\u7F13\u5B58",feat_openai_key:"OpenAI API Key",feat_openai_key_desc:"\u7528\u4E8E API \u5D4C\u5165\u8C03\u7528\uFF0C\u6A21\u578B\u5728\u4E0B\u65B9\u5B9A\u4E49\u3002",feat_output_copied:"\u8F93\u51FA\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\u3002",feat_rebuild_btn:"\u91CD\u5EFA",feat_rebuild_vectors:"\u91CD\u5EFA\u5411\u91CF",feat_rebuild_vectors_changed:"\u6A21\u578B\u5DF2\u66F4\u6362 \u2014 \u9700\u8981\u91CD\u5EFA\u5411\u91CF\u3002",feat_rebuild_vectors_desc:"\u91CD\u5EFA\u6240\u6709 OCR \u5168\u6587\u5411\u91CF\u3002\u66F4\u6362\u6A21\u578B\u6216\u6A21\u5F0F\u540E\u9700\u8981\u91CD\u5EFA\u3002",feat_removing:"\u5220\u9664\u4E2D\u2026",feat_retry_btn:"\u91CD\u8BD5",feat_skills_desc:"\u7BA1\u7406 Vault \u4E2D\u5DF2\u5B89\u88C5\u7684 Agent \u6280\u80FD\u3002\u6BCF\u884C\u5BF9\u5E94\u4E00\u4E2A SKILL.md \u6587\u4EF6\uFF0C\u5173\u95ED\u5F00\u5173\u53EF\u963B\u6B62 Agent \u81EA\u52A8\u8C03\u7528\u8BE5\u6280\u80FD\u3002",feat_skills_system:"\u7CFB\u7EDF\u6280\u80FD\u968F PaperForge \u4E00\u540C\u53D1\u5E03\uFF0C\u4F1A\u8DDF\u968F PaperForge \u7248\u672C\u66F4\u65B0\u3002",feat_skills_user:"\u7528\u6237\u6280\u80FD\u662F\u4F60\u81EA\u884C\u5B89\u88C5\u6216\u521B\u5EFA\u7684\u81EA\u5B9A\u4E49\u6280\u80FD\u3002",feat_uninstall_btn:"\u5378\u8F7D",feat_valid_key:"API Key \u6709\u6548\u3002",feat_vector_config_label:"\u5411\u91CF\u5E93\u914D\u7F6E",feat_vector_corrupted:"\u5411\u91CF\u7D22\u5F15\u5DF2\u635F\u574F \u2014 \u9700\u8981\u5F3A\u5236\u91CD\u5EFA\u3002",feat_vector_desc:"\u5411\u91CF\u6570\u636E\u5E93\u901A\u8FC7\u5D4C\u5165\u6A21\u578B\u5B9E\u73B0 OCR \u5168\u6587\u7684\u8BED\u4E49\u641C\u7D22\u3002\u6587\u6863\u88AB\u5207\u5206\u4E3A\u6587\u672C\u5757\uFF08chunk\uFF09\uFF0C\u7F16\u7801\u4E3A\u5411\u91CF\u5B58\u5165 ChromaDB\u3002\u652F\u6301\u672C\u5730\u6A21\u578B\uFF08\u514D\u8D39\uFF0CCPU \u8FD0\u884C\uFF09\u6216 OpenAI API\uFF08\u4ED8\u8D39\uFF0C\u66F4\u5FEB\u901F\uFF09\u3002",feat_vector_enable:"\u542F\u7528\u5411\u91CF\u68C0\u7D22",feat_vector_enable_desc:"\u5BF9 OCR \u5168\u6587\u8FDB\u884C\u8BED\u4E49\u641C\u7D22\u3002\u9700\u5B89\u88C5: pip install chromadb sentence-transformers openai (~500MB)\u3002",feat_vector_rebuild_force_btn:"\u5F3A\u5236\u91CD\u5EFA",feat_verify:"\u9A8C\u8BC1",feat_verify_btn:"\u9A8C\u8BC1",field_paddleocr:"PaddleOCR API \u5BC6\u94A5",field_python_custom:"\u81EA\u5B9A\u4E49 Python \u8DEF\u5F84",field_python_interp:"\u5F53\u524D Python \u89E3\u91CA\u5668",field_zotero_data:"Zotero \u6570\u636E\u76EE\u5F55",field_zotero_placeholder:"\u53EF\u9009\uFF0C\u7528\u4E8E\u81EA\u52A8\u68C0\u6D4B PDF",guide_ocr:"\u8FD0\u884C OCR",guide_ocr_desc:"Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868",guide_open:"\u6253\u5F00 Dashboard",guide_open_desc:"Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807",guide_sync:"\u540C\u6B65\u6587\u732E",guide_sync_desc:"Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0",header_title:"PaperForge",install_bootstrapping:"\u672A\u68C0\u6D4B\u5230 PaperForge Python \u5305\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5\u2026",install_btn:"\u5F00\u59CB\u5B89\u88C5",install_btn_retry:"\u91CD\u8BD5",install_btn_running:"\u6B63\u5728\u5B89\u88C5...",install_complete:"\u2713 \u5B89\u88C5\u5B8C\u6210\uFF01",install_failed:"\u2717 \u5B89\u88C5\u5931\u8D25\uFF1A",install_validating:"\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u73AF\u5883\u2026",jump_to_deep_reading:"\u8DF3\u8F6C\u5230\u7CBE\u8BFB",label_agent:"Agent \u5E73\u53F0",nav_close:"\u5173\u95ED",nav_next:"\u4E0B\u4E00\u6B65 \u2192",nav_prev:"\u2190 \u4E0A\u4E00\u6B65",no_pending_ocr:"\u6240\u6709 OCR \u4EFB\u52A1\u5DF2\u5B8C\u6210",not_set:"\u672A\u8BBE\u7F6E",notice_check_fail:"\u672A\u901A\u8FC7: ",notice_python_missing:"Python \u672A\u68C0\u6D4B\u5230\uFF0C\u8BF7\u5148\u5B89\u88C5 Python 3.10+ \u5E76\u52A0\u5165 PATH",ocr_privacy_title:"OCR \u9690\u79C1\u63D0\u793A",ocr_privacy_warning:"OCR \u4F1A\u5C06 PDF \u4E0A\u4F20\u5230 PaddleOCR API \u8FDB\u884C\u5904\u7406\u3002\u8BF7\u4E0D\u8981\u4E0A\u4F20\u5305\u542B\u654F\u611F\u4FE1\u606F\u6216\u65E0\u6CD5\u5916\u4F20\u7684\u6587\u732E\u3002",ocr_queue_add:"\u52A0\u5165 OCR \u961F\u5217",ocr_queue_added:"\u5DF2\u52A0\u5165 OCR \u961F\u5217",ocr_queue_remove:"\u79FB\u51FA OCR \u961F\u5217",ocr_queue_removed:"\u5DF2\u79FB\u51FA OCR \u961F\u5217",ocr_understand:"\u6211\u4E86\u89E3\uFF0C\u7EE7\u7EED",optional_later:"\uFF08\u7A0D\u540E\u53EF\u5728\u8BBE\u7F6E\u4E2D\u8865\u5145\uFF09",orphan_delete_failed:"\u6E05\u7406\u5931\u8D25",orphan_delete_selected:"\u5220\u9664 {count} \u7BC7",orphan_deleted:"\u5DF2\u5220\u9664 {count} \u7BC7\u6B8B\u7559\u6587\u732E",orphan_desc:"\u8FD9\u4E9B\u6587\u732E\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002",orphan_deselect_all:"\u53D6\u6D88\u5168\u9009",orphan_explain:"\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002\u5DE5\u4F5C\u533A\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u78C1\u76D8\u4E0A\u3002",orphan_keep_all:"\u4FDD\u7559\u5168\u90E8",orphan_none_selected:"\u672A\u9009\u62E9\u4EFB\u4F55\u6587\u732E",orphan_select_all:"\u5168\u9009",orphan_title:"\u53D1\u73B0 {count} \u7BC7\u6B8B\u7559\u6587\u732E",panel_actions:"\u5FEB\u6377\u64CD\u4F5C",prep_bbt:"Better BibTeX",prep_bbt_desc:"Zotero \u2192 \u5DE5\u5177 \u2192 \u63D2\u4EF6 \u2192 \u5B89\u88C5 Better BibTeX",prep_export:"BBT \u81EA\u52A8\u5BFC\u51FA",prep_export_desc:"\u53F3\u952E\u6587\u732E\u5B50\u5206\u7C7B \u2192 \u5BFC\u51FA\u5206\u7C7B \u2192 BetterBibTeX JSON \u2192 \u52FE\u9009\u4FDD\u6301\u66F4\u65B0 \u2192 \u5BFC\u51FA\u5230\uFF08JSON \u6587\u4EF6\u540D\u5373\u4E3A Base \u540D\uFF09\uFF1A",prep_key:"PaddleOCR Key",prep_key_desc:"\u5728 https://aistudio.baidu.com/paddleocr \u83B7\u53D6 API Key",prep_python:"Python 3.10+",prep_python_desc:"\u786E\u4FDD Python \u53EF\u547D\u4EE4\u884C\u8C03\u7528\u3002\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u81EA\u52A8\u68C0\u6D4B\u3002",prep_zotero:"Zotero \u684C\u9762\u7248",prep_zotero_desc:"\u5B89\u88C5 Zotero (https://www.zotero.org)",run_in_agent:"\u5728 {0} \u4E2D\u8FD0\u884C",runtime_health:"\u8FD0\u884C\u65F6\u72B6\u6001",runtime_health_checking:"\u6B63\u5728\u68C0\u6D4B\u2026",runtime_health_desc:"\u68C0\u67E5\u63D2\u4EF6\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u7684\u5339\u914D\u60C5\u51B5\uFF0C\u5E76\u786E\u8BA4\u5DF2\u90E8\u7F72\u7684 skill contract \u662F\u5426\u4E3A\u5F53\u524D\u7248\u672C\u3002",runtime_health_match:"\u5339\u914D",runtime_health_mismatch:"\u4E0D\u5339\u914D",runtime_health_package_ver:"Python \u5305 v{0}",runtime_health_plugin_ver:"\u63D2\u4EF6 v{0}",runtime_health_sync:"\u540C\u6B65\u8FD0\u884C\u65F6",runtime_health_sync_done:"\u8FD0\u884C\u65F6\u5DF2\u540C\u6B65\u81F3 v{0}",runtime_health_sync_fail:"\u8FD0\u884C\u65F6\u540C\u6B65\u5931\u8D25\uFF1A{0}",runtime_health_syncing:"\u6B63\u5728\u540C\u6B65\u2026",section_config:"\u5F53\u524D\u914D\u7F6E",section_guide:"\u64CD\u4F5C\u65B9\u5F0F",section_prep:"\u5B89\u88C5\u51C6\u5907",section_prep_desc:"\u9996\u6B21\u4F7F\u7528\u524D\uFF0C\u8BF7\u4F9D\u6B21\u5B8C\u6210\u4EE5\u4E0B\u51C6\u5907\uFF1A",setup_done:"\u2713 PaperForge \u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u6210",setup_pending:"\u5C1A\u672A\u5B89\u88C5\uFF0C\u5B8C\u6210\u5B89\u88C5\u51C6\u5907\u540E\u70B9\u51FB\u5B89\u88C5\u5411\u5BFC",tab_features:"\u529F\u80FD",tab_setup:"\u5B89\u88C5",tab_maintenance:"\u7EF4\u62A4",validate_base:"Base \u76EE\u5F55\u672A\u586B\u5199",validate_fail:"\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25",validate_index:"\u7D22\u5F15\u76EE\u5F55\u672A\u586B\u5199",validate_key:"PaddleOCR API \u5BC6\u94A5\u672A\u586B\u5199",validate_notes:"\u6B63\u6587\u76EE\u5F55\u672A\u586B\u5199",validate_resources:"\u8D44\u6E90\u76EE\u5F55\u672A\u586B\u5199",validate_system:"\u7CFB\u7EDF\u76EE\u5F55\u672A\u586B\u5199",validate_vault:"Vault \u8DEF\u5F84\u672A\u586B\u5199",validate_zotero:"Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879",wizard_agent_hint:"\u9009\u62E9\u4F60\u4F7F\u7528\u7684 AI Agent \u5E73\u53F0\uFF0C\u5B89\u88C5\u65F6\u5C06\u6309\u5BF9\u5E94\u683C\u5F0F\u90E8\u7F72\u6280\u80FD\u6587\u4EF6\uFF1A",wizard_dir_hint:"\u8D44\u6E90\u76EE\u5F55\u662F\u6587\u732E\u6570\u636E\u7684\u7EDF\u4E00\u6839\u76EE\u5F55\uFF0C\u4EE5\u4E0B\u5B50\u76EE\u5F55\u5C06\u521B\u5EFA\u5728\u5176\u5185\u90E8\uFF1A",wizard_dir_sub_hint:"\u8D44\u6E90\u76EE\u5F55\u5185\u7684\u4E24\u4E2A\u5B50\u76EE\u5F55\uFF1A",wizard_intro:"\u672C\u5411\u5BFC\u5C06\u5F15\u5BFC\u60A8\u5B8C\u6210 PaperForge \u73AF\u5883\u7684\u5B8C\u6574\u914D\u7F6E\u3002\u5B89\u88C5\u8FC7\u7A0B\u4F1A\u81EA\u52A8\u521B\u5EFA\u6240\u6709\u76EE\u5F55\u7ED3\u6784\uFF0C\u65E0\u9700\u624B\u52A8\u64CD\u4F5C\u3002",wizard_keys_hint:"\u4EE5\u4E0B\u4E3A API \u5BC6\u94A5\u4E0E Zotero \u914D\u7F6E\uFF1A",wizard_preview:"\u7CFB\u7EDF\u6587\u4EF6\u548C Agent \u914D\u7F6E\u4F4D\u4E8E Vault \u6839\u76EE\u5F55\u4E0B\u3002\u6587\u732E\u6570\u636E\uFF08\u6B63\u6587\u3001\u7D22\u5F15\uFF09\u7EDF\u4E00\u5B58\u653E\u5728\u8D44\u6E90\u76EE\u5F55\u5185\u3002\u5B89\u88C5\u540E\u4ECD\u53EF\u5728\u8BBE\u7F6E\u4E2D\u4FEE\u6539\u3002",wizard_safety:"\u5B89\u5168\u8BF4\u660E\uFF1A\u5982\u679C\u4F60\u9009\u62E9\u7684\u76EE\u5F55\u91CC\u5DF2\u7ECF\u6709\u6587\u4EF6\uFF0C\u5B89\u88C5\u5411\u5BFC\u4F1A\u4FDD\u7559\u5DF2\u6709\u5185\u5BB9\uFF0C\u53EA\u8865\u5145\u7F3A\u5931\u7684 PaperForge \u6587\u4EF6\u548C\u76EE\u5F55\u3002",wizard_step1:"\u6982\u89C8",wizard_step2:"\u76EE\u5F55",wizard_step3:"Agent",wizard_step4:"\u5B89\u88C5",wizard_step5:"\u5B8C\u6210",wizard_skip_ocr_desc:"OCR \u529F\u80FD\u5728\u914D\u7F6E\u6709\u6548\u7684 PaddleOCR API \u5BC6\u94A5\u4E4B\u524D\u4E0D\u53EF\u7528\u3002\u60A8\u53EF\u4EE5\u7EE7\u7EED\u5B8C\u6210\u8BBE\u7F6E\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002",wizard_skip_ocr_continue:"\u7EE7\u7EED\uFF0C\u7A0D\u540E\u914D\u7F6E\u5BC6\u94A5",wizard_skip_ocr_back:"\u8FD4\u56DE\u914D\u7F6E",wizard_api_hint_skip:"OCR \u5BC6\u94A5\u4E3A\u9009\u586B\u9879 \u2014 \u53EF\u8DF3\u8FC7\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002",wizard_sys_hint:"\u72EC\u7ACB\u4E8E\u8D44\u6E90\u76EE\u5F55\u7684\u7CFB\u7EDF\u6587\u4EF6\uFF1A",wizard_title:"PaperForge \u5B89\u88C5\u5411\u5BFC",ocr_maint_no_action:"\u65E0\u9700\u5904\u7406",ocr_maint_rebuild:"\u5EFA\u8BAE\u91CD\u5EFA",ocr_maint_failed:"OCR \u5931\u8D25",ocr_maint_limited:"\u7ED3\u679C\u4E00\u822C",ocr_maint_needs_attention:"\u9700\u8981\u5904\u7406",ocr_maint_limitations:"\u7ED3\u679C\u8BF4\u660E",ocr_maint_hero_ok:"OCR \u6574\u4F53\u6B63\u5E38\u3002",ocr_maint_hero_warn:"OCR \u9700\u8981\u5173\u6CE8\uFF1A{rebuild} \u7BC7\u5EFA\u8BAE\u91CD\u5EFA\uFF0C{failed} \u7BC7\u5904\u7406\u5931\u8D25\u3002",ocr_maint_hero_note:"\u672C\u9875\u53EA\u63D0\u793A\u7EF4\u62A4\u540E\u5927\u6982\u7387\u4F1A\u6539\u5584\u7684\u95EE\u9898\u3002\u90E8\u5206\u8BBA\u6587\u6548\u679C\u4E00\u822C\uFF0C\u7EF4\u62A4\u672A\u5FC5\u80FD\u6539\u5584\u3002",ocr_maint_limitations_intro:"\u8FD9\u7C7B\u8BBA\u6587\u901A\u5E38\u8868\u793A\u7248\u5F0F\u590D\u6742\u6216\u4FE1\u53F7\u504F\u5F31\uFF0CPaperForge \u76EE\u524D\u6CA1\u6709\u9AD8\u7F6E\u4FE1\u5EA6\u7684\u7EF4\u62A4\u5EFA\u8BAE\u3002",ocr_maint_all_papers:"\u5168\u90E8\u8BBA\u6587",ocr_maint_rebuild_btn:"\u91CD\u5EFA\u7ED3\u679C",maintenance_group_retry:"\u9700\u8981\u91CD\u8BD5",maintenance_group_rebuild:"\u53EF\u91CD\u5EFA\u7ED3\u679C",maintenance_group_legacy:"\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09",maintenance_btn_retry:"\u91CD\u8BD5",maintenance_btn_rebuild:"\u91CD\u5EFA",maintenance_btn_upgrade:"\u5347\u7EA7",maintenance_refresh_spinning:"\u6B63\u5728\u66F4\u65B0\u2026",maintenance_all_good:"\u2705 \u5168\u90E8\u6B63\u5E38",maintenance_n_pending:"{n} \u7BC7\u9700\u8981\u5904\u7406",version_panel_title:"\u7248\u672C\u5386\u53F2",version_panel_back:"\u8FD4\u56DE",version_filter_placeholder:"\u641C\u7D22\u8BBA\u6587...",version_papers_count:"{n} \u7BC7\u8BBA\u6587",version_current:"\u5F53\u524D",version_restore_btn:"\u6062\u590D",version_compare_btn:"\u5BF9\u6BD4",version_restore_selected:"\u6062\u590D\u9009\u4E2D\u7248\u672C",version_clear_old:"\u6E05\u9664\u65E7\u7248\u672C (\u91CA\u653E {size})",version_no_backups:"\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5386\u53F2\u7248\u672C",version_restore_confirm:"\u786E\u8BA4\u5C06 {paper} \u6062\u590D\u5230 {label}\uFF1F",version_restore_done:"\u5DF2\u6062\u590D\u5230 {label}",version_compare_title:"{vA} vs {vB}",version_compare_paragraphs:"{n} \u6BB5\u6709\u53D8\u5316",version_error_read:"\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C\u6570\u636E"}},Ze=null;function It(h){try{let u=h.vault;if(typeof u.getConfig=="function"){let e=u.getConfig("language");if(e&&String(e).startsWith("zh"))return"zh"}}catch(u){}try{if(typeof localStorage!="undefined"){let u=localStorage.getItem("language");if(u&&String(u).startsWith("zh"))return"zh"}}catch(u){}return"en"}function at(h){Ze=It(h)==="zh"?We.zh:We.en}function o(h){return Ze&&Ze[h]||We.en[h]||h}var C=require("obsidian"),N=$(require("fs")),Z=$(require("path")),kt=$(require("os")),j=require("child_process");var wt=$(qe());var ne=$(require("fs")),se=$(require("path")),ot=$(require("os")),le=require("child_process"),Je=null,it=!1;function L(h,u,e,t){let r=e||ne,n=t||le.execFileSync;if(u&&u.python_path&&u.python_path.trim()){let l=u.python_path.trim();if(r.existsSync(l))return{path:l,source:"manual",extraArgs:[]}}let a=[se.join(h,".paperforge-test-venv","Scripts","python.exe"),se.join(h,".venv","Scripts","python.exe"),se.join(h,"venv","Scripts","python.exe")];for(let l of a)try{if(r.existsSync(l))return{path:l,source:"auto-detected",extraArgs:[]}}catch(i){}let s=[{path:"py",extraArgs:["-3"]},{path:"python",extraArgs:[]},{path:"python3",extraArgs:[]}];for(let l of s)try{let i=n(l.path,[...l.extraArgs,"--version"],{encoding:"utf-8",timeout:5e3,windowsHide:!0});if(i&&i.toLowerCase().includes("python"))return{path:l.path,source:"auto-detected",extraArgs:l.extraArgs}}catch(i){}return{path:"python",source:"auto-detected",extraArgs:[]}}function lt(h,u,e,t,r){t===void 0&&(t=1e4);let n=r||le.execFile;return new Promise(a=>{n(h,["-c","import paperforge; print(paperforge.__version__)"],{cwd:e,timeout:t},(s,l)=>{if(s){a({status:"not-installed",pyVersion:null,pluginVersion:u,error:s.message});return}let i=l&&l.trim()||null;a(i===u?{status:"match",pyVersion:i,pluginVersion:u,error:null}:{status:"mismatch",pyVersion:i,pluginVersion:u,error:null})})})}function ct(h,u,e){e===void 0&&(e=[]);let t=`paperforge==${u}`,r=`git+https://github.com/LLLin000/PaperForge.git@${u}`,n=[...e,"-m","pip","install","--upgrade",t],a=[...e,"-m","pip","install","--upgrade",r];return{cmd:h,url:r,args:a,pypiArgs:n,gitArgs:a,timeout:12e4}}function pt(h,u,e,t,r,n){let a=r||le.spawn;return new Promise(s=>{let l=Date.now(),i={cwd:e,timeout:t,windowsHide:!0};n&&(i.env=n);let c=a(h,u,i),d=[],g=[];c.stdout.on("data",p=>{d.push(p.toString("utf-8"))}),c.stderr.on("data",p=>{g.push(p.toString("utf-8"))}),c.on("close",p=>{s({stdout:d.join(""),stderr:g.join(""),exitCode:p,elapsed:Date.now()-l})}),c.on("error",p=>{s({stdout:d.join(""),stderr:g.join("")+` +`+p.message,exitCode:-1,elapsed:Date.now()-l})})})}function Ue(){if(it)return Je;it=!0;try{let h;if(process.platform==="win32"){let u=process.env.ComSpec||"C:\\Windows\\System32\\cmd.exe";h=(0,le.execFileSync)(u,["/c","where","git"],{timeout:5e3,windowsHide:!0,encoding:"utf-8"})}else h=(0,le.execFileSync)("which",["git"],{timeout:5e3,encoding:"utf-8"});if(h){let u=h.split(` +`)[0].trim();u&&(Je=se.dirname(u))}}catch(h){}return Je}function me(){let h={...process.env},u=process.platform,e=ot.homedir(),t=[],r=Ue();r&&t.push(r),u==="darwin"?t.push("/opt/homebrew/bin","/usr/local/bin","/usr/bin",`${e}/.local/bin`):u==="linux"&&t.push("/usr/local/bin","/usr/bin",`${e}/.local/bin`);let n=h.PATH||"";return h.PATH=[...t,n].filter(Boolean).join(se.delimiter),h}function dt(h){return String(h).toLowerCase().replace(/[^a-z0-9]/g,"").includes("betterbibtex")}function Ge(h){if(!h)return!1;try{if(!ne.existsSync(h))return!1;for(let u of ne.readdirSync(h))if(dt(u))return!0}catch(u){}return!1}function Me(h){if(!h)return!1;try{if(!ne.existsSync(h))return!1;for(let u of ne.readdirSync(h)){let e=se.join(h,u,"extensions");try{if(!ne.existsSync(e))continue;for(let t of ne.readdirSync(e))if(dt(t))return!0}catch(t){}}}catch(u){}return!1}var ye=$(require("fs")),W=$(require("path")),ut=require("child_process"),ae=null;function zt(h,u){let e=u||ye,t=W.join(h,"paperforge.json"),r={system_dir:"System",resources_dir:"Resources",literature_dir:"Literature",base_dir:"Bases"};try{if(!e.existsSync(t))return{...r,_warning:"paperforge.json not found; using defaults"};let n=e.readFileSync(t,"utf-8"),a=JSON.parse(n),s=a.vault_config||{};return{system_dir:s.system_dir||a.system_dir||r.system_dir,resources_dir:s.resources_dir||a.resources_dir||r.resources_dir,literature_dir:s.literature_dir||a.literature_dir||r.literature_dir,base_dir:s.base_dir||a.base_dir||r.base_dir,_warning:null}}catch(n){return console.warn("PaperForge: Failed to read paperforge.json, using defaults",n),{...r,_warning:"paperforge.json invalid; using defaults"}}}function Q(h,u){let e=zt(h,u),t=W.join(h,e.system_dir,"PaperForge");return{vault:h,systemDir:t,indexesDir:W.join(t,"indexes"),logsDir:W.join(t,"logs"),dbPath:W.join(t,"indexes","paperforge.db"),memoryStatePath:W.join(t,"indexes","memory-runtime-state.json"),vectorStatePath:W.join(t,"indexes","vector-runtime-state.json"),healthStatePath:W.join(t,"indexes","runtime-health.json"),buildStatePath:W.join(t,"indexes","vector-build-state.json"),orphanStatePath:W.join(t,"indexes","sync-orphan-state.json"),exportsDir:W.join(t,"exports"),ocrDir:W.join(t,"ocr"),pluginDataPath:W.join(h,".obsidian","plugins","paperforge","data.json"),pfJsonPath:W.join(h,"paperforge.json"),configWarning:e._warning}}function Xe(h){try{return ye.existsSync(h)?JSON.parse(ye.readFileSync(h,"utf-8")):null}catch(u){return null}}function $t(h){let u=Q(h);return Xe(u.memoryStatePath)}function Re(h){let u=Q(h);return Xe(u.vectorStatePath)}function Ye(h){let u=Q(h);return Xe(u.healthStatePath)}function ht(h){var e;let u=Ye(h);return!!(u&&((e=u.summary)==null?void 0:e.status)==="ok")}function Ie(h){let u=$t(h);return!u||u.paper_count_db===0?"DB not found. Run paperforge memory build.":"Papers: "+u.paper_count_db+" | "+(u.fresh?"fresh":"stale")}function be(h){var t,r,n;let u=Re(h);return u?u.healthy===!1?"Vector index unreadable - rebuild required":"Chunks: "+(((t=u.chunk_count)!=null?t:0)+((r=u.body_chunk_count)!=null?r:0)+((n=u.object_chunk_count)!=null?n:0))+" | "+u.model+" | "+u.mode:"Status unavailable"}function ce(h,u){if(ae)return ae;if(u&&u.python_path&&u.python_path.trim()){let r=u.python_path.trim();if(ye.existsSync(r))return ae={path:r,source:"manual",extraArgs:[]},ae}let e=[W.join(h,".paperforge-test-venv","Scripts","python.exe"),W.join(h,".venv","Scripts","python.exe"),W.join(h,"venv","Scripts","python.exe")];for(let r=0;r({...a,_selected:!0,_idx:s})),this.vaultPath=r,this.py=n}_updateUI(){let e=this.orphans.filter(t=>t._selected);this._countEl.setText(o("orphan_delete_selected").replace("{count}",String(e.length))),this._selectAllBtn.setText(e.length===this.orphans.length?o("orphan_deselect_all"):o("orphan_select_all"));for(let t of this.orphans){let r=this._rowEls[t._idx];r&&r.toggleClass("paperforge-orphan-dimmed",!t._selected)}}onOpen(){let{contentEl:e}=this;e.addClass("paperforge-modal"),e.createEl("h2",{text:o("orphan_title").replace("{count}",String(this.orphans.length))}),e.createEl("p",{cls:"paperforge-modal-desc",text:o("orphan_desc")}),this._rowEls=[];let t=e.createEl("div",{cls:"paperforge-orphan-list"});for(let n of this.orphans){let a=t.createEl("div",{cls:"paperforge-orphan-row"+(n._selected?"":" paperforge-orphan-dimmed")});this._rowEls.push(a);let s=a.createEl("div",{cls:"paperforge-orphan-info"}),l=s.createEl("div",{cls:"paperforge-orphan-header"});l.createEl("span",{cls:"paperforge-orphan-key",text:n.citation_key||n.key});let i=l.createEl("span",{cls:"paperforge-orphan-tags"});i.createEl("span",{cls:"paperforge-tag "+(n.has_pdf?"tag-pdf":"tag-nopdf"),text:n.has_pdf?"PDF":"no PDF"}),n.collection_path&&i.createEl("span",{cls:"paperforge-tag tag-collection",text:n.collection_path}),n.title&&s.createEl("div",{cls:"paperforge-orphan-title",text:n.title});let c=[];n.authors&&c.push(n.authors),n.year&&c.push(n.year),c.length>0&&s.createEl("div",{cls:"paperforge-orphan-meta",text:c.join(" \xB7 ")}),s.createEl("div",{cls:"paperforge-orphan-explain",text:o("orphan_explain")}),a.addEventListener("click",()=>{n._selected=!n._selected,this._updateUI()})}let r=e.createEl("div",{cls:"paperforge-modal-actions"});this._selectAllBtn=r.createEl("button",{cls:"paperforge-step-btn",text:"Deselect all"}),this._selectAllBtn.addEventListener("click",()=>{let n=this.orphans.every(a=>a._selected);for(let a of this.orphans)a._selected=!n;this._updateUI()}),this._countEl=r.createEl("button",{cls:"paperforge-step-btn mod-cta",text:"Delete "+this.orphans.length+" selected"}),r.createEl("button",{cls:"paperforge-step-btn",text:"Keep all"}).addEventListener("click",()=>this.close()),this._countEl.addEventListener("click",()=>{let n=this.orphans.filter(s=>s._selected);if(n.length===0){new G.Notice(o("orphan_none_selected"));return}if(this._countEl.setText("Deleting..."),this._countEl.setAttr("disabled",""),this._selectAllBtn.setAttr("disabled",""),!this.py||!this.py.path){new G.Notice("PaperForge: Python not found"),this.close();return}let a=n.map(s=>s.key);(0,De.execFile)(this.py.path,[...this.py.extraArgs,"-m","paperforge","--vault",this.vaultPath,"prune","--force","--json",...a],{cwd:this.vaultPath,timeout:6e4},(s,l)=>{if(s){new G.Notice("PaperForge: prune failed"),this.close();return}try{let i=JSON.parse(l),c=i.data&&i.data.deleted||[];new G.Notice("Deleted "+c.length+" orphan workspace(s)")}catch(i){new G.Notice("PaperForge: prune done")}this.close()})})}onClose(){this.contentEl.empty()}};function Ne(h,u,e){console.log("[PF] checkOrphanState called");try{let r=Q(e).orphanStatePath;if(!te.existsSync(r)){console.log("[PF] orphan file NOT FOUND");return}console.log("[PF] orphan file FOUND");let n=te.readFileSync(r,"utf-8"),s=JSON.parse(n).orphans||[];if(console.log("[PF] orphans count:",s.length),s.length===0)return;let l=ce(e,u.settings);console.log("[PF] py.path:",l?l.path:"null"),new et(h,s,e,l).open(),te.unlinkSync(r),console.log("[PF] orphan file cleaned")}catch(t){console.log("[PF] checkOrphanState exception:",t.message||t)}}var Te=class extends G.Modal{constructor(e,t){super(e);this._pendingSave=null;this._showSkipConfirm=!1;this.plugin=t,this._step=1}onOpen(){this._render()}onClose(){this.contentEl.empty()}_render(){let{contentEl:e}=this;e.empty(),e.addClass("paperforge-modal"),this._renderStepIndicator(),this._renderStepContent(),this._renderNavigation()}_renderStepIndicator(){let e=[o("wizard_step1"),o("wizard_step2"),o("wizard_step3"),o("wizard_step4"),o("wizard_step5")],t=this.contentEl.createEl("div",{cls:"paperforge-step-bar"});e.forEach((r,n)=>{let a=n+1,s=t.createEl("div",{cls:`paperforge-step-dot ${a===this._step?"active":""} ${a1&&e.createEl("button",{cls:"paperforge-step-btn",text:o("nav_prev")}).addEventListener("click",()=>{this._step--,this._showSkipConfirm=!1,this._render()}),this._step<5?e.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("nav_next")}).addEventListener("click",()=>{if(this._step===3){let r=this._validateStep3();if(r.blocked){if(r.reason==="zotero")return;if(r.reason==="ocr"){this._showSkipConfirm=!0,this._render();return}}}this._step++,this._showSkipConfirm=!1,this._render()}):e.createEl("button",{cls:"paperforge-step-btn",text:o("nav_close")}).addEventListener("click",()=>this.close())}_validateStep3(){let e=this.plugin.settings,t=gt(this._apiKeyValidated,e.zotero_data_dir);if(t.reason==="ocr")return t;let r=(e.zotero_data_dir||"").trim();if(!r)return new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879\uFF0C\u8BF7\u586B\u5199\u8DEF\u5F84"),{blocked:!0,reason:"zotero"};if(!te.existsSync(r))return new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u5B58\u5728"),{blocked:!0,reason:"zotero"};if(!te.statSync(r).isDirectory())return new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u662F\u4E00\u4E2A\u76EE\u5F55"),{blocked:!0,reason:"zotero"};let n=_t.join(r,"storage");return!te.existsSync(n)||!te.statSync(n).isDirectory()?(new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u4E2D\u672A\u627E\u5230 storage/ \u5B50\u76EE\u5F55"),{blocked:!0,reason:"zotero"}):{blocked:!1}}_stepOverview(e){e.createEl("h2",{text:o("wizard_title")}),e.createEl("p",{text:o("wizard_intro")});let t=this.plugin.settings,r=this.app.vault.adapter.basePath,n=e.createEl("div",{cls:"paperforge-dir-tree"}),a=n.createEl("div",{cls:"paperforge-dir-node root"});a.textContent=`\u{1F4C1} Vault (${r})`;let s=n.createEl("div",{cls:"paperforge-dir-children"}),l=s.createEl("div",{cls:"paperforge-dir-node folder"});l.textContent=`\u{1F4C1} ${t.resources_dir||"Resources"}/ \u2014 \u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08Base \u6570\u636E\u6765\u6E90\uFF09`,l.createEl("div",{cls:"paperforge-dir-children"}).createEl("div",{cls:"paperforge-dir-node file",text:`\u{1F4C1} ${t.literature_dir||"Literature"}/ \u2014 \u6587\u732E\u5361\u7247`}),s.createEl("div",{cls:"paperforge-dir-node folder",text:`\u{1F4C1} ${t.base_dir||"Bases"}/ \u2014 \u6570\u636E\u7BA1\u7406\u9762\u677F`}),s.createEl("div",{cls:"paperforge-dir-node folder",text:`\u{1F4C1} ${t.system_dir||"System"}/ \u2014 Zotero \u8F6F\u94FE\u63A5 + PaperForge \u7CFB\u7EDF\u6587\u4EF6\u5939`}),e.createEl("p",{text:o("wizard_preview"),cls:"paperforge-modal-hint"}),e.createEl("p",{text:o("wizard_safety"),cls:"paperforge-modal-hint"});let c=e.createEl("div",{cls:"paperforge-summary"}),d=[{label:o("dir_resources"),val:`${r}/${t.resources_dir||"Resources"}`},{label:o("dir_notes"),val:`${r}/${t.resources_dir||"Resources"}/${t.literature_dir||"Literature"}`},{label:o("dir_base"),val:`${r}/${t.base_dir||"Bases"}`},{label:o("dir_system"),val:`${r}/${t.system_dir||"System"}`}];for(let g of d){let p=c.createEl("div",{cls:"paperforge-summary-row"});p.createEl("span",{cls:"paperforge-summary-label",text:g.label}),p.createEl("span",{cls:"paperforge-summary-value",text:g.val})}}_stepDirectories(e){e.createEl("h2",{text:o("wizard_step2")}),e.createEl("p",{text:o("wizard_intro")});let t=this.plugin.settings,r=this.app.vault.adapter.basePath;this._modalField(e,o("dir_vault"),r,!0),e.createEl("p",{text:o("wizard_dir_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u8D44\u6E90\u76EE\u5F55\uFF08\u521B\u5EFA\u6587\u732E\u5361\u7247\u76EE\u5F55\u7684\u5730\u65B9\uFF09","resources_dir",t.resources_dir,"Resources"),e.createEl("p",{text:o("wizard_dir_sub_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08\u5B58\u653E\u6587\u732E\u5361\u7247\u7684\u5730\u65B9\uFF0CBase \u6570\u636E\u6765\u6E90\uFF09","literature_dir",t.literature_dir,"Literature"),e.createEl("p",{text:o("wizard_sys_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u7CFB\u7EDF\u76EE\u5F55\uFF08\u5B58\u653E Zotero \u8F6F\u94FE\u63A5\u548C PaperForge \u7CFB\u7EDF\u6587\u4EF6\uFF09","system_dir",t.system_dir,"System"),this._modalInput(e,"Base \u76EE\u5F55\uFF08\u5B58\u653E\u6570\u636E\u7BA1\u7406\u9762\u677F\u7684\u5730\u65B9\uFF09","base_dir",t.base_dir,"Bases"),e.createEl("p",{text:o("wizard_safety"),cls:"paperforge-modal-hint"});let n=e.createEl("div",{cls:"paperforge-summary"}),a=[{label:o("dir_resources"),val:`${r}/${t.resources_dir||""}`},{label:o("dir_notes"),val:`${r}/${t.resources_dir||""}/${t.literature_dir||""}`},{label:o("dir_system"),val:`${r}/${t.system_dir||""}`},{label:o("dir_base"),val:`${r}/${t.base_dir||""}`}];for(let s of a){let l=n.createEl("div",{cls:"paperforge-summary-row"});l.createEl("span",{cls:"paperforge-summary-label",text:s.label}),l.createEl("span",{cls:"paperforge-summary-value",text:s.val})}}_stepKeys(e){if(e.createEl("h2",{text:o("wizard_step3")}),this._showSkipConfirm){this._renderSkipConfirm(e);return}let t=this.plugin.settings;e.createEl("p",{text:o("wizard_agent_hint"),cls:"paperforge-modal-hint"});let r=[{key:"opencode",name:"OpenCode"},{key:"claude",name:"Claude Code"},{key:"cursor",name:"Cursor"},{key:"github_copilot",name:"GitHub Copilot"},{key:"windsurf",name:"Windsurf"},{key:"codex",name:"Codex"},{key:"gemini",name:"Gemini CLI"},{key:"cline",name:"Cline"}],n=e.createEl("div",{cls:"paperforge-modal-field"});n.createEl("label",{cls:"paperforge-modal-label",text:o("label_agent")});let a=n.createEl("select",{cls:"paperforge-modal-select"});for(let g of r){let p=a.createEl("option",{text:g.name,attr:{value:g.key}});g.key===(t.agent_platform||"opencode")&&(p.selected=!0)}a.addEventListener("change",()=>{t.agent_platform=a.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)}),e.createEl("p",{text:o("wizard_keys_hint"),cls:"paperforge-modal-hint"});let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:o("field_paddleocr")});let l=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"password",placeholder:"API Key"}});l.value=t.paddleocr_api_key||"",this._apiKeyValidated=!1,this._apiKeyStatus=s.createEl("span",{cls:"paperforge-apikey-status",text:""});let i=s.createEl("button",{cls:"paperforge-step-btn",text:"\u9A8C\u8BC1"});i.addEventListener("click",()=>this._validateApiKey(l.value,i)),l.addEventListener("input",()=>{t.paddleocr_api_key=l.value,this._apiKeyValidated=!1,this._apiKeyStatus.textContent="",this._apiKeyStatus.className="paperforge-apikey-status"}),this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500),e.createEl("p",{text:o("wizard_api_hint_skip"),cls:"paperforge-modal-hint"});let c=e.createEl("div",{cls:"paperforge-modal-field"});c.createEl("label",{cls:"paperforge-modal-label",text:o("field_zotero_data")});let d=c.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text",placeholder:o("field_zotero_placeholder")}});d.value=t.zotero_data_dir||"",d.addEventListener("input",()=>{t.zotero_data_dir=d.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_validateApiKey(e,t){if(!e||e.length<10){this._apiKeyStatus.textContent="\u5BC6\u94A5\u683C\u5F0F\u4E0D\u6B63\u786E\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error";return}t.disabled=!0,t.textContent="\u9A8C\u8BC1\u4E2D\u2026",this._apiKeyStatus.textContent="\u6B63\u5728\u9A8C\u8BC1\u2026",this._apiKeyStatus.className="paperforge-apikey-status";let r=JSON.stringify({model:"PaddleOCR-VL-1.5"}),n={hostname:"paddleocr.aistudio-app.com",path:"/api/v2/ocr/jobs",method:"POST",headers:{Authorization:"bearer "+e,"Content-Type":"application/json","Content-Length":Buffer.byteLength(r)},timeout:1e4},a=mt.request(n,s=>{t.disabled=!1,t.textContent="\u9A8C\u8BC1";let l="";s.on("data",i=>l+=i),s.on("end",()=>{try{let i=JSON.parse(l);s.statusCode===400&&i.code===10001?(this._apiKeyStatus.textContent="\u2713 \u5BC6\u94A5\u6709\u6548",this._apiKeyStatus.className="paperforge-apikey-status ok",this._apiKeyValidated=!0):s.statusCode===401?(this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5BC6\u94A5\u65E0\u6548\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1):(this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1AAPI \u8FD4\u56DE "+s.statusCode+"\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1)}catch(i){this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u89E3\u6790\u54CD\u5E94\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1}})});a.on("error",s=>{t.disabled=!1,t.textContent="\u9A8C\u8BC1",this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u8FDE\u63A5 ("+s.message+")\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1}),a.write(r),a.end()}_renderSkipConfirm(e){e.createEl("p",{text:o("wizard_skip_ocr_desc"),cls:"paperforge-modal-desc"});let t=e.createEl("div",{cls:"paperforge-modal-actions"});t.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("wizard_skip_ocr_continue")}).addEventListener("click",()=>{this._showSkipConfirm=!1,this._step++,this._render()}),t.createEl("button",{cls:"paperforge-step-btn",text:o("wizard_skip_ocr_back")}).addEventListener("click",()=>{this._showSkipConfirm=!1,this._render()})}_modalField(e,t,r,n){let a=e.createEl("div",{cls:"paperforge-modal-field"});a.createEl("label",{cls:"paperforge-modal-label",text:t});let s=a.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text"}});s.value=r,s.disabled=!!n}_modalInput(e,t,r,n,a){let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:t});let l=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text",placeholder:a||""}});l.value=n;let i=this.plugin.settings;l.addEventListener("input",()=>{i[r]=l.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_modalSecret(e,t,r,n,a){let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:t});let l=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"password",placeholder:a||""}});l.value=n;let i=this.plugin.settings;l.addEventListener("input",()=>{i[r]=l.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_stepInstall(e){e.createEl("h2",{text:o("wizard_step4")}),this._installLog=e.createEl("div",{cls:"paperforge-install-log"});let t=e.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("install_btn")});t.addEventListener("click",()=>this._runInstall(t))}async _runInstall(e){var s,l,i,c,d,g;e.disabled=!0,e.textContent=o("install_btn_running"),this._installLog.setText(o("install_validating")+` +`),this._log(o("install_validating"));let t=this.plugin.settings,r=this._validate();if(r.length>0){this._log(o("validate_fail")+":"),r.forEach(p=>this._log(" \u2717 "+p)),e.disabled=!1,e.textContent=o("install_btn_retry");return}let n=(p,f={})=>new Promise((y,b)=>{let{path:m,extraArgs:x=[]}=L(t.vault_path.trim(),this.plugin.settings,void 0,void 0),w=(0,De.spawn)(m,[...x,...p],{cwd:t.vault_path.trim(),env:me(),timeout:12e4,...f}),E="",_="";w.stdout.on("data",v=>{let k=v.toString("utf-8");E+=k,f.logStdout&&this._processSetupOutput(k)}),w.stderr.on("data",v=>{let k=v.toString("utf-8");_+=k,this._log("[stderr] "+k.trim())}),w.on("close",v=>{v===0?y({stdout:E,stderr:_}):b(new Error(_.trim()||E.trim()||`exit code ${v}`))}),w.on("error",v=>b(v))}),a=["-m","paperforge","--vault",t.vault_path.trim(),"setup","--headless","--system-dir",t.system_dir.trim(),"--resources-dir",t.resources_dir.trim(),"--literature-dir",t.literature_dir.trim(),"--base-dir",t.base_dir.trim(),"--agent",t.agent_platform||"opencode"];t.zotero_data_dir&&t.zotero_data_dir.trim()&&a.push("--zotero-data",t.zotero_data_dir.trim()),t.paddleocr_api_key&&t.paddleocr_api_key.trim()&&a.push("--paddleocr-key",t.paddleocr_api_key.trim());try{let p=!0;try{await n(["-c","import paperforge"])}catch(f){p=!1}if(!p){this._log(o("install_bootstrapping"));let f=this.plugin.manifest.version;this._log(`[install] Trying PyPI: pip install paperforge==${f}`);let y=["-m","pip","install","--upgrade"];process.platform!=="win32"&&y.push("--user"),y.push(`paperforge==${f}`);try{await n(y,{logStdout:!0})}catch(b){this._log(`[install] PyPI failed, falling back to git: git+https://...@v${f}`),console.warn("[PaperForge] PyPI install failed, falling back to git:",(s=b.message)==null?void 0:s.slice(0,200));let m=["-m","pip","install","--upgrade"];process.platform!=="win32"&&m.push("--user"),m.push(`git+https://github.com/LLLin000/PaperForge.git@v${f}`),await n(m,{logStdout:!0})}}await n(a,{logStdout:!0,env:me()}),this._log(o("install_complete")),t.setup_complete=!0,await this.plugin.saveSettings(),setTimeout(()=>{this._step=5,this._render()},800)}catch(p){console.error("PaperForge setup failed:",p.message);let f=this._formatSetupError(p.message);this._log(o("install_failed")+f);let y=(l=this._installLog.parentElement)==null?void 0:l.createEl("button",{cls:"paperforge-copy-diag-btn",text:o("error_copy_diagnostic")||"Copy diagnostic"});if(y){let b=p.message,m=((c=(i=this.plugin)==null?void 0:i.settings)==null?void 0:c.python_path)||"auto",x=((g=(d=this.plugin)==null?void 0:d.manifest)==null?void 0:g.version)||"?",w=process.platform+" "+process.arch,E,_;try{E=Ue()||"(not found)"}catch(P){E="(error)"}try{_=L(t.vault_path.trim(),this.plugin.settings,void 0,void 0)}catch(P){_=null}let v=(process.env.PATH||"").length,k=(process.env.PATH||"").toLowerCase().includes("git"),S=["[PaperForge Diagnostic]","Category: "+f,"Plugin version: "+x,"Python: "+m,"Resolved Python: "+((_==null?void 0:_.path)||"?"),"OS: "+w,"Vault path: "+(t.vault_path||"?"),"--- Git ---","Git dir (resolved): "+E,"PATH length: "+v+" chars","PATH contains git: "+k,"--- Raw error ---",b.slice(0,2e3)].join(` +`);y.addEventListener("click",()=>{navigator.clipboard.writeText(S).then(()=>{y.setText(o("error_copied")||"Copied!"),setTimeout(()=>{y.setText(o("error_copy_diagnostic")||"Copy diagnostic")},3e3)}).catch(()=>{new G.Notice("[!!] Clipboard write failed",6e3)})})}e.disabled=!1,e.textContent=o("install_btn_retry")}}_log(e){this._installLog&&this._installLog.setText(this._installLog.textContent+e+` +`)}_validate(){let e=[],t=this.plugin.settings;return(!t.vault_path||!t.vault_path.trim())&&e.push(o("validate_vault")),(!t.resources_dir||!t.resources_dir.trim())&&e.push(o("validate_resources")),(!t.literature_dir||!t.literature_dir.trim())&&e.push(o("validate_notes")),(!t.base_dir||!t.base_dir.trim())&&e.push(o("validate_base")),(!t.paddleocr_api_key||!t.paddleocr_api_key.trim())&&this._log(" ! "+o("validate_key")+" "+o("optional_later")),(!t.zotero_data_dir||!t.zotero_data_dir.trim())&&this._log(" ! "+o("validate_zotero")+" "+o("optional_later")),e}_processSetupOutput(e){let t=e.split(` +`).filter(Boolean);for(let r of t)if(r.includes("[*]")||r.includes("[OK]")||r.includes("[FAIL]")){let n=r.replace(/^\[\*\].*\d+:?\s*/,"").replace(/^\[OK\]\s*/,"").replace(/^\[FAIL\]\s*/,"");this._log(" "+n)}}_formatSetupError(e){if(process.platform==="darwin"&&/No module named ['"]?paperforge/i.test(e))return"PaperForge not installed \u2014 install Python from Homebrew or python.org (Apple CLT /Library/Developer/CommandLineTools python often fails); then: python3 -m pip install --user git+https://github.com/LLLin000/PaperForge.git";let t=[{match:/pip.*not found|No module named.*pip|command not found.*pip/i,msg:"pip not found"},{match:/command not found|No such file|not recognized/i,msg:"Python not found"},{match:/resolve host|getaddrinfo.*nodename|connect ETIMEDOUT|connect ECONNREFUSED|fetch failed|Network error|ENOTFOUND|ECONNREFUSED|ECONNRESET/i,msg:"Network error"},{match:/certificate verify failed|SSL.*certificate|self.signed.cert|CERTIFICATE_VERIFY_FAILED/i,msg:"SSL certificate error"},{match:/No space left on device|disk full|ENOSPC/i,msg:"Disk full"},{match:/paperforge.*not found|cannot import|ModuleNotFoundError|No module named/i,msg:"PaperForge not installed"},{match:/permission denied|EACCES|EPERM/i,msg:"Permission denied"},{match:/ENOENT/i,msg:"Path not found"},{match:/timeout|timed out/i,msg:"Timeout"}];for(let n of t)if(n.match.test(e))return n.msg;return e.split(` +`).filter(Boolean).slice(0,3).join(" | ").slice(0,200)||"Unknown error"}_stepComplete(e){e.createEl("h2",{text:o("complete_title")});let t=e.createEl("div",{cls:"paperforge-summary"});t.createEl("div",{cls:"paperforge-summary-title",text:o("complete_summary")});let r=this.plugin.settings,n=this.app.vault.adapter.basePath,a=[{label:o("dir_vault"),val:n},{label:o("dir_resources"),val:`${n}/${r.resources_dir}`},{label:o("dir_notes"),val:`${n}/${r.resources_dir}/${r.literature_dir}`},{label:o("dir_base"),val:`${n}/${r.base_dir}`},{label:o("dir_system"),val:`${n}/${r.system_dir}`},{label:"API Key",val:r.paddleocr_api_key?o("api_key_set"):o("api_key_missing")},{label:o("field_zotero_data"),val:r.zotero_data_dir||o("not_set")}];for(let d of a){let g=t.createEl("div",{cls:"paperforge-summary-row"});g.createEl("span",{cls:"paperforge-summary-label",text:d.label}),g.createEl("span",{cls:"paperforge-summary-value",text:d.val})}let s=t.createEl("div",{cls:"paperforge-summary-row"});s.createEl("span",{cls:"paperforge-summary-label",text:"PaperForge"});let l=s.createEl("span",{cls:"paperforge-summary-value",text:"\u2014"});{let d=n,{path:g,extraArgs:p=[]}=L(d,this.plugin.settings,void 0,void 0);(0,De.execFile)(g,[...p,"-c","import paperforge; print(paperforge.__version__)"],{cwd:d,timeout:1e4},(f,y)=>{!f&&y&&(l.textContent="v"+y.trim())})}for(let d of a){let g=t.createEl("div",{cls:"paperforge-summary-row"});g.createEl("span",{cls:"paperforge-summary-label",text:d.label}),g.createEl("span",{cls:"paperforge-summary-value",text:d.val})}e.createEl("h3",{text:o("complete_next")});let i=e.createEl("div",{cls:"paperforge-nextsteps"}),c=[[o("complete_step4"),o("complete_step4_desc")],["",`${o("complete_export_path")} ${n}/${r.system_dir}/PaperForge/exports/`],[o("complete_step1"),o("complete_step1_desc")],[o("complete_step2"),o("complete_step2_desc")],[o("complete_step3"),o("complete_step3_desc")]];for(let[d,g]of c){let p=i.createEl("div",{cls:"paperforge-nextstep-item"});d&&p.createEl("strong",{text:d}),p.createEl("span",{text:g})}}};var xe=$(require("fs")),ze=$(require("path")),vt=require("child_process");function bt(h){return ze.join(h,"System","PaperForge","cache","ocr_maintenance.json")}function xt(h){try{let u=bt(h),e=xe.readFileSync(u,"utf-8");return JSON.parse(e)}catch(u){return null}}function $e(h,u){let e=bt(h),t=ze.dirname(e);xe.mkdirSync(t,{recursive:!0}),xe.writeFileSync(e,JSON.stringify(u,null,2),"utf-8")}function yt(h,u,e){return new Promise((t,r)=>{(0,vt.execFile)(h,u,e,(n,a)=>{n?r(n):t(a)})})}async function Et(h,u,e,t){let r=await yt(u,[...e,"-m","paperforge","ocr","list","--manifest"],{cwd:h,timeout:3e4}),n=JSON.parse(r);if(t){let d=Object.keys(t.manifest),g=Object.keys(n);if(d.length===g.length&&d.every(f=>t.manifest[f]===n[f]))return{data:Object.values(t.papers).filter(y=>y.visible_in_maintenance),changed:!1}}let a=Object.keys(n).filter(d=>!(t!=null&&t.manifest[d])||t.manifest[d]!==n[d]),s=await yt(u,[...e,"-m","paperforge","ocr","list","--json","--keys",...a],{cwd:h,timeout:3e4}),l=JSON.parse(s),i={manifest:n,papers:{},cached_at:new Date().toISOString()};if(t!=null&&t.papers)for(let d of Object.keys(n))t.papers[d]&&(i.papers[d]=t.papers[d]);for(let d of l)i.papers[d.key]=d;return $e(h,i),{data:Object.values(i.papers).filter(d=>d.visible_in_maintenance),changed:!0}}var je=class extends C.PluginSettingTab{constructor(e,t){super(e,t);this._saveTimeout=null;this._pfConfig=null;this._lastSyncTime=null;this._memoryStatusText=null;this._vectorDepsOk=null;this._embedStatusText=null;this._skillsCollapsed={user:!0};this._featurePanelsCollapsed={};this._advCollapsed=!0;this._refreshPending=!1;this._pythonInterpDescEl=null;this._customPathDescEl=null;this._checkEl=null;this.activeTab="setup";this.plugin=t}_refreshPfConfig(){this._pfConfig=this.plugin.readPaperforgeJson()}display(){let{containerEl:e}=this;if(e.empty(),this._refreshPfConfig(),!document.getElementById("paperforge-tab-styles")){let a=document.createElement("style");a.id="paperforge-tab-styles",a.textContent=` .paperforge-settings-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--background-modifier-border); } .paperforge-settings-tab { padding: 6px 16px; border: none; background: none; cursor: pointer; border-bottom: 2px solid transparent; font-size: 14px; color: var(--text-muted); } .paperforge-settings-tab--active { color: var(--text-accent); border-bottom-color: var(--text-accent); } @@ -4998,4648 +29,26 @@ var er = class extends z.PluginSettingTab { .paperforge-manual-links a { color: var(--text-accent); } .paperforge-modal-subtitle { color: var(--text-muted); font-size: 13px; margin-bottom: 12px; } .paperforge-modal-item { font-size: 13px; margin-left: 8px; color: var(--text-muted); } - `), - document.head.appendChild(c)); - } - let n = r.createDiv({ cls: "paperforge-settings-tabs" }), - i = [ - { id: "setup", label: f("tab_setup") || "\u5B89\u88C5" }, - { id: "features", label: f("tab_features") || "\u529F\u80FD" }, - { id: "maintenance", label: f("tab_maintenance") || "\u7EF4\u62A4" }, - { id: "release-notes", label: "\u66F4\u65B0\u4E0E\u624B\u518C" }, - ], - a = {}; - (i.forEach((c) => { - n.createEl("button", { - cls: - "paperforge-settings-tab" + - (c.id === this.activeTab ? " paperforge-settings-tab--active" : ""), - text: c.label, - }).addEventListener("click", () => { - ((this.activeTab = c.id), this.display()); - }); - }), - i.forEach((c) => { - a[c.id] = r.createDiv({ - cls: - "paperforge-tab-content" + - (c.id === this.activeTab ? " paperforge-tab-content--active" : ""), - }); - }), - this.activeTab === "setup" - ? this._renderSetupTab(a.setup) - : this.activeTab === "features" - ? this._renderFeaturesTab(a.features) - : this.activeTab === "maintenance" - ? this._renderMaintenanceTab(a.maintenance) - : this._renderReleaseNotesTab(a["release-notes"])); - } - _renderSetupTab(r) { - let n = this.app.vault.adapter.basePath; - (this.plugin.settings.vault_path || - ((this.plugin.settings.vault_path = n), this._debouncedSave()), - this.plugin.settings.setup_complete && - (ie.existsSync(me.join(n, "paperforge.json")) || - ((this.plugin.settings.setup_complete = !1), this._debouncedSave())), - r.createEl("h2", { text: f("header_title") || "PaperForge" }), - r.createEl("p", { text: f("desc"), cls: "paperforge-settings-desc" })); - let a = r - .createEl("div", { cls: "paperforge-setup-bar" }) - .createEl("span", { cls: "paperforge-setup-label" }); - this.plugin.settings.setup_complete - ? (a.setText(f("setup_done")), a.addClass("paperforge-setup-done")) - : (a.setText(f("setup_pending")), a.addClass("paperforge-setup-pending")); - let c = this.app.vault.adapter.basePath, - l = re(c, this.plugin.settings, void 0, void 0), - u = l.path, - p = this.plugin.settings._python_path_stale ? "stale" : l.source, - h = new z.Setting(r) - .setName(f("field_python_interp")) - .setDesc(this._getPythonDesc(u, p)); - this._pythonInterpDescEl = h.descEl; - let b = new z.Setting(r).setName(f("field_python_custom")).setDesc(""); - ((this._customPathDescEl = b.descEl), - b.addText((A) => { - A.setPlaceholder("e.g. C:\\Python310\\python.exe") - .setValue(this.plugin.settings.python_path || "") - .onChange((v) => { - if ( - ((this.plugin.settings.python_path = v), - this.plugin.saveSettings(), - v && v.trim()) - ) { - let M = ie.existsSync(v.trim()); - this.plugin.settings._python_path_stale = !M; - } else this.plugin.settings._python_path_stale = !1; - let w = re( - this.app.vault.adapter.basePath, - this.plugin.settings, - void 0, - void 0 - ), - O = this.plugin.settings._python_path_stale ? "stale" : w.source; - this._pythonInterpDescEl && - (this._pythonInterpDescEl.textContent = this._getPythonDesc( - w.path, - O - )); - }); - }), - b.addButton((A) => { - A.setButtonText(f("btn_validate")).onClick(() => - this._validatePythonOverride() - ); - }), - r.createEl("h3", { text: f("runtime_health") }), - r.createEl("p", { - text: f("runtime_health_desc"), - cls: "paperforge-settings-desc", - })); - let k = new z.Setting(r) - .setName("PaperForge") - .setDesc(f("runtime_health_checking")), - g = k.descEl.createEl("span", { cls: "paperforge-runtime-badge" }), - x = null; - k.addButton((A) => { - ((x = A), - A.setButtonText(f("runtime_health_sync")) - .setDisabled(!0) - .onClick(() => this._syncRuntime(A))); - }); - { - let A = this.app.vault.adapter.basePath, - { path: v, extraArgs: w = [] } = re( - A, - this.plugin.settings, - void 0, - void 0 - ), - O = this.plugin.manifest.version || "?"; - (0, oe.execFile)( - v, - [...w, "-c", "import paperforge; print(paperforge.__version__)"], - { cwd: A, timeout: 1e4 }, - (M, I) => { - let J = this.plugin.settings.setup_complete, - q = !M && I ? I.trim() : null, - te = q - ? `${f("runtime_health_plugin_ver").replace("{0}", O)} \u2192 ${f("runtime_health_package_ver").replace("{0}", q)}` - : J - ? `Plugin v${O} \u2192 Python package not installed. Click "Sync Runtime" to install.` - : `Plugin v${O} \u2192 Not configured. Please open the setup wizard first.`; - (k.setDesc(te), - q === O - ? (g.setText(f("runtime_health_match")), - (g.className = "paperforge-runtime-badge match"), - x && x.setDisabled(!0)) - : q - ? (g.setText(f("runtime_health_mismatch")), - (g.className = "paperforge-runtime-badge mismatch"), - x && x.setDisabled(!1)) - : (g.setText(J ? "Not installed" : "Setup needed"), - (g.className = "paperforge-runtime-badge missing"), - x && x.setDisabled(!1))); - } - ); - } - (r.createEl("h3", { text: f("section_prep") }), - r.createEl("p", { - text: f("section_prep_desc"), - cls: "paperforge-settings-desc", - })); - let C = r.createEl("div", { cls: "paperforge-guide" }), - R = [ - ["prep_python", "prep_python_desc"], - ["prep_zotero", "prep_zotero_desc"], - ["prep_bbt", "prep_bbt_desc"], - ["prep_key", "prep_key_desc"], - ]; - for (let [A, v] of R) { - let w = C.createEl("div", { cls: "paperforge-guide-item" }); - (w.createEl("strong", { text: f(A) }), - w.createEl("span", { text: " \u2014 " + f(v) })); - } - this._checkEl = r.createEl("div", { cls: "paperforge-message" }); - let S = !this.plugin.settings.setup_complete; - (new z.Setting(r) - .setName(f(S ? "btn_install" : "btn_reconfig")) - .setDesc(f(S ? "btn_install_desc" : "btn_reconfig_desc")) - .addButton((A) => { - A.setButtonText(f(S ? "btn_install" : "btn_reconfig")) - .setCta() - .onClick(() => { - S - ? this._preCheck(() => { - new Tt(this.app, this.plugin).open(); - }) - : new Tt(this.app, this.plugin).open(); - }); - }), - r.createEl("h3", { text: f("section_guide") })); - let F = r.createEl("div", { cls: "paperforge-guide" }), - B = [ - ["guide_open", "guide_open_desc"], - ["guide_sync", "guide_sync_desc"], - ["guide_ocr", "guide_ocr_desc"], - ]; - for (let [A, v] of B) { - let w = F.createEl("div", { cls: "paperforge-guide-item" }); - (w.createEl("strong", { text: f(A) }), - w.createEl("span", { text: " \u2014 " + f(v) })); - } - if (this.plugin.settings.setup_complete) { - r.createEl("h3", { text: f("section_config") }); - let A = r.createEl("div", { cls: "paperforge-summary" }), - v = this.plugin.settings, - w = this._pfConfig, - O = [ - { label: f("dir_vault"), val: n }, - { - label: f("dir_resources"), - val: `${n}/${w == null ? void 0 : w.resources_dir}`, - }, - { - label: " " + f("dir_notes"), - val: `${n}/${w == null ? void 0 : w.resources_dir}/${w == null ? void 0 : w.literature_dir}`, - }, - { - label: f("dir_base"), - val: `${n}/${w == null ? void 0 : w.base_dir}`, - }, - { - label: f("dir_system"), - val: `${n}/${w == null ? void 0 : w.system_dir}`, - }, - { - label: "API Key", - val: v.paddleocr_api_key ? f("api_key_set") : f("api_key_missing"), - }, - { - label: f("field_zotero_data"), - val: v.zotero_data_dir || f("not_set"), - }, - ]; - for (let M of O) { - let I = A.createEl("div", { cls: "paperforge-summary-row" }); - (I.createEl("span", { cls: "paperforge-summary-label", text: M.label }), - I.createEl("span", { cls: "paperforge-summary-value", text: M.val })); - } - } - } - _execMemoryStatus(r, n, i) { - (0, oe.exec)( - `"${r}" -m paperforge --vault "${n}" memory status --json`, - { encoding: "utf-8", timeout: 15e3 }, - (a, c) => { - if (a) { - i("Status unavailable"); - return; - } - try { - let l = JSON.parse(c); - if (l.ok) { - let u = l.data, - p = u.fresh ? "fresh" : "stale"; - i( - `Papers: ${u.paper_count_db} | ${p}${u.needs_rebuild ? " - needs rebuild" : ""}` - ); - } else i("DB not found. Run paperforge memory build."); - } catch (l) { - i("Could not parse status."); - } - } - ); - } - _execEmbedStatus(r, n, i) { - (0, oe.exec)( - `"${r}" -m paperforge --vault "${n}" embed status --json`, - { encoding: "utf-8", timeout: 15e3 }, - (a, c) => { - if (a) { - i("Status unavailable"); - return; - } - try { - let l = JSON.parse(c); - l.ok - ? i( - `Chunks: ${l.data.chunk_count} | ${l.data.model} | ${l.data.mode}` - ) - : i("Could not parse status."); - } catch (l) { - i("Could not parse status."); - } - } - ); - } - _callPython(r, n) { - let i = this.app.vault.adapter.basePath, - a = Ue(i, this.plugin.settings), - c = [...a.extraArgs, "-m", "paperforge", "--vault", i, ...r]; - if (n && n.stream) { - let l = (0, oe.spawn)(a.path, c, { - cwd: i, - env: n.env || process.env, - windowsHide: !0, - }); - return ( - n.onData && l.stdout.on("data", n.onData), - n.onStderr && l.stderr.on("data", n.onStderr), - n.onError && l.on("error", n.onError), - l.on("close", n.onClose), - l - ); - } - return ( - (0, oe.execFile)( - a.path, - c, - { cwd: i, timeout: (n && n.timeout) || 6e4 }, - (l, u, p) => { - n && n.onClose && n.onClose(l ? 1 : 0, u, p); - } - ), - null - ); - } - _renderMemoryStatusText(r, n, i) { - ((r.innerHTML = ""), - r.createEl("span", { text: n, cls: "paperforge-memory-text" }), - i === "syncing" - ? r.createEl("span", { - text: "Syncing...", - cls: "paperforge-sync-status", - }) - : i && r.createEl("span", { text: i, cls: "paperforge-sync-status" })); - let a = r.createEl("button", { - cls: "paperforge-rebuild-btn", - text: f("feat_memory_rebuild_btn"), - }); - ((a.title = "Rebuild memory database"), - (a.onclick = () => { - let l = this.app.vault.adapter.basePath, - u = Ue(l, this.plugin.settings); - if (!u.path) { - new z.Notice(f("feat_no_python")); - return; - } - (console.log("[PaperForge] Rebuilding memory:", u.path), - a.setText(f("feat_memory_rebuilding")), - a.setAttr("disabled", ""), - this._callPython(["memory", "build"], { - timeout: 6e4, - onClose: (p, h, b) => { - (console.log( - "[PaperForge] memory build exit:", - p ? "FAIL:" + p : "OK", - (h || "").slice(0, 200), - (b || "").slice(0, 200) - ), - a.setText(f("feat_memory_rebuild_btn")), - a.removeAttribute("disabled"), - p === 0 - ? new z.Notice(f("feat_memory_rebuild_done")) - : new z.Notice( - f("feat_memory_rebuild_failed") + - (b ? " " + b.slice(0, 80) : "") - ), - (this._memoryStatusText = Gt(l)), - this._refreshSnapshots(l)); - }, - })); - })); - let c = r.createEl("button", { - cls: "paperforge-refresh-btn", - text: "\u21BB", - }); - ((c.title = "Sync now"), - (c.onclick = () => { - ((this._memoryStatusText = null), this._runManualSync()); - })); - } - _getBuildCommand(r) { - let n = this.app.vault.adapter.basePath, - i = re(n, r, void 0, void 0); - return i.path ? `"${i.path}" -m paperforge --vault "${n}" sync` : null; - } - _runManualSync() { - let r = this.app.vault.adapter.basePath; - if (!Ue(r, this.plugin.settings).path) return; - let i = document.querySelector(".paperforge-memory-status"); - (i && this._renderMemoryStatusText(i, "Checking...", "syncing"), - (this.plugin._autoSyncRunning = !0), - this._callPython(["sync"], { - timeout: 12e4, - onClose: (a) => { - ((this.plugin._autoSyncRunning = !1), - (this._memoryStatusText = null), - a === 0 && - ((this._lastSyncTime = new Date().toLocaleTimeString()), - (this.plugin._lastSyncTime = this._lastSyncTime)), - this.display(), - this._refreshSnapshots(r), - Qt(this.app, this.plugin, r)); - }, - })); - } - _refreshSnapshots(r) { - let n = Ue(r, this.plugin.settings), - i = [ - ...n.extraArgs, - "-m", - "paperforge", - "--vault", - r, - "runtime-health", - "--json", - ]; - ((this._refreshPending = !0), - (0, oe.execFile)( - n.path, - i, - { cwd: r, timeout: 3e4, windowsHide: !0 }, - (a, c, l) => { - ((this._refreshPending = !1), - (this._memoryStatusText = Gt(r)), - (this._embedStatusText = gt(r)), - this.display()); - } - )); - } - _renderFeaturesTab(r) { - r.createEl("h3", { text: "Skills" }); - let n = r.createEl("div", { cls: "paperforge-desc-box" }); - (n.setText(f("feat_skills_desc")), - n.createEl("br"), - n.createEl("span", { text: f("feat_skills_system") })); - let i = { - opencode: "OpenCode", - claude: "Claude Code", - codex: "Codex", - cursor: "Cursor", - windsurf: "Windsurf", - github_copilot: "GitHub Copilot", - gemini: "Gemini CLI", - }, - a = { - opencode: ".opencode/skills", - claude: ".claude/skills", - codex: ".codex/skills", - cursor: ".cursor/skills", - windsurf: ".windsurf/skills", - github_copilot: ".github/skills", - gemini: ".gemini/skills", - }, - c = this.app.vault.adapter.basePath, - l = this.plugin.settings.selected_skill_platform || "opencode"; - new z.Setting(r) - .setName(f("feat_agent_platform")) - .setDesc(f("feat_agent_platform_desc")) - .addDropdown((v) => { - (Object.entries(i).forEach(([w, O]) => v.addOption(w, O)), - v.setValue(l).onChange((w) => { - ((this.plugin.settings.selected_skill_platform = w), - this.plugin.saveSettings(), - this.display()); - })); - }) - .addExtraButton((v) => { - v.setIcon("folder") - .setTooltip("Open skills folder") - .onClick(() => { - let w = a[l] || ".opencode/skills", - O = me.join(c, w); - ie.existsSync(O) - ? (0, oe.exec)(`start "" "${O}"`) - : new z.Notice(`Skills folder not found: ${w}`); - }); - }); - let u = me.join(c, a[l]), - p = [], - h = []; - ie.existsSync(u) && - ie.readdirSync(u, { withFileTypes: !0 }).forEach((v) => { - if (!v.isDirectory()) return; - let w = me.join(u, v.name, "SKILL.md"); - if (!ie.existsSync(w)) return; - let O = ie.readFileSync(w, "utf-8"), - M = O.match(/^name:\s*(.+)$/m), - I = O.split(` -`), - J = I.findIndex((ue) => /^description:/.test(ue)), - q = ""; - if (J >= 0) { - let ue = I[J].match(/^description:\s*(.+)$/); - if (ue && ue[1] && ue[1] !== ">" && ue[1] !== "|-" && ue[1] !== "|") - q = ue[1].trim(); - else { - for ( - let V = J + 1; - V < I.length && (/^\s{2,}/.test(I[V]) || I[V].trim() === ""); - V++ - ) - q += I[V].trim() + " "; - q = q.trim(); - } - } - let te = O.match(/^source:\s*(.+)$/m), - se = O.match(/^disable-model-invocation:\s*(.+)$/m), - G = O.match(/^version:\s*(.+)$/m), - ye = { - name: M ? M[1].trim() : v.name, - desc: q, - source: te ? te[1].trim() : "user", - disabled: se && se[1].trim() === "true", - version: G ? G[1].trim() : "", - path: w, - content: O, - dirName: v.name, - }; - ye.source === "paperforge" ? p.push(ye) : h.push(ye); - }); - let b = r.createEl("div", { cls: "paperforge-skills-box" }), - k = (v, w, O) => { - if (w.length === 0) return; - let M = b.createEl("div", { cls: "paperforge-skills-group" }), - I = M.createEl("div", { cls: "paperforge-skills-collapse-header" }), - J = M.createEl("div", { cls: "paperforge-skills-collapse-content" }), - q = I.createEl("span", { - text: "\u25BC", - cls: "paperforge-skills-arrow", - }); - (I.createEl("h4", { - text: `${v} (${w.length})`, - cls: "paperforge-skills-subheader", - }), - w.forEach((G) => { - let ye = G.name + (G.version ? " v" + G.version : ""), - ue = O ? " [system]" : " [user]", - V = G.desc || "", - U = new z.Setting(J).setName(ye + ue).setDesc(V); - ((U.settingEl.style.opacity = G.disabled ? "0.4" : "1"), - U.addToggle((be) => { - be.setValue(!G.disabled).onChange((we) => { - let ge = !we, - fe = G.content.match(/^disable-model-invocation:\s*(.+)$/m) - ? G.content.replace( - /^disable-model-invocation:\s*.+$/m, - `disable-model-invocation: ${ge}` - ) - : G.content.replace( - /^(---\r?\n)/, - `$1disable-model-invocation: ${ge} -` - ); - (ie.writeFileSync(G.path, fe, "utf-8"), - (G.disabled = ge), - (G.content = fe), - (U.settingEl.style.opacity = G.disabled ? "0.4" : "1")); - }); - })); - })); - let te = O ? "system" : "user"; - ((this._skillsCollapsed[te] || !1) && - ((J.style.display = "none"), (q.style.transform = "rotate(-90deg)")), - I.addEventListener("click", () => { - (J.style.display !== "none" - ? ((J.style.display = "none"), - (q.style.transform = "rotate(-90deg)")) - : ((J.style.display = ""), (q.style.transform = "rotate(0deg)")), - (this._skillsCollapsed[te] = J.style.display === "none")); - })); - }; - (k("System Skills", p, !0), - k("User Skills", h, !1), - p.length === 0 && - h.length === 0 && - b.createEl("p", { - text: `No skills found in ${a[l]}. Run setup to deploy skills.`, - cls: "setting-item-description", - }), - this._advCollapsed === void 0 && (this._advCollapsed = !0)); - let g = r.createEl("div", { cls: "paperforge-collapsible-header" }), - x = g.createEl("span", { - text: "\u25B6", - cls: "paperforge-collapsible-arrow", - }); - x.style.transform = this._advCollapsed ? "rotate(0deg)" : "rotate(90deg)"; - let C = g.createEl("span", { - cls: "paperforge-collapsible-title", - text: "Advanced", - }), - R = g.createEl("span", { - cls: "paperforge-collapsible-sub", - text: "Memory + Vector DB + Embedding", - }), - S = r.createEl("div", { cls: "paperforge-collapsible-content" }); - ((S.style.display = this._advCollapsed ? "none" : ""), - g.addEventListener("click", () => { - ((this._advCollapsed = !this._advCollapsed), - (S.style.display = this._advCollapsed ? "none" : ""), - (x.style.transform = this._advCollapsed - ? "rotate(0deg)" - : "rotate(90deg)")); - }), - S.createEl("h4", { text: "Memory Layer" }), - S.createEl("div", { cls: "paperforge-desc-box" }).setText( - f("feat_memory_desc") - )); - let B = S.createEl("div", { cls: "paperforge-memory-status" }), - A = this.app.vault.adapter.basePath; - (this.plugin._lastSyncTime && - !this._lastSyncTime && - (this._lastSyncTime = this.plugin._lastSyncTime), - this._memoryStatusText === null && (this._memoryStatusText = Gt(A)), - this._renderMemoryStatusText( - B, - this._memoryStatusText, - this._lastSyncTime - ), - this._renderVectorSection(S)); - } - _renderVectorSection(r) { - var p; - if ( - (r.createEl("h4", { text: "Vector Database" }), - this.plugin.settings.features || - (this.plugin.settings.features = { memory_layer: !0, vector_db: !1 }), - r - .createEl("div", { cls: "paperforge-desc-box" }) - .setText(f("feat_vector_desc")), - new z.Setting(r) - .setName(f("feat_vector_enable")) - .setDesc(f("feat_vector_enable_desc")) - .addToggle((h) => { - h.setValue(!!this.plugin.settings.features.vector_db).onChange( - (b) => { - ((this.plugin.settings.features.vector_db = b), - this.plugin.saveSettings(), - (this._vectorDepsOk = null), - (this._embedStatusText = null), - this.display()); - } - ); - }), - !this.plugin.settings.features.vector_db) - ) - return; - let i = this.app.vault.adapter.basePath, - a = r.createEl("div", { cls: "paperforge-vec-header" }), - c = a.createEl("span", { - text: "\u25BC", - cls: "paperforge-skills-arrow", - }); - a.createEl("span", { - cls: "paperforge-vec-header-label", - text: f("feat_vector_config_label"), - }); - let l = r.createEl("div", { cls: "paperforge-vector-config" }), - u = (h) => { - ((l.style.display = h ? "none" : ""), - (c.style.transform = h ? "rotate(-90deg)" : "rotate(0deg)")); - }; - if ( - (u(Dr(this._featurePanelsCollapsed, "vectorConfig", !1)), - a.addEventListener("click", () => { - let h = Bn(this._featurePanelsCollapsed, "vectorConfig", !1); - u(h); - }), - this._vectorDepsOk === !0) - ) { - this._renderVectorReady(l, i); - return; - } - if (this._vectorDepsOk === !1) { - this._renderVectorNoDeps(l); - return; - } - if (this._vectorDepsOk === null) { - let h = Rt(i); - ((this._vectorDepsOk = h && (p = h.deps_installed) != null ? p : !1), - this._vectorDepsOk && (this._embedStatusText = gt(i)), - this.display()); - } - } - _renderApiConfig(r) { - (new z.Setting(r) - .setName(f("feat_openai_key")) - .setDesc(f("feat_openai_key_desc")) - .addText((n) => { - n.setPlaceholder("sk-...") - .setValue(this.plugin.settings.vector_db_api_key || "") - .onChange((i) => { - ((this.plugin.settings.vector_db_api_key = i), - this.plugin.saveSettings()); - }); - }), - new z.Setting(r) - .setName(f("feat_api_base_url")) - .setDesc(f("feat_api_base_url_desc")) - .addText((n) => { - n.setPlaceholder("https://api.openai.com/v1") - .setValue(this.plugin.settings.vector_db_api_base || "") - .onChange((i) => { - ((this.plugin.settings.vector_db_api_base = i), - this.plugin.saveSettings()); - }); - }), - new z.Setting(r) - .setName(f("feat_api_model")) - .setDesc(f("feat_api_model_desc")) - .addText((n) => { - n.setPlaceholder("text-embedding-3-small") - .setValue( - this.plugin.settings.vector_db_api_model || - "text-embedding-3-small" - ) - .onChange((i) => { - ((this.plugin.settings.vector_db_api_model = i), - this.plugin.saveSettings()); - }); - })); - } - _renderVectorNoDeps(r) { - (r - .createEl("div", { cls: "paperforge-desc-box" }) - .setText(f("feat_deps_missing")), - new z.Setting(r) - .setName(f("feat_install_deps")) - .setDesc(f("feat_install_deps_desc")) - .addButton((i) => { - i.setButtonText(f("feat_install_btn")) - .setCta() - .onClick(async () => { - let a = this.app.vault.adapter.basePath, - c = Ue(a, this.plugin.settings); - if (!c.path) { - new z.Notice(f("feat_no_python")); - return; - } - (i.setButtonText(f("feat_installing")), i.setDisabled(!0)); - let l = "chromadb openai", - u = new z.Notice( - f("feat_installing_pkgs").replace("{pkgs}", l), - 0 - ); - try { - let p = Object.assign({}, process.env, { - PYTHONIOENCODING: "utf-8", - PYTHONUTF8: "1", - }), - h = l.split(" "); - (await new Promise((b, k) => { - (0, oe.execFile)( - c.path, - [...c.extraArgs, "-m", "pip", "install", ...h], - { cwd: a, timeout: 3e5, env: p, windowsHide: !0 }, - (g) => { - g ? k(g) : b(); - } - ); - }), - u.hide(), - new z.Notice(f("feat_install_done")), - (this._vectorDepsOk = !0), - (this._embedStatusText = gt(a)), - this.display()); - } catch (p) { - (u.hide(), - new z.Notice( - f("feat_install_failed") + (p.stderr || p.message || p) - ), - i.setButtonText(f("feat_retry_btn")), - i.setDisabled(!1)); - } - }); - })); - } - _renderVectorReady(r, n) { - (r.createEl("div", { cls: "paperforge-desc-box" }).setText(gt(n)), - this._renderApiConfig(r)); - let a = r.createEl("div", { cls: "paperforge-embed-section" }); - a.createEl("div", { cls: "paperforge-embed-header" }).createEl("span", { - text: f("feat_rebuild_vectors"), - cls: "setting-item-name", - }); - let l = a.createEl("div", { cls: "paperforge-embed-controls" }), - u = a.createEl("div", { cls: "paperforge-embed-status-text" }); - (() => { - var C, R, S; - (l.empty(), u.empty()); - let h = (Rt(n) || {}).build_state || {}; - ((this.plugin._embedProgress = this.plugin._embedProgress || { - current: 0, - total: 0, - key: "", - }), - !this.plugin._embedProcess && - h.status === "running" && - (this.plugin._embedProgress = { - current: h.current || 0, - total: h.total || 1, - key: h.paper_id || "", - })); - let { current: b, total: k, key: g } = this.plugin._embedProgress; - if (!!this.plugin._embedProcess || h.status === "running") { - let F = l.createEl("div", { cls: "paperforge-progress-track" }); - F.style.cssText = "flex:1;"; - let B = k > 0 ? ((b / k) * 100).toFixed(1) : "0", - A = F.createEl("div", { cls: "paperforge-progress-seg done" }); - if ( - ((A.style.cssText = `width:${B}%; min-width:${b > 0 ? "2px" : "0"};`), - b < k) - ) { - let w = F.createEl("div", { cls: "paperforge-progress-seg pending" }); - w.style.cssText = `width:${(100 - parseFloat(B)).toFixed(1)}%;`; - } - (u.createEl("span", { - cls: "paperforge-embed-progress-text", - text: `${b}/${k} papers`, - }), - g && - u.createEl("span", { - cls: "paperforge-embed-progress-key", - text: ` (${g})`, - })); - let v = l.createEl("button"); - (v.setText("Stop"), - (v.className = "mod-warning"), - v.addEventListener("click", () => { - (this._callPython(["embed", "stop", "--json"], { timeout: 8e3 }), - this.plugin._embedProcess && - (this.plugin._embedProcess.kill(), - (this.plugin._embedProcess = null)), - this.display()); - })); - } else { - let F = Rt(n), - B = - ((C = F == null ? void 0 : F.chunk_count) != null ? C : 0) + - ((R = F == null ? void 0 : F.body_chunk_count) != null ? R : 0) + - ((S = F == null ? void 0 : F.object_chunk_count) != null ? S : 0), - A = B > 0, - v = F ? !!F.corrupted : !1, - w = (M) => { - if (!Ue(n, this.plugin.settings).path) { - new z.Notice(f("feat_no_python")); - return; - } - let J = Object.assign({}, process.env, { - PYTHONIOENCODING: "utf-8", - PYTHONUTF8: "1", - VECTOR_DB_API_KEY: this.plugin.settings.vector_db_api_key || "", - VECTOR_DB_API_BASE: this.plugin.settings.vector_db_api_base || "", - VECTOR_DB_API_MODEL: - this.plugin.settings.vector_db_api_model || "", - }); - ((this.plugin._embedStderr = ""), - (this.plugin._embedProgress = { current: 0, total: 0, key: "" }), - (this.plugin._embedProcess = this._callPython( - ["embed", "build", M], - { - stream: !0, - env: J, - onData: (q) => { - let te = q.toString("utf-8").split(` -`); - for (let se of te) - if (se.startsWith("EMBED_START:")) - this.plugin._embedProgress.total = - parseInt(se.split(":")[1]) || 0; - else if (se.startsWith("EMBED_PROGRESS:")) { - let G = se.split(":"); - ((this.plugin._embedProgress.current = - parseInt(G[1]) || 0), - (this.plugin._embedProgress.key = G[3] || "")); - } else - se.startsWith("EMBED_DONE") && - ((this.plugin._embedProcess = null), - (this.plugin._embedProgress.current = - this.plugin._embedProgress.total)); - this.display(); - }, - onStderr: (q) => { - (this.plugin._embedStderr || - (this.plugin._embedStderr = ""), - (this.plugin._embedStderr += q.toString("utf-8"))); - }, - onError: (q) => { - ((this.plugin._embedProcess = null), - new z.Notice( - f("feat_build_failed") + ": " + (q.message || q) - ), - this.display()); - }, - onClose: (q) => { - if (((this.plugin._embedProcess = null), q === 0)) - ((this.plugin._embedProgress.current = - this.plugin._embedProgress.total), - this.plugin.saveSettings(), - (this._embedStatusText = gt(n)), - new z.Notice(f("feat_build_complete"))); - else { - this._embedStatusText = null; - let te = (this.plugin._embedStderr || "").slice(0, 200); - new z.Notice( - f("feat_build_failed") + (te ? ": " + te : ""), - 8e3 - ); - } - ((this.plugin._embedStderr = ""), - this.display(), - this._refreshSnapshots(n)); - }, - } - )), - this.display()); - }; - if (v) { - let M = a.createEl("div"); - ((M.style.cssText = - "padding:8px 12px; margin:8px 0; background:var(--background-modifier-warning); border-radius:4px; font-size:12px; display:flex; align-items:center; justify-content:space-between;"), - M.createEl("span", { text: f("feat_vector_corrupted") })); - let I = M.createEl("button", { - text: f("feat_vector_rebuild_force_btn"), - }); - ((I.className = "mod-cta"), - I.addEventListener("click", () => w("--force"))); - } - A && - !v && - l.createEl("span", { - text: B + " chunks embedded", - cls: "setting-item-description", - }); - let O = l.createEl("button"); - if ( - (O.setText(A ? f("feat_rebuild_btn") : f("feat_build_btn")), - O.addClass("mod-cta"), - O.addEventListener("click", () => w("--resume")), - !v && A) - ) { - let M = l.createEl("button"); - (M.setText(f("feat_vector_rebuild_force_btn")), - (M.style.marginLeft = "6px"), - M.addEventListener("click", () => w("--force"))); - } - } - })(); - } - _getCurrentModelKey() { - return this.plugin.settings.vector_db_api_model || "text-embedding-3-small"; - } - _parseEmbedStatus(r) { - let n = {}; - return ( - r && - (r - .split( - ` -` - ) - .forEach((i) => { - let a = i.match(/^\s*([^:]+):\s*(.*)/); - a && (n[a[1].trim()] = a[2].trim()); - }), - n.db_exists !== void 0 && (n.db_exists = n.db_exists === "True"), - n.chunk_count !== void 0 && - (n.chunk_count = parseInt(n.chunk_count, 10) || 0)), - n - ); - } - _getPythonDesc(r, n) { - return n === "stale" - ? `[!!] ${r} (stale \u2014 path no longer exists, update or clear the override below)` - : n === "manual" - ? `${r} (manual)` - : `${r} (auto-detected)`; - } - _refreshPythonInterpDesc(r, n) { - let i = this._pythonInterpDescEl; - i && - (n === "stale" - ? (i.textContent = `[!!] ${r} (stale \u2014 path no longer exists, update or clear the override below)`) - : n === "manual" - ? (i.textContent = `${r} (manual)`) - : (i.textContent = `${r} (auto-detected)`)); - } - _validatePythonOverride() { - let r = this.plugin.settings.python_path - ? this.plugin.settings.python_path.trim() - : "", - n = this._customPathDescEl; - if (!r) { - let i = "\u8BF7\u8F93\u5165\u8DEF\u5F84 / Enter a path first"; - (n && - (n.innerHTML = `\u2717 ${i}`), - new z.Notice(i)); - return; - } - if (!ie.existsSync(r)) { - let i = "\u8DEF\u5F84\u4E0D\u5B58\u5728 / Path does not exist"; - (n && - (n.innerHTML = `\u2717 ${i}`), - new z.Notice(i, 4e3)); - return; - } - try { - ie.accessSync(r, ie.constants.X_OK); - } catch (i) { - let a = "\u4E0D\u53EF\u6267\u884C / Not executable"; - (n && - (n.innerHTML = `\u2717 ${a}`), - new z.Notice(a, 4e3)); - return; - } - (0, oe.execFile)(r, ["--version"], { timeout: 8e3 }, (i, a) => { - if (i || !a) { - let p = "\u65E0\u6CD5\u8FD0\u884C / Cannot run"; - (n && - (n.innerHTML = `\u2717 ${p}`), - new z.Notice(p, 4e3)); - return; - } - let c = a.match(/Python (\d+)\.(\d+)/); - if (!c) { - let p = "\u65E0\u6CD5\u89E3\u6790\u7248\u672C / Cannot parse version"; - (n && - (n.innerHTML = `\u2717 ${p}`), - new z.Notice(p, 4e3)); - return; - } - let l = parseInt(c[1], 10), - u = parseInt(c[2], 10); - if (l < 3 || (l === 3 && u < 10)) { - let p = - "Python \u7248\u672C\u8FC7\u4F4E\uFF0C\u9700\u8981 3.10+ / Python version too low, need 3.10+"; - (n && - (n.innerHTML = `\u2717 ${p}`), - new z.Notice(p, 4e3)); - return; - } - (0, oe.execFile)(r, ["-m", "pip", "--version"], { timeout: 8e3 }, (p) => { - if (p) { - let h = `\u2713 Python ${l}.${u} \u6709\u6548\uFF0C\u4F46\u672A\u68C0\u6D4B\u5230 pip / Valid, but pip not found`; - (n && - (n.innerHTML = `\u26A0 ${h}`), - new z.Notice(h, 4e3)); - } else { - let h = `\u2713 Python ${l}.${u} \u6709\u6548 / Valid`; - (n && - (n.innerHTML = `${h}`), - new z.Notice(h, 4e3)); - } - }); - }); - } - _syncRuntime(r) { - let n = this.app.vault.adapter.basePath, - { path: i, extraArgs: a = [] } = re( - n, - this.plugin.settings, - void 0, - void 0 - ), - c = this.plugin.manifest.version, - l = Fn(i, c, a); - (r.setDisabled(!0), r.setButtonText(f("runtime_health_syncing"))); - let u = (h, b) => ( - console.log(`[PaperForge] Sync Runtime: trying ${b}`), - Rn(l.cmd, h, n, l.timeout, void 0, ot()) - ), - p = () => { - let h = "opencode"; - try { - let x = ie.readFileSync(me.join(n, "paperforge.json"), "utf-8"), - C = JSON.parse(x); - C.agent_key && (h = C.agent_key); - } catch (x) {} - let b = [ - ...a, - "-c", - 'from paperforge.services.skill_deploy import deploy_skills; from pathlib import Path; r=deploy_skills(vault=Path(r"' + - n.replace(/\\/g, "\\\\") + - '"), agent_key="' + - h + - '", overwrite=True); print("skills deployed" if r["skill_deployed"] else "skills skipped", flush=True)', - ], - k = (0, oe.spawn)(i, b, { cwd: n, timeout: 3e4, windowsHide: !0 }), - g = ""; - (k.stdout.on("data", (x) => { - g += x.toString("utf-8"); - }), - k.on("close", (x) => { - console.log(`[PaperForge] Skill deploy: ${g.trim()} (exit ${x})`); - })); - }; - u(l.pypiArgs, "PyPI").then((h) => { - if (h.exitCode === 0) { - (console.log("[PaperForge] Sync Runtime: installed via PyPI"), - p(), - new z.Notice(f("runtime_health_sync_done").replace("{0}", c), 5e3), - this.display()); - return; - } - (console.warn( - "[PaperForge] Sync Runtime: PyPI failed, falling back to git..." - ), - u(l.gitArgs, "git").then((b) => { - b.exitCode === 0 - ? (console.log("[PaperForge] Sync Runtime: installed via git"), - p(), - new z.Notice( - f("runtime_health_sync_done").replace("{0}", c), - 5e3 - ), - this.display()) - : (r.setDisabled(!1), - r.setButtonText(f("runtime_health_sync")), - console.error("[PaperForge] git fallback stderr:", b.stderr), - new z.Notice( - f("runtime_health_sync_fail").replace( - "{0}", - "pip exit code " + b.exitCode - ), - 8e3 - )); - })); - }); - } - _debouncedSave() { - (clearTimeout(this._saveTimeout), - (this._saveTimeout = setTimeout(() => this.plugin.saveSettings(), 500))); - } - _preCheck(r) { - var c; - let n = this.app.vault.adapter.basePath, - { path: i, extraArgs: a = [] } = re( - n, - (c = this.plugin) == null ? void 0 : c.settings, - void 0, - void 0 - ); - (0, oe.execFile)(i, [...a, "--version"], { timeout: 8e3 }, (l, u) => { - let p = []; - p.push({ - label: "Python", - ok: !l, - detail: l ? f("check_python_fail") : u.trim(), - }); - let h = !1, - b = process.env.HOME || process.env.USERPROFILE || Vn.homedir() || ""; - if (process.platform === "darwin") - h = [ - "/Applications/Zotero.app", - me.join(b, "Applications", "Zotero.app"), - ].some((F) => { - try { - return ie.existsSync(F); - } catch (B) { - return !1; - } - }); - else if (process.platform === "win32") { - let S = process.env.ProgramFiles || "", - F = process.env.LOCALAPPDATA || ""; - h = [ - me.join(S, "Zotero"), - me.join(S, "(x86)", "Zotero"), - me.join(F, "Programs", "Zotero"), - me.join(F, "Zotero"), - me.join(b, "AppData", "Local", "Programs", "Zotero"), - ] - .filter(Boolean) - .some((A) => { - try { - return ie.existsSync(A); - } catch (v) { - return !1; - } - }); - } else - h = [ - me.join(b, ".local", "share", "zotero", "zotero"), - "/usr/bin/zotero", - "/usr/local/bin/zotero", - ].some((F) => { - try { - return ie.existsSync(F); - } catch (B) { - return !1; - } - }); - let k = this.plugin.settings.zotero_data_dir; - if (!h && k) - try { - h = ie.existsSync(k); - } catch (S) {} - p.push({ - label: "Zotero", - ok: h, - detail: h ? f("check_zotero_ok") : f("check_zotero_fail"), - }); - let g = !1, - x = process.env.APPDATA || ""; - (process.platform === "win32" && - x && - (g = Jt(me.join(x, "Zotero", "Zotero", "Profiles"))), - !g && - process.platform === "darwin" && - b && - (g = Jt( - me.join(b, "Library", "Application Support", "Zotero", "Profiles") - )), - !g && - process.platform !== "win32" && - process.platform !== "darwin" && - b && - (g = Jt(me.join(b, ".zotero", "zotero", "Profiles"))), - !g && k && String(k).trim() && (g = Fr(k.trim())), - !g && b && (g = Fr(me.join(b, "Zotero"))), - p.push({ - label: "Better BibTeX", - ok: g, - detail: g ? f("check_bbt_ok") : f("check_bbt_fail"), - })); - let C = { true: "\u2713", false: "\u2717" }; - if (this._checkEl) { - this._checkEl.setText( - p.map((F) => `${C[String(F.ok)]} ${F.label}: ${F.detail}`).join(` -`) - ); - let S = p.some((F) => !F.ok); - this._checkEl.className = `paperforge-message msg-${S ? "error" : "ok"}`; - } - let R = p.filter((S) => !S.ok); - (R.length > 0 && - new z.Notice( - `[!!] \u672A\u901A\u8FC7: ${R.map((S) => S.label).join(", ")}`, - 6e3 - ), - r()); - }); - } - _renderMaintenanceTab(r) { - r.createEl("h2", { text: f("tab_maintenance") || "\u7EF4\u62A4" }); - let n = this.app.vault.adapter.basePath, - i = r.createEl("div"), - a = (k, g) => - g === "retry_ocr" || g === "upgrade_legacy" - ? { cmd: ["-m", "paperforge", "ocr", "redo", ...k], timeout: 3e5 } - : g === "rebuild_result" - ? { - cmd: ["-m", "paperforge", "ocr", "rebuild", ...k], - timeout: 12e4, - } - : null, - c = null; - try { - c = zn(n); - } catch (k) {} - let l = re(n, this.plugin.settings, ie, oe.execFileSync); - if (!l.path) { - i.createEl("p", { - text: "\u26A0 Python \u672A\u914D\u7F6E\uFF0C\u8BF7\u5148\u5728\u300C\u5B89\u88C5\u300D\u6807\u7B7E\u9875\u914D\u7F6E\u3002", - cls: "setting-item-description", - }); - return; - } - let u = (k) => { - i.empty(); - let g = k.filter((S) => S.visible_in_maintenance); - if (g.length === 0) { - i.createEl("p", { - text: f("maintenance_all_good") || "\u2705 \u5168\u90E8\u6B63\u5E38", - }); - return; - } - let x = l.path, - C = l.extraArgs || [], - R = [ - { - key: "retry", - title: f("maintenance_group_retry") || "\u9700\u8981\u91CD\u8BD5", - items: [], - }, - { - key: "rebuild", - title: - f("maintenance_group_rebuild") || - "\u53EF\u91CD\u5EFA\u7ED3\u679C", - items: [], - }, - { - key: "legacy_optional", - title: - f("maintenance_group_legacy") || - "\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09", - items: [], - }, - ]; - for (let S of g) { - let F = R.find((B) => B.key === S.display_group); - F && F.items.push(S); - } - for (let S of R) { - if (S.items.length === 0) continue; - let F = S.key === "legacy_optional", - B = F ? i.createEl("details") : i.createEl("div"); - F - ? B.createEl("summary").createEl("strong", { - text: S.title + " (" + S.items.length + ")", - }) - : B.createEl("h3", { text: S.title + " (" + S.items.length + ")" }); - let A = new Map(); - for (let V of S.items) A.set(V.key, !1); - let v = B.createEl("div", { cls: "pf-maint-toolbar" }), - w = v.createEl("button", { text: "\u5168\u9009" }), - O = v.createEl("button", { text: "\u53D6\u6D88\u5168\u9009" }), - M = v.createEl("button", { - text: "\u25B6 \u6267\u884C\u5DF2\u9009", - cls: "mod-cta", - }), - I = v.createEl("span", { cls: "pf-maint-exec-label" }), - J = () => { - let V = S.items.filter((U) => A.get(U.key)).length; - I.setText("\u5DF2\u9009 " + V + " \u7BC7"); - }; - (J(), - w.addEventListener("click", () => { - for (let U of S.items) A.set(U.key, !0); - (J(), - B.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach( - (U) => { - U.checked = !0; - } - )); - }), - O.addEventListener("click", () => { - for (let U of S.items) A.set(U.key, !1); - (J(), - B.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach( - (U) => { - U.checked = !1; - } - )); - }), - M.addEventListener("click", () => { - let V = S.items.filter((U) => A.get(U.key)); - if (V.length === 0) { - new z.Notice( - "\u8BF7\u5148\u9009\u62E9\u8981\u5904\u7406\u7684\u8BBA\u6587\u3002" - ); - return; - } - for (let U of V) { - let be = a([U.key], U.display_action); - be && - (0, oe.execFile)( - x, - [...C, ...be.cmd], - { cwd: n, timeout: be.timeout, windowsHide: !0 }, - () => { - new z.Notice(U.display_label + " \u2014 " + U.key); - } - ); - } - })); - let te = B.createEl("div", { cls: "pf-maint-table-wrap" }).createEl( - "table", - { cls: "pf-maint-table" } - ), - se = te.createEl("thead"), - G = te.createEl("tbody"), - ye = se.insertRow(); - [ - "", - "Key", - "Title", - "\u5EFA\u8BAE\u64CD\u4F5C", - "\u539F\u56E0", - "\u64CD\u4F5C", - ].forEach((V) => { - let U = document.createElement("th"); - ((U.textContent = V), ye.appendChild(U)); - }); - let ue = (V) => - V === "retry_ocr" - ? f("maintenance_btn_retry") || "\u91CD\u8BD5" - : V === "rebuild_result" - ? f("maintenance_btn_rebuild") || "\u91CD\u5EFA" - : V === "upgrade_legacy" - ? f("maintenance_btn_upgrade") || "\u5347\u7EA7" - : ""; - for (let V of S.items) { - let U = G.insertRow(), - be = U.insertCell(); - be.style.cssText = "padding:3px 4px;text-align:center;"; - let we = document.createElement("input"); - ((we.type = "checkbox"), - (we.className = "pf-maint-sel"), - (we.checked = A.get(V.key) || !1), - we.addEventListener("change", () => { - (A.set(V.key, we.checked), J()); - }), - be.appendChild(we)); - let ge = U.insertCell(); - ((ge.style.cssText = - "padding:3px 4px;white-space:nowrap;font-size:11px;max-width:90px;overflow:hidden;text-overflow:ellipsis;"), - (ge.textContent = V.key)); - let Ce = U.insertCell(); - ((Ce.style.cssText = - "padding:3px 4px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis;"), - (Ce.textContent = V.title || V.key)); - let fe = U.insertCell(); - ((fe.style.cssText = "padding:3px 4px;white-space:nowrap;"), - (fe.textContent = V.display_label)); - let Le = U.insertCell(); - ((Le.style.cssText = - "padding:3px 4px;white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis;font-size:11px;color:var(--text-muted);"), - (Le.textContent = V.display_reason || "")); - let De = U.insertCell(); - De.style.cssText = - "padding:3px 4px;text-align:center;white-space:nowrap;"; - let Ie = document.createElement("button"); - ((Ie.textContent = ue(V.display_action)), - Ie.textContent && - (Ie.addEventListener("click", () => { - let K = a([V.key], V.display_action); - K && - (0, oe.execFile)( - x, - [...C, ...K.cmd], - { cwd: n, timeout: K.timeout, windowsHide: !0 }, - () => { - new z.Notice(V.display_label + " \u2014 " + V.key); - } - ); - }), - De.appendChild(Ie))); - } - } - }; - if (c) { - let k = Object.values(c.papers); - u(k); - } else - i.createEl("p", { - text: "\u6B63\u5728\u52A0\u8F7D OCR \u7EF4\u62A4\u6570\u636E\u2026", - }); - ($n(n, l.path, l.extraArgs || [], c || null) - .then((k) => { - k.changed - ? (u(k.data), - Yt(n, { - manifest: {}, - papers: Object.fromEntries(k.data.map((g) => [g.key, g])), - cached_at: new Date().toISOString(), - })) - : c || - (u(k.data), - Yt(n, { - manifest: {}, - papers: Object.fromEntries(k.data.map((g) => [g.key, g])), - cached_at: new Date().toISOString(), - })); - }) - .catch(() => { - c || - (i.empty(), - i.createEl("p", { - text: "\u65E0\u6CD5\u52A0\u8F7D OCR \u6570\u636E\u3002\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 paperforge \u5E76\u8FD0\u884C\u8FC7 OCR\u3002", - cls: "setting-item-description", - })); - }), - r.createEl("hr"), - r.createEl("h3", { text: "\u5168\u5C40\u64CD\u4F5C" })); - let p = r.createEl("div", { cls: "pf-maint-global" }); - (p - .createEl("button", { text: "\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15" }) - .addEventListener("click", () => { - (new z.Notice("\u6B63\u5728\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15\u2026"), - (0, oe.execFile)( - l.path, - [ - ...(l.extraArgs || []), - "-m", - "paperforge", - "embed", - "build", - "--force", - ], - { cwd: n, timeout: 3e5, windowsHide: !0 }, - () => { - new z.Notice( - "\u641C\u7D22\u7D22\u5F15\u91CD\u5EFA\u5B8C\u6210\u3002" - ); - } - )); - }), - p - .createEl("button", { text: "\u91CD\u5EFA\u8BB0\u5FC6\u5E93" }) - .addEventListener("click", () => { - (new z.Notice("\u6B63\u5728\u91CD\u5EFA\u8BB0\u5FC6\u5E93\u2026"), - (0, oe.execFile)( - l.path, - [...(l.extraArgs || []), "-m", "paperforge", "repair", "--fix"], - { cwd: n, timeout: 12e4, windowsHide: !0 }, - () => { - new z.Notice( - "\u8BB0\u5FC6\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002" - ); - } - )); - })); - } - _renderReleaseNotesTab(r) { - (r.createEl("h2", { text: "\u66F4\u65B0\u4E0E\u624B\u518C" }), - r.createEl("h3", { text: "\u7248\u672C\u66F4\u65B0\u8BB0\u5F55" })); - let n = qn.default.versions || []; - for (let c of n) { - let l = r.createEl("div", { cls: "paperforge-release-card" }), - u = l.createEl("div", { cls: "paperforge-release-header" }); - if ( - (u.createEl("strong", { text: `v${c.version} \u2014 ${c.title}` }), - u.createEl("span", { - cls: "paperforge-release-date", - text: ` (${c.date})`, - }), - c.breaking_or_migration && c.breaking_or_migration.length > 0) - ) { - let p = l.createEl("div", { cls: "paperforge-release-section" }); - p.createEl("div", { - cls: "paperforge-release-label", - text: "\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F", - }); - for (let h of c.breaking_or_migration) - p.createEl("div", { - cls: "paperforge-release-item", - text: `\u2022 ${h}`, - }); - } - if (c.new_features && c.new_features.length > 0) { - let p = l.createEl("div", { cls: "paperforge-release-section" }); - p.createEl("div", { - cls: "paperforge-release-label", - text: "\u65B0\u529F\u80FD", - }); - for (let h of c.new_features) - p.createEl("div", { - cls: "paperforge-release-item", - text: `\u2022 ${h}`, - }); - } - if (c.fixes && c.fixes.length > 0) { - let p = l.createEl("div", { cls: "paperforge-release-section" }); - p.createEl("div", { - cls: "paperforge-release-label", - text: "\u4FEE\u590D", - }); - for (let h of c.fixes) - p.createEl("div", { - cls: "paperforge-release-item", - text: `\u2022 ${h}`, - }); - } - if (c.recommended_actions && c.recommended_actions.length > 0) { - let p = l.createEl("div", { - cls: "paperforge-release-section paperforge-release-recommended", - }); - p.createEl("div", { - cls: "paperforge-release-label", - text: "\u5EFA\u8BAE\u64CD\u4F5C", - }); - for (let h of c.recommended_actions) - p.createEl("div", { - cls: "paperforge-release-item paperforge-release-item-bold", - text: `\u2022 ${h}`, - }); - } - } - (r.createEl("h3", { text: "\u4F7F\u7528\u624B\u518C" }), - r - .createEl("div", { cls: "paperforge-manual-links" }) - .createEl("a", { - text: "\u2192 \u67E5\u770B\u5B8C\u6574\u4F7F\u7528\u624B\u518C\uFF08GitHub\uFF09", - href: "https://github.com/LLLin000/PaperForge/blob/master/docs/user-manual.md", - }) - .setAttr("target", "_blank")); - } -}; -var X = require("obsidian"), - We = ae(require("fs")), - Mt = ae(require("path")), - et = require("child_process"); -var At = ae(require("path")); -function Hn(_) { - if (!_) return null; - let y = At.dirname(_); - for (;;) { - let r = At.basename(y); - if (!r || r === ".") break; - let n = r.match(/^([A-Z0-9]{8})(?:\s*-\s*.*)?$/i); - if (n) return n[1]; - let i = At.dirname(y); - if (i === y) break; - y = i; - } - return null; -} -var pe = ae(require("fs")), - Ye = ae(require("path")); -function Bt(_) { - return Te(_).ocrDir; -} -function Ys(_, y) { - let r = Ye.join(Bt(_), y, "versions", "manifest.json"); - try { - if (!pe.existsSync(r)) return null; - let n = pe.readFileSync(r, "utf-8"), - i = JSON.parse(n); - if (i && typeof i == "object" && "versions" in i && "current" in i) { - let a = i, - c = a.versions, - l = a.current; - if (Array.isArray(c) && l && typeof l == "object" && "label" in l) - return i; - } - return null; - } catch (n) { - return null; - } -} -function ea(_) { - let y = Bt(_); - try { - return pe.existsSync(y) - ? pe - .readdirSync(y, { withFileTypes: !0 }) - .filter((r) => r.isDirectory()) - .map((r) => r.name) - : []; - } catch (r) { - return []; - } -} -function Br(_) { - let y = ea(_), - r = []; - for (let n of y) { - let i = Ys(_, n); - if (!i) continue; - let a = i.versions.map((l) => l.label), - c = 0; - for (let l of a) { - let u = Ye.join(Bt(_), n, "versions", l, "fulltext.md"); - try { - pe.existsSync(u) && (c += pe.statSync(u).size); - } catch (p) {} - } - r.push({ - key: n, - title: n.replace(/_/g, " "), - versions: i.versions, - currentLabel: i.current.label, - totalSize: c, - }); - } - return (r.sort((n, i) => n.title.localeCompare(i.title)), r); -} -function Un(_, y, r) { - let n = Bt(_), - i = Ye.join(n, y, "versions", r, "fulltext.md"), - a = Ye.join(n, y, "render"), - c = Ye.join(a, "fulltext.md"); - try { - return pe.existsSync(i) - ? (pe.existsSync(a) || pe.mkdirSync(a, { recursive: !0 }), - pe.copyFileSync(i, c), - !0) - : !1; - } catch (l) { - return !1; - } -} -function Wn(_, y, r, n) { - var g; - let i = Bt(_), - a = Ye.join(i, y, "versions", r, "fulltext.md"), - c = Ye.join(i, y, "versions", n, "fulltext.md"), - l = "", - u = ""; - try { - pe.existsSync(a) && (l = pe.readFileSync(a, "utf-8")); - } catch (x) {} - try { - pe.existsSync(c) && (u = pe.readFileSync(c, "utf-8")); - } catch (x) {} - let p = Kn(l), - h = Kn(u), - b = Math.max(p.length, h.length), - k = []; - for (let x = 0; x < b; x++) { - let C = x < p.length ? p[x] : "", - R = x < h.length ? h[x] : "", - S = - (g = (C || R).split(` -`)[0]) != null - ? g - : "", - F = S.startsWith("## ") ? S.replace(/^##\s+/, "") : "", - B = "unchanged"; - (!C && R - ? (B = "added") - : C && !R - ? (B = "removed") - : C !== R && (B = "changed"), - B !== "unchanged" && - k.push({ - paragraphIndex: x, - heading: F, - type: B, - oldText: C || void 0, - newText: R || void 0, - })); - } - return k; -} -function Kn(_) { - let y = _.split(` -`), - r = [], - n = []; - for (let i of y) - if (i.startsWith("## ") && n.length > 0) - (r.push( - n - .join( - ` -` - ) - .trim() - ), - (n = [i])); - else if (i.trim() === "" && n.length > 0) { - let a = n - .join( - ` -` - ) - .trim(); - a && (r.push(a), (n = [])); - } else n.push(i); - if (n.length > 0) { - let i = n - .join( - ` -` - ) - .trim(); - i && r.push(i); - } - return r; -} -var sr = ae(require("fs")), - Or = ae(require("path")), - Jn = ae(Zn()), - Mr = null, - mt = null; -function ta(_) { - if (((_ = _.trim()), !_)) return ""; - if (_.startsWith('"') && _.endsWith('"')) return _; - let y = _.split(/\s+/).filter(Boolean); - return y.length === 0 ? "" : y.join(" AND "); -} -function ct(_) { - return _ == null - ? "" - : typeof _ == "string" - ? _ - : _ instanceof Uint8Array - ? new TextDecoder().decode(_) - : String(_); -} -function ra(_) { - return _ == null ? 0 : typeof _ == "number" ? _ : Number(_); -} -async function Gn(_) { - let y = Or.join(_, "System", "PaperForge", "indexes", "paperforge.db"); - if (!sr.existsSync(y)) - throw new Error(`PaperForge database not found at ${y}`); - let r = await (0, Jn.default)({ locateFile: (i) => Or.join(__dirname, i) }), - n = sr.readFileSync(y); - ((Mr = new r.Database(new Uint8Array(n))), - (mt = - Mr.prepare(`SELECT zotero_key, title, first_author, year, journal, domain, abstract, rank - FROM paper_fts - WHERE paper_fts MATCH ? - ORDER BY rank - LIMIT ?`))); -} -function Qn(_, y = 20) { - if (!Mr || !mt) return null; - let r = ta(_); - if (!r) return []; - mt.bind([r, y]); - let n = []; - for (; mt.step(); ) { - let i = mt.getAsObject(); - n.push({ - zotero_key: ct(i.zotero_key), - title: ct(i.title), - first_author: ct(i.first_author), - year: ct(i.year), - journal: ct(i.journal), - domain: ct(i.domain), - abstract: ct(i.abstract), - rank: ra(i.rank), - }); - } - return (mt.reset(), n); -} -var yt = class extends X.ItemView { - constructor(r) { - super(r); - this._currentMode = null; - this._currentDomain = null; - this._currentPaperKey = null; - this._currentPaperEntry = null; - this._currentFilePath = null; - this._cachedItems = null; - this._modeSubscribers = []; - this._leafChangeTimer = null; - this._ocrPrivacyShown = !1; - this._cachedStats = null; - this._techDetailsExpanded = !1; - this._paperforgeVersion = ""; - this._dashboardPermissions = {}; - this._headerTitle = null; - this._versionBadge = null; - this._messageEl = null; - this._metricsEl = null; - this._ocrSection = null; - this._ocrEmpty = null; - this._ocrBadge = null; - this._ocrTrack = null; - this._ocrCounts = null; - this._driftBannerEl = null; - this._versionPapers = null; - this._versionFilter = ""; - this._searchContainer = null; - this._searchInput = null; - this._searchResultsEl = null; - this._searchTimer = void 0; - this._sqlJsInitialized = !1; - this._sqlJsFailed = !1; - ((this._currentMode = null), - (this._currentDomain = null), - (this._currentPaperKey = null), - (this._currentPaperEntry = null), - (this._currentFilePath = null), - (this._cachedItems = null), - (this._modeSubscribers = []), - (this._leafChangeTimer = null), - (this._ocrPrivacyShown = !1)); - } - getViewType() { - return it; - } - getDisplayText() { - return "PaperForge"; - } - getIcon() { - return Ct; - } - async onOpen() { - (this._buildPanel(), - (this._modeSubscribers = []), - (this._leafChangeTimer = null), - this._setupEventSubscriptions(), - this._fetchVersion(), - this._detectAndSwitch()); - } - async onClose() { - if (this._modeSubscribers && this._modeSubscribers.length > 0) { - for (let r of this._modeSubscribers) - r.event === "active-leaf-change" - ? this.app.workspace.off("active-leaf-change", r.ref) - : r.event === "modify" && this.app.vault.off("modify", r.ref); - this._modeSubscribers = []; - } - (this._leafChangeTimer && - (clearTimeout(this._leafChangeTimer), (this._leafChangeTimer = null)), - (this._cachedItems = null), - (this._cachedStats = null)); - } - _buildPanel() { - let r = this.containerEl; - (r.empty(), r.addClass("paperforge-status-panel")); - let n = r.createEl("div", { cls: "paperforge-header" }), - i = n.createEl("div", { cls: "paperforge-header-left" }); - (i.createEl("div", { cls: "paperforge-header-logo", text: "P" }), - (this._modeContextEl = i.createEl("div", { - cls: "paperforge-mode-context", - })), - (this._headerTitle = i.createEl("h3", { - cls: "paperforge-header-title", - text: "PaperForge", - })), - (this._versionBadge = i.createEl("span", { - cls: "paperforge-header-badge", - text: "v\u2014", - }))); - let a = n.createEl("button", { - cls: "paperforge-header-refresh", - attr: { "aria-label": "Refresh" }, - }); - ((a.innerHTML = "\u21BB"), - a.addEventListener("click", () => { - (this._invalidateIndex(), this._detectAndSwitch()); - }), - (this._messageEl = r.createEl("div", { cls: "paperforge-message" })), - (this._contentEl = r.createEl("div", { - cls: "paperforge-content-area", - }))); - } - _fetchVersion() { - var l, u; - let r = this.app.vault.adapter.basePath, - n = this.app.plugins.plugins.paperforge, - i = - ((l = n == null ? void 0 : n.manifest) == null ? void 0 : l.version) || - "?", - { path: a, extraArgs: c = [] } = re( - r, - (u = n == null ? void 0 : n.settings) != null ? u : null, - void 0, - void 0 - ); - Cn(a, i, r, 1e4, void 0).then((p) => { - if (p.status === "not-installed") return; - let h = p.pyVersion || ""; - ((this._paperforgeVersion = h.startsWith("v") ? h : "v" + h), - this._versionBadge && - this._versionBadge.setText(this._paperforgeVersion), - this._driftBannerEl && - i && - this._paperforgeVersion !== "v" + i.replace(/^v/, "") - ? ((this._driftBannerEl.style.display = "block"), - this._driftBannerEl.setText( - f("dashboard_drift_warning") - .replace("{0}", this._paperforgeVersion) - .replace("{1}", "v" + i.replace(/^v/, "")) - )) - : this._driftBannerEl && - (this._driftBannerEl.style.display = "none")); - }); - } - _fetchStats(r) { - var l; - if (!this._metricsEl) return; - if (!r && !this._cachedStats) - (this._metricsEl.empty(), - this._metricsEl.createEl("div", { - cls: "paperforge-status-loading", - text: "Loading...", - })); - else if (r && !this._cachedStats) return; - let n = this.app.vault.adapter.basePath, - i = this.app.plugins.plugins.paperforge, - { path: a, extraArgs: c = [] } = re( - n, - (l = i == null ? void 0 : i.settings) != null ? l : null, - void 0, - void 0 - ); - (0, et.execFile)( - a, - [...c, "-m", "paperforge", "dashboard", "--json"], - { cwd: n, timeout: 3e4 }, - (u, p) => { - if (!u) - try { - let h = JSON.parse(p); - if (h.ok && h.data) { - let b = this._normalizeDashboardData(h.data); - ((this._cachedStats = b), - this._metricsEl.empty(), - this._renderStats(b), - this._renderOcr(b), - (this._dashboardPermissions = h.data.permissions || {})); - return; - } - } catch (h) {} - this._fallbackFetchStats(r, n, i); - } - ); - } - _normalizeDashboardData(r) { - let n = r.stats || {}, - i = n.ocr_health || {}, - a = n.pdf_health || {}, - c = r.ocr_version_state || {}, - l = (i.done || 0) + (i.pending || 0) + (i.failed || 0); - return { - total_papers: n.papers || 0, - formal_notes: n.papers || 0, - exports: 0, - bases: 0, - ocr: { - total: l, - pending: i.pending || 0, - processing: 0, - done: i.done || 0, - failed: i.failed || 0, - }, - path_errors: (a.broken || 0) + (a.missing || 0), - ocr_version_state: { - total_papers: c.total_papers || 0, - derived_stale_count: c.derived_stale_count || 0, - raw_upgradable_count: c.raw_upgradable_count || 0, - }, - }; - } - _fallbackFetchStats(r, n, i) { - var l, u, p; - let a = - ((l = i == null ? void 0 : i.settings) == null - ? void 0 - : l.system_dir) || "System", - c = Mt.join(n, a, "PaperForge", "indexes", "formal-library.json"); - try { - let h = We.readFileSync(c, "utf-8"), - b = JSON.parse(h), - k = b.items || [], - g = {}, - x = { - pdf_health: { healthy: 0, unhealthy: 0 }, - ocr_health: { healthy: 0, unhealthy: 0 }, - note_health: { healthy: 0, unhealthy: 0 }, - asset_health: { healthy: 0, unhealthy: 0 }, - }, - C = 0, - R = 0, - S = 0, - F = 0, - B = 0, - A = 0; - for (let v of k) { - v.note_path && A++; - let w = v.lifecycle || "pdf_ready"; - g[w] = (g[w] || 0) + 1; - let O = v.health || {}; - for (let I of [ - "pdf_health", - "ocr_health", - "note_health", - "asset_health", - ]) - (O[I] || "healthy") === "healthy" ? x[I].healthy++ : x[I].unhealthy++; - let M = v.ocr_status || ""; - (C++, - M === "done" - ? R++ - : M === "pending" - ? S++ - : M === "processing" || M === "queued" || M === "running" - ? F++ - : B++); - } - ((this._cachedStats = { - version: - b.paperforge_version || - ((u = this._cachedStats) == null ? void 0 : u.version) || - "\u2014", - total_papers: k.length, - formal_notes: A, - exports: 0, - bases: 0, - ocr: { total: C, pending: S, processing: F, done: R, failed: B }, - path_errors: 0, - lifecycle_level_counts: g, - health_aggregate: x, - }), - this._metricsEl.empty(), - this._renderStats(this._cachedStats), - this._renderOcr(this._cachedStats)); - } catch (h) { - !r && - !this._cachedStats && - this._metricsEl.createEl("div", { - cls: "paperforge-status-loading", - text: "No index \u2014 trying CLI...", - }); - let { path: b, extraArgs: k = [] } = re( - n, - (p = i == null ? void 0 : i.settings) != null ? p : null, - void 0, - void 0 - ); - (0, et.execFile)( - b, - [...k, "-m", "paperforge", "status", "--json"], - { cwd: n, timeout: 3e4 }, - (g, x) => { - if (g) { - if (this._cachedStats) return; - this._metricsEl.createEl("div", { - cls: "paperforge-status-error", - text: `Cannot reach PaperForge CLI. -Make sure paperforge is installed and in your PATH.`, - }); - return; - } - try { - let C = JSON.parse(x); - ((this._cachedStats = C), - this._metricsEl.empty(), - this._renderStats(C), - this._renderOcr(C)); - } catch (C) { - this._cachedStats || - this._metricsEl.createEl("div", { - cls: "paperforge-status-error", - text: "Invalid response from paperforge status.", - }); - } - } - ); - } - } - _renderSkeleton(r) { - r.addClass("paperforge-loading"); - } - _renderEmptyState(r, n) { - r.createEl("div", { cls: "paperforge-empty-state", text: n || "No data" }); - } - _buildMetricBar(r, n, i) { - if (i <= 0) return; - let a = Math.min(100, (n / i) * 100); - r.createEl("div", { cls: "paperforge-metric-progress" }).createEl("div", { - cls: "paperforge-metric-progress-fill", - attr: { style: `width:${a.toFixed(1)}%` }, - }); - } - _loadIndex() { - var c; - let r = this.app.vault.adapter.basePath, - n = this.app.plugins.plugins.paperforge, - i = - ((c = n == null ? void 0 : n.settings) == null - ? void 0 - : c.system_dir) || "System", - a = Mt.join(r, i, "PaperForge", "indexes", "formal-library.json"); - try { - let l = We.readFileSync(a, "utf-8"); - return JSON.parse(l); - } catch (l) { - return null; - } - } - _getCachedIndex() { - if (!this._cachedItems) { - let r = this._loadIndex(); - this._cachedItems = r ? r.items || [] : []; - } - return this._cachedItems; - } - _findEntry(r) { - if (!r) return null; - let n = this._getCachedIndex().find((i) => i.zotero_key === r) || null; - return wn(this.app, n); - } - _patchCachedEntry(r, n) { - if (!r || !this._cachedItems) return; - let i = this._cachedItems.findIndex((a) => a.zotero_key === r); - i !== -1 && (this._cachedItems[i] = xr(this._cachedItems[i], n)); - } - _filterByDomain(r) { - return r ? this._getCachedIndex().filter((n) => n.domain === r) : []; - } - _renderStats(r) { - var l; - if ( - (this._versionBadge && - this._versionBadge.setText( - this._paperforgeVersion || (r.version ? "v" + r.version : "v\u2014") - ), - !r || typeof r.total_papers == "undefined") - ) { - this._metricsEl && this._renderSkeleton(this._metricsEl); - return; - } - if (!this._metricsEl) return; - this._metricsEl.removeClass("paperforge-loading"); - let n = r.total_papers || 0, - i = r.formal_notes || 0, - a = [ - { value: n, label: "Papers", color: "var(--color-cyan)", barMax: 0 }, - { - value: i, - label: "Formal Notes", - color: "var(--color-blue)", - barMax: n, - }, - { - value: r.exports || 0, - label: "Exports", - color: "var(--color-purple)", - barMax: 0, - }, - ]; - for (let u of a) { - let p = this._metricsEl.createEl("div", { - cls: "paperforge-metric-card", - }); - (p.style.setProperty("--metric-color", u.color), - p.createEl("div", { - cls: "paperforge-metric-value", - text: ((l = u.value) == null ? void 0 : l.toString()) || "\u2014", - }), - p.createEl("div", { cls: "paperforge-metric-label", text: u.label }), - u.barMax > 0 && this._buildMetricBar(p, u.value, u.barMax)); - } - let c = r.ocr_version_state || {}; - if ( - c.total_papers > 0 && - (c.derived_stale_count > 0 || c.raw_upgradable_count > 0) - ) { - let u = []; - (c.derived_stale_count > 0 && u.push(`${c.derived_stale_count} stale`), - c.raw_upgradable_count > 0 && - u.push(`${c.raw_upgradable_count} upgradable`)); - let p = this._metricsEl.createEl("div", { - cls: "paperforge-metric-card", - }); - (p.style.setProperty("--metric-color", "var(--color-yellow)"), - p.createEl("div", { - cls: "paperforge-metric-value", - text: u.join(", "), - }), - p.createEl("div", { - cls: "paperforge-metric-label", - text: "OCR Version", - })); - } - } - _renderOcr(r) { - if (!this._ocrSection) return; - let n = r.ocr || {}, - i = n.total || 0; - if (i === 0) { - this._ocrSection.style.display = "none"; - return; - } - ((this._ocrSection.style.display = "block"), - this._ocrEmpty && (this._ocrEmpty.style.display = "none")); - let a = n.done || 0, - c = n.pending || 0, - l = n.processing || 0, - u = n.failed || 0; - if ( - (this._ocrBadge && - (this._ocrBadge.removeClass("active", "idle"), - l > 0 - ? (this._ocrBadge.addClass("active"), - this._ocrBadge.setText("Processing")) - : c > 0 - ? (this._ocrBadge.addClass("idle"), - this._ocrBadge.setText("Pending")) - : (this._ocrBadge.addClass("idle"), - this._ocrBadge.setText("Idle"))), - this._ocrTrack) - ) { - (this._ocrTrack.empty(), - l > 0 - ? this._ocrTrack.addClass("paperforge-processing") - : this._ocrTrack.removeClass("paperforge-processing")); - let p = [ - { cls: "pending", count: c }, - { cls: "active", count: l }, - { cls: "done", count: a }, - { cls: "failed", count: u }, - ]; - for (let h of p) - if (h.count > 0) { - let b = ((h.count / i) * 100).toFixed(1); - this._ocrTrack.createEl("div", { - cls: `paperforge-progress-seg ${h.cls}`, - attr: { style: `width:${b}%` }, - }); - } - } - if (this._ocrCounts) { - this._ocrCounts.empty(); - let p = [ - { cls: "pending", value: c, label: "Pending" }, - { cls: "active", value: l, label: "Processing" }, - { cls: "done", value: a, label: "Done" }, - { cls: "failed", value: u, label: "Failed" }, - ]; - for (let h of p) { - let b = this._ocrCounts.createEl("div", { - cls: "paperforge-ocr-count", - }); - (b.createEl("div", { - cls: "paperforge-ocr-count-value", - text: h.value.toString(), - }), - b.createEl("div", { - cls: "paperforge-ocr-count-label", - text: h.label, - })); - } - } - } - _renderLifecycleStepper(r, n, i) { - if (!n || !i) { - this._renderSkeleton(r); - return; - } - let a = [ - { key: "indexed", label: "Indexed" }, - { key: "pdf_ready", label: "PDF Ready" }, - { key: "fulltext_ready", label: "Fulltext Ready" }, - { key: "deep_read_done", label: "Deep Read" }, - ], - c = r.createEl("div", { cls: "paperforge-lifecycle-stepper" }), - l = !1; - for (let u of a) { - let p = c.createEl("div", { cls: "step" }); - (p.createEl("div", { cls: "step-indicator" }), - p.createEl("div", { cls: "step-label", text: u.label }), - u.key === i - ? (p.addClass("current"), (l = !0)) - : l - ? p.addClass("pending") - : p.addClass("completed")); - } - } - _renderHealthMatrix(r, n) { - if (!n) { - this._renderSkeleton(r); - return; - } - let i = [ - { - key: "pdf_health", - label: "PDF Health", - iconOk: "\u2713", - iconWarn: "\u26A0", - iconFail: "\u2717", - }, - { - key: "ocr_health", - label: "OCR Health", - iconOk: "\u2713", - iconWarn: "\u26A0", - iconFail: "\u2717", - }, - { - key: "note_health", - label: "Note Health", - iconOk: "\u2713", - iconWarn: "\u26A0", - iconFail: "\u2717", - }, - { - key: "asset_health", - label: "Asset Health", - iconOk: "\u2713", - iconWarn: "\u26A0", - iconFail: "\u2717", - }, - ], - a = r.createEl("div", { cls: "paperforge-health-matrix" }); - for (let c of i) { - let l = n[c.key] || "healthy", - u = a.createEl("div", { cls: "paperforge-health-cell" }), - p, - h, - b; - (l === "healthy" || l === "ok" - ? ((p = c.iconOk), (h = "ok"), (b = `${c.label}: OK`)) - : l === "warn" || l === "warning" || l === "degraded" - ? ((p = c.iconWarn), - (h = "warn"), - (b = `${c.label}: Needs Attention`)) - : ((p = c.iconFail), (h = "fail"), (b = `${c.label}: Failed`)), - u.addClass(h), - u.setAttribute("title", b), - u.createEl("div", { cls: "paperforge-health-cell-icon", text: p }), - u.createEl("div", { - cls: "paperforge-health-cell-label", - text: c.label, - })); - } - } - _renderMaturityGauge(r, n, i) { - if (n == null || n === void 0) { - this._renderSkeleton(r); - return; - } - let a = r.createEl("div", { cls: "paperforge-maturity-gauge" }), - c = a.createEl("div", { cls: "gauge-track" }), - l = 4, - u = Math.max(1, Math.min(l, Math.round(n))); - for (let p = 1; p <= l; p++) { - let h = c.createEl("div", { cls: "gauge-segment" }); - p <= u && (h.addClass("filled"), h.addClass(`level-${p}`)); - } - if ( - (a.createEl("div", { cls: "gauge-level", text: `Level ${u} / ${l}` }), - u < l && i) - ) { - let p = typeof i == "string" ? [i] : i; - if (p.length > 0) { - let h = a.createEl("ul", { cls: "gauge-blockers" }); - for (let b of p) h.createEl("li", { text: b }); - } - } - } - _renderBarChart(r, n) { - if (!n || Object.keys(n).length === 0) { - this._renderEmptyState(r, "No lifecycle data"); - return; - } - let i = [ - { key: "indexed", label: "Indexed", cls: "stage-indexed" }, - { key: "pdf_ready", label: "PDF Ready", cls: "stage-pdf-ready" }, - { - key: "fulltext_ready", - label: "Fulltext Ready", - cls: "stage-fulltext-ready", - }, - { key: "deep_read_done", label: "Deep Read", cls: "stage-deep-read" }, - ], - a = r.createEl("div", { cls: "paperforge-bar-chart" }), - c = Math.max(1, ...i.map((l) => n[l.key] || 0)); - for (let l of i) { - let u = n[l.key] || 0, - p = (u / c) * 100, - h = a.createEl("div", { cls: "bar-row" }); - (h.createEl("div", { cls: "bar-label", text: l.label }), - h - .createEl("div", { cls: "bar-track" }) - .createEl("div", { - cls: `bar-fill ${l.cls}`, - attr: { style: `width:${p.toFixed(1)}%` }, - }), - h.createEl("div", { cls: "bar-count", text: u.toString() })); - } - } - _invalidateIndex() { - this._cachedItems = null; - } - _extractZoteroKeyFromPath(r) { - return Hn(r); - } - _resolveModeForFile(r) { - if (!r) return { mode: "global", filePath: null, key: null, domain: null }; - let n = r.extension, - i = r.path; - if (n === "base") - return { - mode: "collection", - filePath: i, - key: null, - domain: r.basename.trim(), - }; - if (n === "md") { - let c = this.app.metadataCache.getFileCache(r), - l = c && c.frontmatter && c.frontmatter.zotero_key; - if (l) return { mode: "paper", filePath: i, key: l, domain: null }; - } - if (n === "pdf") { - let c = this._getCachedIndex(); - for (let l of c) { - let u = (l.pdf_path || "").match(/\[\[([^\]]+)\]\]/); - if ((u ? u[1] : l.pdf_path) === i) - return { - mode: "paper", - filePath: i, - key: l.zotero_key, - domain: null, - }; - } - } - let a = this._extractZoteroKeyFromPath(i); - return a - ? { mode: "paper", filePath: i, key: a, domain: null } - : { mode: "global", filePath: i, key: null, domain: null }; - } - _detectAndSwitch() { - let r = this._resolveModeForFile(this.app.workspace.getActiveFile()); - ((this._currentDomain = r.domain || null), - (this._currentPaperKey = r.key || null), - (this._currentPaperEntry = r.key ? this._findEntry(r.key) : null), - this._switchMode(r.mode, r.filePath)); - } - _switchMode(r, n) { - if (this._currentMode === r && this._currentFilePath === n) { - this._refreshCurrentMode(); - return; - } - if ( - ((this._currentMode = r), - (this._currentFilePath = n), - (this._techDetailsExpanded = !1), - !!this._contentEl) - ) - switch ( - (this._contentEl.empty(), - this._contentEl.removeClass("switching"), - this._renderModeHeader(r), - r) - ) { - case "global": - this._renderGlobalMode(); - break; - case "paper": - this._renderPaperMode(); - break; - case "collection": - this._renderCollectionMode(); - break; - case "versions": - this._renderVersionMode(); - break; - } - } - _renderGlobalMode() { - var we, ge, Ce, fe, Le, De, Ie; - if (!this._contentEl) return; - let r = this._contentEl.createEl("div", { cls: "paperforge-global-view" }); - ((this._driftBannerEl = r.createEl("div", { - cls: "paperforge-drift-banner", - })), - (this._driftBannerEl.style.display = "none")); - let n = this._getCachedIndex(), - i = n.length, - a = 0, - c = 0, - l = 0; - for (let K of n) - (K.has_pdf && a++, - K.ocr_status === "done" && c++, - K.deep_reading_status === "done" && l++); - let u = r.createEl("div", { cls: "paperforge-library-snapshot" }); - u.createEl("div", { - cls: "paperforge-section-label", - text: "Library Snapshot", - }); - let p = u.createEl("div", { cls: "paperforge-snapshot-pills" }), - h = [ - { value: i, label: "papers" }, - { value: a, label: "PDFs ready" }, - { value: c, label: "OCR done" }, - { value: l, label: "deep-read done" }, - ]; - for (let K of h) { - let j = p.createEl("div", { cls: "paperforge-snapshot-pill" }); - (j.createEl("span", { - cls: "paperforge-snapshot-value", - text: String(K.value), - }), - j.createEl("span", { - cls: "paperforge-snapshot-label", - text: " " + K.label, - })); - } - let b = r.createEl("div", { cls: "paperforge-system-status" }); - b.createEl("div", { - cls: "paperforge-section-label", - text: "System Status", - }); - let k = b.createEl("div", { cls: "paperforge-status-grid" }), - g = this.app.plugins.plugins.paperforge, - x = - ((we = g == null ? void 0 : g.manifest) == null - ? void 0 - : we.version) || "?", - C = this._paperforgeVersion; - if (!C) - try { - let K = this.app.vault.adapter.basePath, - { path: j, extraArgs: ke = [] } = re( - K, - (ge = g == null ? void 0 : g.settings) != null ? ge : null, - void 0, - void 0 - ), - ce = (0, et.execFileSync)( - j, - [...ke, "-c", "import paperforge; print(paperforge.__version__)"], - { cwd: K, timeout: 5e3, encoding: "utf-8", windowsHide: !0 } - ).trim(); - ce && - ((C = ce.startsWith("v") ? ce : "v" + ce), - (this._paperforgeVersion = C)); - } catch (K) {} - C = C || "\u2014"; - let R = C === "v" + x; - this._renderSystemStatusRow( - k, - "Runtime", - R ? "healthy" : "mismatch", - R ? "v" + x : "plugin v" + x + " \u2260 CLI " + C - ); - let S = this._loadIndex(), - F = S && S.items && S.items.length > 0; - this._renderSystemStatusRow( - k, - "Index", - F ? "healthy" : "missing", - F ? S.items.length + " entries" : "formal-library.json not found" - ); - let B = - ((Ce = g == null ? void 0 : g.settings) == null - ? void 0 - : Ce.system_dir) || "System", - A = this.app.vault.adapter.basePath, - v = !1, - w = "No exports found"; - try { - let K = Mt.join(A, B, "PaperForge", "exports"); - if (We.existsSync(K)) { - let j = We.readdirSync(K).filter((ke) => ke.endsWith(".json")); - ((v = j.length > 0), - (w = v ? j.length + " export(s)" : "No JSON exports")); - } - } catch (K) {} - this._renderSystemStatusRow( - k, - "Zotero Export", - v ? "healthy" : "missing", - w - ); - let O = !!( - (fe = g == null ? void 0 : g.settings) != null && fe.paddleocr_api_key - ); - if (!O) - try { - let K = - ((Le = g == null ? void 0 : g.settings) == null - ? void 0 - : Le.system_dir) || "System", - j = Mt.join(A, K, "PaperForge", ".env"); - if (We.existsSync(j)) { - let ce = We.readFileSync(j, "utf-8").match( - /^PADDLEOCR_API_TOKEN\s*=\s*(.+)$/m - ); - O = !!(ce && ce[1] && ce[1].trim()); - } - } catch (K) {} - (O || - (O = !!( - process.env.PADDLEOCR_API_TOKEN || - process.env.PADDLEOCR_API_KEY || - process.env.OCR_TOKEN - )), - this._renderSystemStatusRow( - k, - "OCR Token", - O ? "configured" : "missing", - O ? "Configured" : "Not set" - )); - let M = !1, - I = "", - J = this.app.vault.adapter.basePath, - q = Tr(J); - ((M = An(J)), - (I = - (q && ((De = q.summary) == null ? void 0 : De.reason)) || - (q && ((Ie = q.summary) == null ? void 0 : Ie.status)) || - "Unknown"), - this._renderSystemStatusRow( - k, - "Memory Layer", - M ? "healthy" : "fail", - I - )); - let te = !R && C !== "\u2014"; - if (te || !F || !v || !O) { - let K = r.createEl("div", { cls: "paperforge-issue-summary" }); - K.createEl("div", { - cls: "paperforge-section-label", - text: "\u9700\u8981\u5904\u7406", - }); - let j = K.createEl("div", { cls: "paperforge-issue-list" }); - (te && - j.createEl("div", { - cls: "paperforge-issue-item", - text: "Runtime version mismatch", - }), - F || - j.createEl("div", { - cls: "paperforge-issue-item", - text: "Index missing or corrupted", - }), - v || - j.createEl("div", { - cls: "paperforge-issue-item", - text: "No Zotero export found", - }), - O || - j.createEl("div", { - cls: "paperforge-issue-item", - text: "PaddleOCR API key not configured", - })); - let ke = K.createEl("div", { cls: "paperforge-issue-actions" }), - ce = ke.createEl("button", { cls: "paperforge-contextual-btn" }); - (ce.createEl("span", { text: "Run Doctor" }), - ce.addEventListener("click", () => { - let Ne = Pe.find((vt) => vt.id === "paperforge-doctor"); - Ne && this._runAction(Ne, ce); - })); - let Ae = ke.createEl("button", { cls: "paperforge-contextual-btn" }); - (Ae.createEl("span", { text: "Repair Issues" }), - Ae.addEventListener("click", () => { - let Ne = Pe.find((vt) => vt.id === "paperforge-repair"); - Ne && this._runAction(Ne, Ae); - })); - } - let G = r.createEl("div", { cls: "paperforge-global-actions" }); - G.createEl("div", { - cls: "paperforge-section-label", - text: "Start Working", - }); - let ye = G.createEl("div", { cls: "paperforge-global-actions-row" }), - ue = ye.createEl("button", { cls: "paperforge-contextual-btn primary" }); - (ue.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u{1F4C1}", - }), - ue.createEl("span", { text: "Open Literature Hub" }), - ue.addEventListener("click", () => { - var ke; - let K = - ((ke = g == null ? void 0 : g.settings) == null - ? void 0 - : ke.base_dir) || "Bases", - j = this.app.vault.getAbstractFileByPath(K); - if (j) { - let ce = null; - if ( - (j.children && - (ce = j.children.find((Ae) => Ae.extension === "base")), - ce) - ) { - let Ae = this.app.workspace.getLeaf(!1); - Ae && Ae.openFile(ce); - } else new X.Notice("[!!] No .base file found in " + K, 6e3); - } else new X.Notice("[!!] Base directory not found: " + K, 6e3); - })); - let V = ye.createEl("button", { cls: "paperforge-contextual-btn" }); - (V.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u21BB", - }), - V.createEl("span", { text: "Sync Library" }), - V.addEventListener("click", () => { - let K = Pe.find((j) => j.id === "paperforge-sync"); - K && this._runAction(K, V); - })); - let U = ye.createEl("button", { cls: "paperforge-contextual-btn" }); - (U.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u229E", - }), - U.createEl("span", { text: "Run OCR" }), - U.addEventListener("click", () => { - let K = Pe.find((j) => j.id === "paperforge-ocr"); - K && this._runAction(K, U); - })); - let be = ye.createEl("button", { cls: "paperforge-contextual-btn warn" }); - (be.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u21BA", - }), - be.createEl("span", { text: "Redo OCR" }), - be.addEventListener("click", () => { - let K = Pe.find((j) => j.id === "paperforge-ocr-redo"); - K && this._runAction(K, be); - })); - } - _renderSystemStatusRow(r, n, i, a) { - let c = r.createEl("div", { cls: "paperforge-status-row" }); - (c - .createEl("span", { cls: "paperforge-status-dot" }) - .addClass(i === "healthy" || i === "configured" ? "ok" : "fail"), - c.createEl("span", { cls: "paperforge-status-label", text: n }), - c.createEl("span", { cls: "paperforge-status-detail", text: a || "" })); - } - _renderPaperMode() { - let r = this._currentPaperEntry, - n = this._currentPaperKey; - if (!this._contentEl) return; - if (!n) { - this._renderEmptyState(this._contentEl, "No paper data available."); - return; - } - if (!r) { - this._contentEl.createEl("div", { - cls: "paperforge-content-placeholder", - text: 'Paper "' + n + '" not found in canonical index. Sync first.', - }); - return; - } - let i = this._contentEl.createEl("div", { cls: "paperforge-paper-view" }), - a = i.createEl("div", { cls: "paperforge-paper-header" }); - a.createEl("div", { - cls: "paperforge-paper-title pf-copy", - text: r.title || "Untitled", - }).addEventListener("click", () => { - (navigator.clipboard.writeText(r.title || ""), - new X.Notice("Title copied")); - }); - let l = a.createEl("div", { cls: "paperforge-paper-meta" }); - (r.authors && - r.authors.length > 0 && - l.createEl("span", { - cls: "paperforge-paper-authors", - text: r.authors.join(", "), - }), - r.year && - l.createEl("span", { - cls: "paperforge-paper-year", - text: String(r.year), - })); - let u = i.createEl("div", { cls: "paperforge-status-strip" }), - p = u.createEl("div", { cls: "paperforge-status-strip-left" }), - h = u.createEl("div", { cls: "paperforge-status-strip-right" }), - b = [ - { key: "pdf", label: "PDF", ok: r.has_pdf === !0 }, - { - key: "ocr", - label: "OCR", - ok: r.ocr_status === "done", - pending: ["pending", "queued", "processing"].includes( - r.ocr_status || "" - ), - fail: ["failed", "blocked", "done_incomplete", "nopdf"].includes( - r.ocr_status || "" - ), - }, - { - key: "deep", - label: "\u7CBE\u8BFB", - ok: r.deep_reading_status === "done", - }, - ]; - for (let g of b) { - let x = p.createEl("span", { cls: "paperforge-status-pill" }), - C = "pending"; - (g.ok ? (C = "ok") : g.fail ? (C = "fail") : g.pending && (C = "pending"), - x.addClass(C)); - let R = g.ok ? "\u2713" : g.fail ? "\u2717" : "\u25CB"; - (x.createEl("span", { cls: "paperforge-status-pill-icon", text: R }), - x.createEl("span", { text: " " + g.label })); - } - if (r.pdf_path) { - let g = h.createEl("button", { cls: "paperforge-contextual-btn" }); - (g.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u{1F4C4}", - }), - g.createEl("span", { text: "\u6253\u5F00 PDF" }), - g.addEventListener("click", () => { - let x = r.pdf_path.match(/\[\[([^\]]+)\]\]/), - C = x ? x[1] : r.pdf_path; - this.app.vault.getAbstractFileByPath(C) - ? this.app.workspace.openLinkText(C, "") - : new X.Notice("[!!] PDF not found: " + C, 6e3); - })); - } - if (r.fulltext_path) { - let g = h.createEl("button", { cls: "paperforge-contextual-btn" }); - (g.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u{1F4DD}", - }), - g.createEl("span", { text: "\u6253\u5F00\u5168\u6587" }), - g.addEventListener("click", () => this._openFulltext(r.fulltext_path))); - } - let k = h.createEl("button", { cls: "paperforge-contextual-btn" }); - if ( - (k.createEl("span", { text: f("version_panel_title") }), - k.addEventListener("click", () => { - this._switchToVersionMode(n); - }), - this._renderPaperOverviewCard(i, r), - r.next_step === "ready" && r.deep_reading_status === "done") - ) { - let g = i.createEl("div", { cls: "paperforge-complete-row" }); - (g.createEl("span", { text: "\u2713" }), - g.createEl("span", { - text: "\u5DF2\u5B8C\u6210\uFF0C\u53EF\u76F4\u63A5\u4F7F\u7528", - })); - } else this._renderNextStepCard(i, r, n); - (this._renderRecentDiscussionCard(i, r), - this._renderPaperTechnicalDetails(i, r)); - } - _renderPaperOverviewCard(r, n) { - let i = r.createEl("div", { cls: "paperforge-paper-overview" }); - i.createEl("div", { cls: "paperforge-paper-overview-header" }).createEl( - "span", - { - cls: "paperforge-paper-overview-title", - text: "\u6587\u7AE0\u6982\u89C8", - } - ); - let c = i.createEl("div", { cls: "paperforge-paper-overview-body" }), - l = c.createEl("div", { - cls: "paperforge-paper-overview-excerpt", - text: "\u52A0\u8F7D\u4E2D...", - }); - if (n.note_path) { - let u = this.app.vault.getAbstractFileByPath(n.note_path); - u - ? this.app.vault - .read(u) - .then((p) => { - let h = this._extractOverviewFromNote(p); - if (h) { - let b = h.length > 200 ? h.slice(0, 200) + "..." : h; - if ((l.setText(b), h.length > 200)) { - let k = c.createEl("div", { - cls: "paperforge-expand-container", - }), - g = k.createEl("button", { - cls: "paperforge-expand-icon", - title: "\u5C55\u5F00/\u6536\u8D77", - }); - g.innerHTML = - ''; - let x = !1; - k.addEventListener("click", () => { - (l.setText(x ? b : h), - (g.innerHTML = x - ? '' - : ''), - (x = !x)); - }); - } - } else - l.setText( - "\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8\u3002\u8FD0\u884C /pf-deep \u5F00\u59CB\u7CBE\u8BFB\u3002" - ); - }) - .catch(() => { - l.setText("\u65E0\u6CD5\u8BFB\u53D6\u7B14\u8BB0\u5185\u5BB9"); - }) - : l.setText("\u7B14\u8BB0\u6587\u4EF6\u4E0D\u5B58\u5728"); - } else l.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8"); - } - _extractOverviewFromNote(r) { - if (!r) return null; - let n = r.indexOf("## \u{1F50D} \u7CBE\u8BFB"); - if (n === -1) return null; - let i = r.slice(n), - a = [ - "**\u4E00\u53E5\u8BDD\u603B\u89C8:**", - "**\u4E00\u53E5\u8BDD\u603B\u89C8**", - "**\u6587\u7AE0\u6458\u8981:**", - "**\u6587\u7AE0\u6458\u8981**", - ]; - for (let u of a) { - let p = i.indexOf(u); - if (p !== -1) { - let h = i.slice(p + u.length), - b = ["**5 Cs", "**Figure", "**\u8BC1\u636E", "### Pass 2", "## "], - k = h.length; - for (let C of b) { - let R = h.indexOf(C); - R !== -1 && R < k && (k = R); - } - let g = h.indexOf(` + `,document.head.appendChild(a)}let t=e.createDiv({cls:"paperforge-settings-tabs"}),r=[{id:"setup",label:o("tab_setup")||"\u5B89\u88C5"},{id:"features",label:o("tab_features")||"\u529F\u80FD"},{id:"maintenance",label:o("tab_maintenance")||"\u7EF4\u62A4"},{id:"release-notes",label:"\u66F4\u65B0\u4E0E\u624B\u518C"}],n={};r.forEach(a=>{t.createEl("button",{cls:"paperforge-settings-tab"+(a.id===this.activeTab?" paperforge-settings-tab--active":""),text:a.label}).addEventListener("click",()=>{this.activeTab=a.id,this.display()})}),r.forEach(a=>{n[a.id]=e.createDiv({cls:"paperforge-tab-content"+(a.id===this.activeTab?" paperforge-tab-content--active":"")})}),this.activeTab==="setup"?this._renderSetupTab(n.setup):this.activeTab==="features"?this._renderFeaturesTab(n.features):this.activeTab==="maintenance"?this._renderMaintenanceTab(n.maintenance):this._renderReleaseNotesTab(n["release-notes"])}_renderSetupTab(e){let t=this.app.vault.adapter.basePath;this.plugin.settings.vault_path||(this.plugin.settings.vault_path=t,this._debouncedSave()),this.plugin.settings.setup_complete&&(N.existsSync(Z.join(t,"paperforge.json"))||(this.plugin.settings.setup_complete=!1,this._debouncedSave())),e.createEl("h2",{text:o("header_title")||"PaperForge"}),e.createEl("p",{text:o("desc"),cls:"paperforge-settings-desc"});let n=e.createEl("div",{cls:"paperforge-setup-bar"}).createEl("span",{cls:"paperforge-setup-label"});this.plugin.settings.setup_complete?(n.setText(o("setup_done")),n.addClass("paperforge-setup-done")):(n.setText(o("setup_pending")),n.addClass("paperforge-setup-pending"));let a=this.app.vault.adapter.basePath,s=L(a,this.plugin.settings,void 0,void 0),l=s.path,i=this.plugin.settings._python_path_stale?"stale":s.source,c=new C.Setting(e).setName(o("field_python_interp")).setDesc(this._getPythonDesc(l,i));this._pythonInterpDescEl=c.descEl;let d=new C.Setting(e).setName(o("field_python_custom")).setDesc("");this._customPathDescEl=d.descEl,d.addText(E=>{E.setPlaceholder("e.g. C:\\Python310\\python.exe").setValue(this.plugin.settings.python_path||"").onChange(_=>{if(this.plugin.settings.python_path=_,this.plugin.saveSettings(),_&&_.trim()){let S=N.existsSync(_.trim());this.plugin.settings._python_path_stale=!S}else this.plugin.settings._python_path_stale=!1;let v=L(this.app.vault.adapter.basePath,this.plugin.settings,void 0,void 0),k=this.plugin.settings._python_path_stale?"stale":v.source;this._pythonInterpDescEl&&(this._pythonInterpDescEl.textContent=this._getPythonDesc(v.path,k))})}),d.addButton(E=>{E.setButtonText(o("btn_validate")).onClick(()=>this._validatePythonOverride())}),e.createEl("h3",{text:o("runtime_health")}),e.createEl("p",{text:o("runtime_health_desc"),cls:"paperforge-settings-desc"});let g=new C.Setting(e).setName("PaperForge").setDesc(o("runtime_health_checking")),p=g.descEl.createEl("span",{cls:"paperforge-runtime-badge"}),f=null;g.addButton(E=>{f=E,E.setButtonText(o("runtime_health_sync")).setDisabled(!0).onClick(()=>this._syncRuntime(E))});{let E=this.app.vault.adapter.basePath,{path:_,extraArgs:v=[]}=L(E,this.plugin.settings,void 0,void 0),k=this.plugin.manifest.version||"?";(0,j.execFile)(_,[...v,"-c","import paperforge; print(paperforge.__version__)"],{cwd:E,timeout:1e4},(S,P)=>{let A=this.plugin.settings.setup_complete,T=!S&&P?P.trim():null,I=T?`${o("runtime_health_plugin_ver").replace("{0}",k)} \u2192 ${o("runtime_health_package_ver").replace("{0}",T)}`:A?`Plugin v${k} \u2192 Python package not installed. Click "Sync Runtime" to install.`:`Plugin v${k} \u2192 Not configured. Please open the setup wizard first.`;g.setDesc(I),T===k?(p.setText(o("runtime_health_match")),p.className="paperforge-runtime-badge match",f&&f.setDisabled(!0)):T?(p.setText(o("runtime_health_mismatch")),p.className="paperforge-runtime-badge mismatch",f&&f.setDisabled(!1)):(p.setText(A?"Not installed":"Setup needed"),p.className="paperforge-runtime-badge missing",f&&f.setDisabled(!1))})}e.createEl("h3",{text:o("section_prep")}),e.createEl("p",{text:o("section_prep_desc"),cls:"paperforge-settings-desc"});let y=e.createEl("div",{cls:"paperforge-guide"}),b=[["prep_python","prep_python_desc"],["prep_zotero","prep_zotero_desc"],["prep_bbt","prep_bbt_desc"],["prep_key","prep_key_desc"]];for(let[E,_]of b){let v=y.createEl("div",{cls:"paperforge-guide-item"});v.createEl("strong",{text:o(E)}),v.createEl("span",{text:" \u2014 "+o(_)})}this._checkEl=e.createEl("div",{cls:"paperforge-message"});let m=!this.plugin.settings.setup_complete;new C.Setting(e).setName(o(m?"btn_install":"btn_reconfig")).setDesc(o(m?"btn_install_desc":"btn_reconfig_desc")).addButton(E=>{E.setButtonText(o(m?"btn_install":"btn_reconfig")).setCta().onClick(()=>{m?this._preCheck(()=>{new Te(this.app,this.plugin).open()}):new Te(this.app,this.plugin).open()})}),e.createEl("h3",{text:o("section_guide")});let x=e.createEl("div",{cls:"paperforge-guide"}),w=[["guide_open","guide_open_desc"],["guide_sync","guide_sync_desc"],["guide_ocr","guide_ocr_desc"]];for(let[E,_]of w){let v=x.createEl("div",{cls:"paperforge-guide-item"});v.createEl("strong",{text:o(E)}),v.createEl("span",{text:" \u2014 "+o(_)})}if(this.plugin.settings.setup_complete){e.createEl("h3",{text:o("section_config")});let E=e.createEl("div",{cls:"paperforge-summary"}),_=this.plugin.settings,v=this._pfConfig,k=[{label:o("dir_vault"),val:t},{label:o("dir_resources"),val:`${t}/${v==null?void 0:v.resources_dir}`},{label:" "+o("dir_notes"),val:`${t}/${v==null?void 0:v.resources_dir}/${v==null?void 0:v.literature_dir}`},{label:o("dir_base"),val:`${t}/${v==null?void 0:v.base_dir}`},{label:o("dir_system"),val:`${t}/${v==null?void 0:v.system_dir}`},{label:"API Key",val:_.paddleocr_api_key?o("api_key_set"):o("api_key_missing")},{label:o("field_zotero_data"),val:_.zotero_data_dir||o("not_set")}];for(let S of k){let P=E.createEl("div",{cls:"paperforge-summary-row"});P.createEl("span",{cls:"paperforge-summary-label",text:S.label}),P.createEl("span",{cls:"paperforge-summary-value",text:S.val})}}}_execMemoryStatus(e,t,r){(0,j.exec)(`"${e}" -m paperforge --vault "${t}" memory status --json`,{encoding:"utf-8",timeout:15e3},(n,a)=>{if(n){r("Status unavailable");return}try{let s=JSON.parse(a);if(s.ok){let l=s.data,i=l.fresh?"fresh":"stale";r(`Papers: ${l.paper_count_db} | ${i}${l.needs_rebuild?" - needs rebuild":""}`)}else r("DB not found. Run paperforge memory build.")}catch(s){r("Could not parse status.")}})}_execEmbedStatus(e,t,r){(0,j.exec)(`"${e}" -m paperforge --vault "${t}" embed status --json`,{encoding:"utf-8",timeout:15e3},(n,a)=>{if(n){r("Status unavailable");return}try{let s=JSON.parse(a);s.ok?r(`Chunks: ${s.data.chunk_count} | ${s.data.model} | ${s.data.mode}`):r("Could not parse status.")}catch(s){r("Could not parse status.")}})}_callPython(e,t){let r=this.app.vault.adapter.basePath,n=ce(r,this.plugin.settings),a=[...n.extraArgs,"-m","paperforge","--vault",r,...e];if(t&&t.stream){let s=(0,j.spawn)(n.path,a,{cwd:r,env:t.env||process.env,windowsHide:!0});return t.onData&&s.stdout.on("data",t.onData),t.onStderr&&s.stderr.on("data",t.onStderr),t.onError&&s.on("error",t.onError),s.on("close",t.onClose),s}return(0,j.execFile)(n.path,a,{cwd:r,timeout:t&&t.timeout||6e4},(s,l,i)=>{t&&t.onClose&&t.onClose(s?1:0,l,i)}),null}_renderMemoryStatusText(e,t,r){e.innerHTML="",e.createEl("span",{text:t,cls:"paperforge-memory-text"}),r==="syncing"?e.createEl("span",{text:"Syncing...",cls:"paperforge-sync-status"}):r&&e.createEl("span",{text:r,cls:"paperforge-sync-status"});let n=e.createEl("button",{cls:"paperforge-rebuild-btn",text:o("feat_memory_rebuild_btn")});n.title="Rebuild memory database",n.onclick=()=>{let s=this.app.vault.adapter.basePath,l=ce(s,this.plugin.settings);if(!l.path){new C.Notice(o("feat_no_python"));return}console.log("[PaperForge] Rebuilding memory:",l.path),n.setText(o("feat_memory_rebuilding")),n.setAttr("disabled",""),this._callPython(["memory","build"],{timeout:6e4,onClose:(i,c,d)=>{console.log("[PaperForge] memory build exit:",i?"FAIL:"+i:"OK",(c||"").slice(0,200),(d||"").slice(0,200)),n.setText(o("feat_memory_rebuild_btn")),n.removeAttribute("disabled"),i===0?new C.Notice(o("feat_memory_rebuild_done")):new C.Notice(o("feat_memory_rebuild_failed")+(d?" "+d.slice(0,80):"")),this._memoryStatusText=Ie(s),this._refreshSnapshots(s)}})};let a=e.createEl("button",{cls:"paperforge-refresh-btn",text:"\u21BB"});a.title="Sync now",a.onclick=()=>{this._memoryStatusText=null,this._runManualSync()}}_getBuildCommand(e){let t=this.app.vault.adapter.basePath,r=L(t,e,void 0,void 0);return r.path?`"${r.path}" -m paperforge --vault "${t}" sync`:null}_runManualSync(){let e=this.app.vault.adapter.basePath;if(!ce(e,this.plugin.settings).path)return;let r=document.querySelector(".paperforge-memory-status");r&&this._renderMemoryStatusText(r,"Checking...","syncing"),this.plugin._autoSyncRunning=!0,this._callPython(["sync"],{timeout:12e4,onClose:n=>{this.plugin._autoSyncRunning=!1,this._memoryStatusText=null,n===0&&(this._lastSyncTime=new Date().toLocaleTimeString(),this.plugin._lastSyncTime=this._lastSyncTime),this.display(),this._refreshSnapshots(e),Ne(this.app,this.plugin,e)}})}_refreshSnapshots(e){let t=ce(e,this.plugin.settings),r=[...t.extraArgs,"-m","paperforge","--vault",e,"runtime-health","--json"];this._refreshPending=!0,(0,j.execFile)(t.path,r,{cwd:e,timeout:3e4,windowsHide:!0},(n,a,s)=>{this._refreshPending=!1,this._memoryStatusText=Ie(e),this._embedStatusText=be(e),this.display()})}_renderFeaturesTab(e){e.createEl("h3",{text:"Skills"});let t=e.createEl("div",{cls:"paperforge-desc-box"});t.setText(o("feat_skills_desc")),t.createEl("br"),t.createEl("span",{text:o("feat_skills_system")});let r={opencode:"OpenCode",claude:"Claude Code",codex:"Codex",cursor:"Cursor",windsurf:"Windsurf",github_copilot:"GitHub Copilot",gemini:"Gemini CLI"},n={opencode:".opencode/skills",claude:".claude/skills",codex:".codex/skills",cursor:".cursor/skills",windsurf:".windsurf/skills",github_copilot:".github/skills",gemini:".gemini/skills"},a=this.app.vault.adapter.basePath,s=this.plugin.settings.selected_skill_platform||"opencode";new C.Setting(e).setName(o("feat_agent_platform")).setDesc(o("feat_agent_platform_desc")).addDropdown(_=>{Object.entries(r).forEach(([v,k])=>_.addOption(v,k)),_.setValue(s).onChange(v=>{this.plugin.settings.selected_skill_platform=v,this.plugin.saveSettings(),this.display()})}).addExtraButton(_=>{_.setIcon("folder").setTooltip("Open skills folder").onClick(()=>{let v=n[s]||".opencode/skills",k=Z.join(a,v);N.existsSync(k)?(0,j.exec)(`start "" "${k}"`):new C.Notice(`Skills folder not found: ${v}`)})});let l=Z.join(a,n[s]),i=[],c=[];N.existsSync(l)&&N.readdirSync(l,{withFileTypes:!0}).forEach(_=>{if(!_.isDirectory())return;let v=Z.join(l,_.name,"SKILL.md");if(!N.existsSync(v))return;let k=N.readFileSync(v,"utf-8"),S=k.match(/^name:\s*(.+)$/m),P=k.split(` +`),A=P.findIndex(q=>/^description:/.test(q)),T="";if(A>=0){let q=P[A].match(/^description:\s*(.+)$/);if(q&&q[1]&&q[1]!==">"&&q[1]!=="|-"&&q[1]!=="|")T=q[1].trim();else{for(let F=A+1;F{if(v.length===0)return;let S=d.createEl("div",{cls:"paperforge-skills-group"}),P=S.createEl("div",{cls:"paperforge-skills-collapse-header"}),A=S.createEl("div",{cls:"paperforge-skills-collapse-content"}),T=P.createEl("span",{text:"\u25BC",cls:"paperforge-skills-arrow"});P.createEl("h4",{text:`${_} (${v.length})`,cls:"paperforge-skills-subheader"}),v.forEach(O=>{let U=O.name+(O.version?" v"+O.version:""),q=k?" [system]":" [user]",F=O.desc||"",D=new C.Setting(A).setName(U+q).setDesc(F);D.settingEl.style.opacity=O.disabled?"0.4":"1",D.addToggle(X=>{X.setValue(!O.disabled).onChange(ee=>{let oe=!ee,de=O.content.match(/^disable-model-invocation:\s*(.+)$/m)?O.content.replace(/^disable-model-invocation:\s*.+$/m,`disable-model-invocation: ${oe}`):O.content.replace(/^(---\r?\n)/,`$1disable-model-invocation: ${oe} +`);N.writeFileSync(O.path,de,"utf-8"),O.disabled=oe,O.content=de,D.settingEl.style.opacity=O.disabled?"0.4":"1"})})});let I=k?"system":"user";(this._skillsCollapsed[I]||!1)&&(A.style.display="none",T.style.transform="rotate(-90deg)"),P.addEventListener("click",()=>{A.style.display!=="none"?(A.style.display="none",T.style.transform="rotate(-90deg)"):(A.style.display="",T.style.transform="rotate(0deg)"),this._skillsCollapsed[I]=A.style.display==="none"})};g("System Skills",i,!0),g("User Skills",c,!1),i.length===0&&c.length===0&&d.createEl("p",{text:`No skills found in ${n[s]}. Run setup to deploy skills.`,cls:"setting-item-description"}),this._advCollapsed===void 0&&(this._advCollapsed=!0);let p=e.createEl("div",{cls:"paperforge-collapsible-header"}),f=p.createEl("span",{text:"\u25B6",cls:"paperforge-collapsible-arrow"});f.style.transform=this._advCollapsed?"rotate(0deg)":"rotate(90deg)";let y=p.createEl("span",{cls:"paperforge-collapsible-title",text:"Advanced"}),b=p.createEl("span",{cls:"paperforge-collapsible-sub",text:"Memory + Vector DB + Embedding"}),m=e.createEl("div",{cls:"paperforge-collapsible-content"});m.style.display=this._advCollapsed?"none":"",p.addEventListener("click",()=>{this._advCollapsed=!this._advCollapsed,m.style.display=this._advCollapsed?"none":"",f.style.transform=this._advCollapsed?"rotate(0deg)":"rotate(90deg)"}),m.createEl("h4",{text:"Memory Layer"}),m.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_memory_desc"));let w=m.createEl("div",{cls:"paperforge-memory-status"}),E=this.app.vault.adapter.basePath;this.plugin._lastSyncTime&&!this._lastSyncTime&&(this._lastSyncTime=this.plugin._lastSyncTime),this._memoryStatusText===null&&(this._memoryStatusText=Ie(E)),this._renderMemoryStatusText(w,this._memoryStatusText,this._lastSyncTime),this._renderVectorSection(m)}_renderVectorSection(e){var i;if(e.createEl("h4",{text:"Vector Database"}),this.plugin.settings.features||(this.plugin.settings.features={memory_layer:!0,vector_db:!1}),e.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_vector_desc")),new C.Setting(e).setName(o("feat_vector_enable")).setDesc(o("feat_vector_enable_desc")).addToggle(c=>{c.setValue(!!this.plugin.settings.features.vector_db).onChange(d=>{this.plugin.settings.features.vector_db=d,this.plugin.saveSettings(),this._vectorDepsOk=null,this._embedStatusText=null,this.display()})}),!this.plugin.settings.features.vector_db)return;let r=this.app.vault.adapter.basePath,n=e.createEl("div",{cls:"paperforge-vec-header"}),a=n.createEl("span",{text:"\u25BC",cls:"paperforge-skills-arrow"});n.createEl("span",{cls:"paperforge-vec-header-label",text:o("feat_vector_config_label")});let s=e.createEl("div",{cls:"paperforge-vector-config"}),l=c=>{s.style.display=c?"none":"",a.style.transform=c?"rotate(-90deg)":"rotate(0deg)"};if(l(Qe(this._featurePanelsCollapsed,"vectorConfig",!1)),n.addEventListener("click",()=>{let c=ft(this._featurePanelsCollapsed,"vectorConfig",!1);l(c)}),this._vectorDepsOk===!0){this._renderVectorReady(s,r);return}if(this._vectorDepsOk===!1){this._renderVectorNoDeps(s);return}if(this._vectorDepsOk===null){let c=Re(r);this._vectorDepsOk=c&&(i=c.deps_installed)!=null?i:!1,this._vectorDepsOk&&(this._embedStatusText=be(r)),this.display()}}_renderApiConfig(e){new C.Setting(e).setName(o("feat_openai_key")).setDesc(o("feat_openai_key_desc")).addText(t=>{t.setPlaceholder("sk-...").setValue(this.plugin.settings.vector_db_api_key||"").onChange(r=>{this.plugin.settings.vector_db_api_key=r,this.plugin.saveSettings()})}),new C.Setting(e).setName(o("feat_api_base_url")).setDesc(o("feat_api_base_url_desc")).addText(t=>{t.setPlaceholder("https://api.openai.com/v1").setValue(this.plugin.settings.vector_db_api_base||"").onChange(r=>{this.plugin.settings.vector_db_api_base=r,this.plugin.saveSettings()})}),new C.Setting(e).setName(o("feat_api_model")).setDesc(o("feat_api_model_desc")).addText(t=>{t.setPlaceholder("text-embedding-3-small").setValue(this.plugin.settings.vector_db_api_model||"text-embedding-3-small").onChange(r=>{this.plugin.settings.vector_db_api_model=r,this.plugin.saveSettings()})})}_renderVectorNoDeps(e){e.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_deps_missing")),new C.Setting(e).setName(o("feat_install_deps")).setDesc(o("feat_install_deps_desc")).addButton(r=>{r.setButtonText(o("feat_install_btn")).setCta().onClick(async()=>{let n=this.app.vault.adapter.basePath,a=ce(n,this.plugin.settings);if(!a.path){new C.Notice(o("feat_no_python"));return}r.setButtonText(o("feat_installing")),r.setDisabled(!0);let s="chromadb openai",l=new C.Notice(o("feat_installing_pkgs").replace("{pkgs}",s),0);try{let i=Object.assign({},process.env,{PYTHONIOENCODING:"utf-8",PYTHONUTF8:"1"}),c=s.split(" ");await new Promise((d,g)=>{(0,j.execFile)(a.path,[...a.extraArgs,"-m","pip","install",...c],{cwd:n,timeout:3e5,env:i,windowsHide:!0},p=>{p?g(p):d()})}),l.hide(),new C.Notice(o("feat_install_done")),this._vectorDepsOk=!0,this._embedStatusText=be(n),this.display()}catch(i){l.hide(),new C.Notice(o("feat_install_failed")+(i.stderr||i.message||i)),r.setButtonText(o("feat_retry_btn")),r.setDisabled(!1)}})})}_renderVectorReady(e,t){e.createEl("div",{cls:"paperforge-desc-box"}).setText(be(t)),this._renderApiConfig(e);let n=e.createEl("div",{cls:"paperforge-embed-section"});n.createEl("div",{cls:"paperforge-embed-header"}).createEl("span",{text:o("feat_rebuild_vectors"),cls:"setting-item-name"});let s=n.createEl("div",{cls:"paperforge-embed-controls"}),l=n.createEl("div",{cls:"paperforge-embed-status-text"});(()=>{var y,b,m;s.empty(),l.empty();let c=(Re(t)||{}).build_state||{};this.plugin._embedProgress=this.plugin._embedProgress||{current:0,total:0,key:""},!this.plugin._embedProcess&&c.status==="running"&&(this.plugin._embedProgress={current:c.current||0,total:c.total||1,key:c.paper_id||""});let{current:d,total:g,key:p}=this.plugin._embedProgress;if(!!this.plugin._embedProcess||c.status==="running"){let x=s.createEl("div",{cls:"paperforge-progress-track"});x.style.cssText="flex:1;";let w=g>0?(d/g*100).toFixed(1):"0",E=x.createEl("div",{cls:"paperforge-progress-seg done"});if(E.style.cssText=`width:${w}%; min-width:${d>0?"2px":"0"};`,d{this._callPython(["embed","stop","--json"],{timeout:8e3}),this.plugin._embedProcess&&(this.plugin._embedProcess.kill(),this.plugin._embedProcess=null),this.display()})}else{let x=Re(t),w=((y=x==null?void 0:x.chunk_count)!=null?y:0)+((b=x==null?void 0:x.body_chunk_count)!=null?b:0)+((m=x==null?void 0:x.object_chunk_count)!=null?m:0),E=w>0,_=x?!!x.corrupted:!1,v=S=>{if(!ce(t,this.plugin.settings).path){new C.Notice(o("feat_no_python"));return}let A=Object.assign({},process.env,{PYTHONIOENCODING:"utf-8",PYTHONUTF8:"1",VECTOR_DB_API_KEY:this.plugin.settings.vector_db_api_key||"",VECTOR_DB_API_BASE:this.plugin.settings.vector_db_api_base||"",VECTOR_DB_API_MODEL:this.plugin.settings.vector_db_api_model||""});this.plugin._embedStderr="",this.plugin._embedProgress={current:0,total:0,key:""},this.plugin._embedProcess=this._callPython(["embed","build",S],{stream:!0,env:A,onData:T=>{let I=T.toString("utf-8").split(` +`);for(let z of I)if(z.startsWith("EMBED_START:"))this.plugin._embedProgress.total=parseInt(z.split(":")[1])||0;else if(z.startsWith("EMBED_PROGRESS:")){let O=z.split(":");this.plugin._embedProgress.current=parseInt(O[1])||0,this.plugin._embedProgress.key=O[3]||""}else z.startsWith("EMBED_DONE")&&(this.plugin._embedProcess=null,this.plugin._embedProgress.current=this.plugin._embedProgress.total);this.display()},onStderr:T=>{this.plugin._embedStderr||(this.plugin._embedStderr=""),this.plugin._embedStderr+=T.toString("utf-8")},onError:T=>{this.plugin._embedProcess=null,new C.Notice(o("feat_build_failed")+": "+(T.message||T)),this.display()},onClose:T=>{if(this.plugin._embedProcess=null,T===0)this.plugin._embedProgress.current=this.plugin._embedProgress.total,this.plugin.saveSettings(),this._embedStatusText=be(t),new C.Notice(o("feat_build_complete"));else{this._embedStatusText=null;let I=(this.plugin._embedStderr||"").slice(0,200);new C.Notice(o("feat_build_failed")+(I?": "+I:""),8e3)}this.plugin._embedStderr="",this.display(),this._refreshSnapshots(t)}}),this.display()};if(_){let S=n.createEl("div");S.style.cssText="padding:8px 12px; margin:8px 0; background:var(--background-modifier-warning); border-radius:4px; font-size:12px; display:flex; align-items:center; justify-content:space-between;",S.createEl("span",{text:o("feat_vector_corrupted")});let P=S.createEl("button",{text:o("feat_vector_rebuild_force_btn")});P.className="mod-cta",P.addEventListener("click",()=>v("--force"))}E&&!_&&s.createEl("span",{text:w+" chunks embedded",cls:"setting-item-description"});let k=s.createEl("button");if(k.setText(E?o("feat_rebuild_btn"):o("feat_build_btn")),k.addClass("mod-cta"),k.addEventListener("click",()=>v("--resume")),!_&&E){let S=s.createEl("button");S.setText(o("feat_vector_rebuild_force_btn")),S.style.marginLeft="6px",S.addEventListener("click",()=>v("--force"))}}})()}_getCurrentModelKey(){return this.plugin.settings.vector_db_api_model||"text-embedding-3-small"}_parseEmbedStatus(e){let t={};return e&&(e.split(` +`).forEach(r=>{let n=r.match(/^\s*([^:]+):\s*(.*)/);n&&(t[n[1].trim()]=n[2].trim())}),t.db_exists!==void 0&&(t.db_exists=t.db_exists==="True"),t.chunk_count!==void 0&&(t.chunk_count=parseInt(t.chunk_count,10)||0)),t}_getPythonDesc(e,t){return t==="stale"?`[!!] ${e} (stale \u2014 path no longer exists, update or clear the override below)`:t==="manual"?`${e} (manual)`:`${e} (auto-detected)`}_refreshPythonInterpDesc(e,t){let r=this._pythonInterpDescEl;r&&(t==="stale"?r.textContent=`[!!] ${e} (stale \u2014 path no longer exists, update or clear the override below)`:t==="manual"?r.textContent=`${e} (manual)`:r.textContent=`${e} (auto-detected)`)}_validatePythonOverride(){let e=this.plugin.settings.python_path?this.plugin.settings.python_path.trim():"",t=this._customPathDescEl;if(!e){let r="\u8BF7\u8F93\u5165\u8DEF\u5F84 / Enter a path first";t&&(t.innerHTML=`\u2717 ${r}`),new C.Notice(r);return}if(!N.existsSync(e)){let r="\u8DEF\u5F84\u4E0D\u5B58\u5728 / Path does not exist";t&&(t.innerHTML=`\u2717 ${r}`),new C.Notice(r,4e3);return}try{N.accessSync(e,N.constants.X_OK)}catch(r){let n="\u4E0D\u53EF\u6267\u884C / Not executable";t&&(t.innerHTML=`\u2717 ${n}`),new C.Notice(n,4e3);return}(0,j.execFile)(e,["--version"],{timeout:8e3},(r,n)=>{if(r||!n){let i="\u65E0\u6CD5\u8FD0\u884C / Cannot run";t&&(t.innerHTML=`\u2717 ${i}`),new C.Notice(i,4e3);return}let a=n.match(/Python (\d+)\.(\d+)/);if(!a){let i="\u65E0\u6CD5\u89E3\u6790\u7248\u672C / Cannot parse version";t&&(t.innerHTML=`\u2717 ${i}`),new C.Notice(i,4e3);return}let s=parseInt(a[1],10),l=parseInt(a[2],10);if(s<3||s===3&&l<10){let i="Python \u7248\u672C\u8FC7\u4F4E\uFF0C\u9700\u8981 3.10+ / Python version too low, need 3.10+";t&&(t.innerHTML=`\u2717 ${i}`),new C.Notice(i,4e3);return}(0,j.execFile)(e,["-m","pip","--version"],{timeout:8e3},i=>{if(i){let c=`\u2713 Python ${s}.${l} \u6709\u6548\uFF0C\u4F46\u672A\u68C0\u6D4B\u5230 pip / Valid, but pip not found`;t&&(t.innerHTML=`\u26A0 ${c}`),new C.Notice(c,4e3)}else{let c=`\u2713 Python ${s}.${l} \u6709\u6548 / Valid`;t&&(t.innerHTML=`${c}`),new C.Notice(c,4e3)}})})}_syncRuntime(e){let t=this.app.vault.adapter.basePath,{path:r,extraArgs:n=[]}=L(t,this.plugin.settings,void 0,void 0),a=this.plugin.manifest.version,s=ct(r,a,n);e.setDisabled(!0),e.setButtonText(o("runtime_health_syncing"));let l=(c,d)=>(console.log(`[PaperForge] Sync Runtime: trying ${d}`),pt(s.cmd,c,t,s.timeout,void 0,me())),i=()=>{let c="opencode";try{let f=N.readFileSync(Z.join(t,"paperforge.json"),"utf-8"),y=JSON.parse(f);y.agent_key&&(c=y.agent_key)}catch(f){}let d=[...n,"-c",'from paperforge.services.skill_deploy import deploy_skills; from pathlib import Path; r=deploy_skills(vault=Path(r"'+t.replace(/\\/g,"\\\\")+'"), agent_key="'+c+'", overwrite=True); print("skills deployed" if r["skill_deployed"] else "skills skipped", flush=True)'],g=(0,j.spawn)(r,d,{cwd:t,timeout:3e4,windowsHide:!0}),p="";g.stdout.on("data",f=>{p+=f.toString("utf-8")}),g.on("close",f=>{console.log(`[PaperForge] Skill deploy: ${p.trim()} (exit ${f})`)})};l(s.pypiArgs,"PyPI").then(c=>{if(c.exitCode===0){console.log("[PaperForge] Sync Runtime: installed via PyPI"),i(),new C.Notice(o("runtime_health_sync_done").replace("{0}",a),5e3),this.display();return}console.warn("[PaperForge] Sync Runtime: PyPI failed, falling back to git..."),l(s.gitArgs,"git").then(d=>{d.exitCode===0?(console.log("[PaperForge] Sync Runtime: installed via git"),i(),new C.Notice(o("runtime_health_sync_done").replace("{0}",a),5e3),this.display()):(e.setDisabled(!1),e.setButtonText(o("runtime_health_sync")),console.error("[PaperForge] git fallback stderr:",d.stderr),new C.Notice(o("runtime_health_sync_fail").replace("{0}","pip exit code "+d.exitCode),8e3))})})}_debouncedSave(){clearTimeout(this._saveTimeout),this._saveTimeout=setTimeout(()=>this.plugin.saveSettings(),500)}_preCheck(e){var a;let t=this.app.vault.adapter.basePath,{path:r,extraArgs:n=[]}=L(t,(a=this.plugin)==null?void 0:a.settings,void 0,void 0);(0,j.execFile)(r,[...n,"--version"],{timeout:8e3},(s,l)=>{let i=[];i.push({label:"Python",ok:!s,detail:s?o("check_python_fail"):l.trim()});let c=!1,d=process.env.HOME||process.env.USERPROFILE||kt.homedir()||"";if(process.platform==="darwin")c=["/Applications/Zotero.app",Z.join(d,"Applications","Zotero.app")].some(x=>{try{return N.existsSync(x)}catch(w){return!1}});else if(process.platform==="win32"){let m=process.env.ProgramFiles||"",x=process.env.LOCALAPPDATA||"";c=[Z.join(m,"Zotero"),Z.join(m,"(x86)","Zotero"),Z.join(x,"Programs","Zotero"),Z.join(x,"Zotero"),Z.join(d,"AppData","Local","Programs","Zotero")].filter(Boolean).some(E=>{try{return N.existsSync(E)}catch(_){return!1}})}else c=[Z.join(d,".local","share","zotero","zotero"),"/usr/bin/zotero","/usr/local/bin/zotero"].some(x=>{try{return N.existsSync(x)}catch(w){return!1}});let g=this.plugin.settings.zotero_data_dir;if(!c&&g)try{c=N.existsSync(g)}catch(m){}i.push({label:"Zotero",ok:c,detail:c?o("check_zotero_ok"):o("check_zotero_fail")});let p=!1,f=process.env.APPDATA||"";process.platform==="win32"&&f&&(p=Me(Z.join(f,"Zotero","Zotero","Profiles"))),!p&&process.platform==="darwin"&&d&&(p=Me(Z.join(d,"Library","Application Support","Zotero","Profiles"))),!p&&process.platform!=="win32"&&process.platform!=="darwin"&&d&&(p=Me(Z.join(d,".zotero","zotero","Profiles"))),!p&&g&&String(g).trim()&&(p=Ge(g.trim())),!p&&d&&(p=Ge(Z.join(d,"Zotero"))),i.push({label:"Better BibTeX",ok:p,detail:p?o("check_bbt_ok"):o("check_bbt_fail")});let y={true:"\u2713",false:"\u2717"};if(this._checkEl){this._checkEl.setText(i.map(x=>`${y[String(x.ok)]} ${x.label}: ${x.detail}`).join(` +`));let m=i.some(x=>!x.ok);this._checkEl.className=`paperforge-message msg-${m?"error":"ok"}`}let b=i.filter(m=>!m.ok);b.length>0&&new C.Notice(`[!!] \u672A\u901A\u8FC7: ${b.map(m=>m.label).join(", ")}`,6e3),e()})}_renderMaintenanceTab(e){e.createEl("h2",{text:o("tab_maintenance")||"\u7EF4\u62A4"});let t=this.app.vault.adapter.basePath,r=e.createEl("div"),n=(g,p)=>p==="retry_ocr"||p==="upgrade_legacy"?{cmd:["-m","paperforge","ocr","redo",...g],timeout:3e5}:p==="rebuild_result"?{cmd:["-m","paperforge","ocr","rebuild",...g],timeout:12e4}:null,a=null;try{a=xt(t)}catch(g){}let s=L(t,this.plugin.settings,N,j.execFileSync);if(!s.path){r.createEl("p",{text:"\u26A0 Python \u672A\u914D\u7F6E\uFF0C\u8BF7\u5148\u5728\u300C\u5B89\u88C5\u300D\u6807\u7B7E\u9875\u914D\u7F6E\u3002",cls:"setting-item-description"});return}let l=g=>{r.empty();let p=g.filter(m=>m.visible_in_maintenance);if(p.length===0){r.createEl("p",{text:o("maintenance_all_good")||"\u2705 \u5168\u90E8\u6B63\u5E38"});return}let f=s.path,y=s.extraArgs||[],b=[{key:"retry",title:o("maintenance_group_retry")||"\u9700\u8981\u91CD\u8BD5",items:[]},{key:"rebuild",title:o("maintenance_group_rebuild")||"\u53EF\u91CD\u5EFA\u7ED3\u679C",items:[]},{key:"legacy_optional",title:o("maintenance_group_legacy")||"\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09",items:[]}];for(let m of p){let x=b.find(w=>w.key===m.display_group);x&&x.items.push(m)}for(let m of b){if(m.items.length===0)continue;let x=m.key==="legacy_optional",w=x?r.createEl("details"):r.createEl("div");x?w.createEl("summary").createEl("strong",{text:m.title+" ("+m.items.length+")"}):w.createEl("h3",{text:m.title+" ("+m.items.length+")"});let E=new Map;for(let F of m.items)E.set(F.key,!1);let _=w.createEl("div",{cls:"pf-maint-toolbar"}),v=_.createEl("button",{text:"\u5168\u9009"}),k=_.createEl("button",{text:"\u53D6\u6D88\u5168\u9009"}),S=_.createEl("button",{text:"\u25B6 \u6267\u884C\u5DF2\u9009",cls:"mod-cta"}),P=_.createEl("span",{cls:"pf-maint-exec-label"}),A=()=>{let F=m.items.filter(D=>E.get(D.key)).length;P.setText("\u5DF2\u9009 "+F+" \u7BC7")};A(),v.addEventListener("click",()=>{for(let D of m.items)E.set(D.key,!0);A(),w.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach(D=>{D.checked=!0})}),k.addEventListener("click",()=>{for(let D of m.items)E.set(D.key,!1);A(),w.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach(D=>{D.checked=!1})}),S.addEventListener("click",()=>{let F=m.items.filter(D=>E.get(D.key));if(F.length===0){new C.Notice("\u8BF7\u5148\u9009\u62E9\u8981\u5904\u7406\u7684\u8BBA\u6587\u3002");return}for(let D of F){let X=n([D.key],D.display_action);X&&(0,j.execFile)(f,[...y,...X.cmd],{cwd:t,timeout:X.timeout,windowsHide:!0},()=>{new C.Notice(D.display_label+" \u2014 "+D.key)})}});let I=w.createEl("div",{cls:"pf-maint-table-wrap"}).createEl("table",{cls:"pf-maint-table"}),z=I.createEl("thead"),O=I.createEl("tbody"),U=z.insertRow();["","Key","Title","\u5EFA\u8BAE\u64CD\u4F5C","\u539F\u56E0","\u64CD\u4F5C"].forEach(F=>{let D=document.createElement("th");D.textContent=F,U.appendChild(D)});let q=F=>F==="retry_ocr"?o("maintenance_btn_retry")||"\u91CD\u8BD5":F==="rebuild_result"?o("maintenance_btn_rebuild")||"\u91CD\u5EFA":F==="upgrade_legacy"?o("maintenance_btn_upgrade")||"\u5347\u7EA7":"";for(let F of m.items){let D=O.insertRow(),X=D.insertCell();X.style.cssText="padding:3px 4px;text-align:center;";let ee=document.createElement("input");ee.type="checkbox",ee.className="pf-maint-sel",ee.checked=E.get(F.key)||!1,ee.addEventListener("change",()=>{E.set(F.key,ee.checked),A()}),X.appendChild(ee);let oe=D.insertCell();oe.style.cssText="padding:3px 4px;white-space:nowrap;font-size:11px;max-width:90px;overflow:hidden;text-overflow:ellipsis;",oe.textContent=F.key;let ve=D.insertCell();ve.style.cssText="padding:3px 4px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis;",ve.textContent=F.title||F.key;let de=D.insertCell();de.style.cssText="padding:3px 4px;white-space:nowrap;",de.textContent=F.display_label;let we=D.insertCell();we.style.cssText="padding:3px 4px;white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis;font-size:11px;color:var(--text-muted);",we.textContent=F.display_reason||"";let Se=D.insertCell();Se.style.cssText="padding:3px 4px;text-align:center;white-space:nowrap;";let ge=document.createElement("button");ge.textContent=q(F.display_action),ge.textContent&&(ge.addEventListener("click",()=>{let R=n([F.key],F.display_action);R&&(0,j.execFile)(f,[...y,...R.cmd],{cwd:t,timeout:R.timeout,windowsHide:!0},()=>{new C.Notice(F.display_label+" \u2014 "+F.key)})}),Se.appendChild(ge))}}};if(a){let g=Object.values(a.papers);l(g)}else r.createEl("p",{text:"\u6B63\u5728\u52A0\u8F7D OCR \u7EF4\u62A4\u6570\u636E\u2026"});Et(t,s.path,s.extraArgs||[],a||null).then(g=>{g.changed?(l(g.data),$e(t,{manifest:{},papers:Object.fromEntries(g.data.map(p=>[p.key,p])),cached_at:new Date().toISOString()})):a||(l(g.data),$e(t,{manifest:{},papers:Object.fromEntries(g.data.map(p=>[p.key,p])),cached_at:new Date().toISOString()}))}).catch(()=>{a||(r.empty(),r.createEl("p",{text:"\u65E0\u6CD5\u52A0\u8F7D OCR \u6570\u636E\u3002\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 paperforge \u5E76\u8FD0\u884C\u8FC7 OCR\u3002",cls:"setting-item-description"}))}),e.createEl("hr"),e.createEl("h3",{text:"\u5168\u5C40\u64CD\u4F5C"});let i=e.createEl("div",{cls:"pf-maint-global"});i.createEl("button",{text:"\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15"}).addEventListener("click",()=>{new C.Notice("\u6B63\u5728\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15\u2026"),(0,j.execFile)(s.path,[...s.extraArgs||[],"-m","paperforge","embed","build","--force"],{cwd:t,timeout:3e5,windowsHide:!0},()=>{new C.Notice("\u641C\u7D22\u7D22\u5F15\u91CD\u5EFA\u5B8C\u6210\u3002")})}),i.createEl("button",{text:"\u91CD\u5EFA\u8BB0\u5FC6\u5E93"}).addEventListener("click",()=>{new C.Notice("\u6B63\u5728\u91CD\u5EFA\u8BB0\u5FC6\u5E93\u2026"),(0,j.execFile)(s.path,[...s.extraArgs||[],"-m","paperforge","repair","--fix"],{cwd:t,timeout:12e4,windowsHide:!0},()=>{new C.Notice("\u8BB0\u5FC6\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002")})})}_renderReleaseNotesTab(e){e.createEl("h2",{text:"\u66F4\u65B0\u4E0E\u624B\u518C"}),e.createEl("h3",{text:"\u7248\u672C\u66F4\u65B0\u8BB0\u5F55"});let t=wt.default.versions||[];for(let a of t){let s=e.createEl("div",{cls:"paperforge-release-card"}),l=s.createEl("div",{cls:"paperforge-release-header"});if(l.createEl("strong",{text:`v${a.version} \u2014 ${a.title}`}),l.createEl("span",{cls:"paperforge-release-date",text:` (${a.date})`}),a.breaking_or_migration&&a.breaking_or_migration.length>0){let i=s.createEl("div",{cls:"paperforge-release-section"});i.createEl("div",{cls:"paperforge-release-label",text:"\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F"});for(let c of a.breaking_or_migration)i.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.new_features&&a.new_features.length>0){let i=s.createEl("div",{cls:"paperforge-release-section"});i.createEl("div",{cls:"paperforge-release-label",text:"\u65B0\u529F\u80FD"});for(let c of a.new_features)i.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.fixes&&a.fixes.length>0){let i=s.createEl("div",{cls:"paperforge-release-section"});i.createEl("div",{cls:"paperforge-release-label",text:"\u4FEE\u590D"});for(let c of a.fixes)i.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.recommended_actions&&a.recommended_actions.length>0){let i=s.createEl("div",{cls:"paperforge-release-section paperforge-release-recommended"});i.createEl("div",{cls:"paperforge-release-label",text:"\u5EFA\u8BAE\u64CD\u4F5C"});for(let c of a.recommended_actions)i.createEl("div",{cls:"paperforge-release-item paperforge-release-item-bold",text:`\u2022 ${c}`})}}e.createEl("h3",{text:"\u4F7F\u7528\u624B\u518C"}),e.createEl("div",{cls:"paperforge-manual-links"}).createEl("a",{text:"\u2192 \u67E5\u770B\u5B8C\u6574\u4F7F\u7528\u624B\u518C\uFF08GitHub\uFF09",href:"https://github.com/LLLin000/PaperForge/blob/master/docs/user-manual.md"}).setAttr("target","_blank")}};var B=require("obsidian"),pe=$(require("fs")),Oe=$(require("path")),fe=require("child_process");var Be=$(require("path"));function St(h){if(!h)return null;let u=Be.dirname(h);for(;;){let e=Be.basename(u);if(!e||e===".")break;let t=e.match(/^([A-Z0-9]{8})(?:\s*-\s*.*)?$/i);if(t)return t[1];let r=Be.dirname(u);if(r===u)break;u=r}return null}var V=$(require("fs")),he=$(require("path"));function Ae(h){return Q(h).ocrDir}function jt(h,u){let e=he.join(Ae(h),u,"versions","manifest.json");try{if(!V.existsSync(e))return null;let t=V.readFileSync(e,"utf-8"),r=JSON.parse(t);if(r&&typeof r=="object"&&"versions"in r&&"current"in r){let n=r,a=n.versions,s=n.current;if(Array.isArray(a)&&s&&typeof s=="object"&&"label"in s)return r}return null}catch(t){return null}}function Ht(h){let u=Ae(h);try{return V.existsSync(u)?V.readdirSync(u,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name):[]}catch(e){return[]}}function tt(h){let u=Ht(h),e=[];for(let t of u){let r=jt(h,t);if(!r)continue;let n=r.versions.map(s=>s.label),a=0;for(let s of n){let l=he.join(Ae(h),t,"versions",s,"fulltext.md");try{V.existsSync(l)&&(a+=V.statSync(l).size)}catch(i){}}e.push({key:t,title:t.replace(/_/g," "),versions:r.versions,currentLabel:r.current.label,totalSize:a})}return e.sort((t,r)=>t.title.localeCompare(r.title)),e}function Ct(h,u,e){let t=Ae(h),r=he.join(t,u,"versions",e,"fulltext.md"),n=he.join(t,u,"render"),a=he.join(n,"fulltext.md");try{return V.existsSync(r)?(V.existsSync(n)||V.mkdirSync(n,{recursive:!0}),V.copyFileSync(r,a),!0):!1}catch(s){return!1}}function Ft(h,u,e,t){var p;let r=Ae(h),n=he.join(r,u,"versions",e,"fulltext.md"),a=he.join(r,u,"versions",t,"fulltext.md"),s="",l="";try{V.existsSync(n)&&(s=V.readFileSync(n,"utf-8"))}catch(f){}try{V.existsSync(a)&&(l=V.readFileSync(a,"utf-8"))}catch(f){}let i=Pt(s),c=Pt(l),d=Math.max(i.length,c.length),g=[];for(let f=0;f0)e.push(t.join(` +`).trim()),t=[r];else if(r.trim()===""&&t.length>0){let n=t.join(` +`).trim();n&&(e.push(n),t=[])}else t.push(r);if(t.length>0){let r=t.join(` +`).trim();r&&e.push(r)}return e}var Ee=class extends B.ItemView{constructor(e){super(e);this._currentMode=null;this._currentDomain=null;this._currentPaperKey=null;this._currentPaperEntry=null;this._currentFilePath=null;this._cachedItems=null;this._modeSubscribers=[];this._leafChangeTimer=null;this._ocrPrivacyShown=!1;this._cachedStats=null;this._techDetailsExpanded=!1;this._paperforgeVersion="";this._dashboardPermissions={};this._headerTitle=null;this._versionBadge=null;this._messageEl=null;this._metricsEl=null;this._ocrSection=null;this._ocrEmpty=null;this._ocrBadge=null;this._ocrTrack=null;this._ocrCounts=null;this._driftBannerEl=null;this._versionPapers=null;this._versionFilter="";this._searchContainer=null;this._searchInput=null;this._searchResultsEl=null;this._searchTimer=void 0;this._currentMode=null,this._currentDomain=null,this._currentPaperKey=null,this._currentPaperEntry=null,this._currentFilePath=null,this._cachedItems=null,this._modeSubscribers=[],this._leafChangeTimer=null,this._ocrPrivacyShown=!1}getViewType(){return _e}getDisplayText(){return"PaperForge"}getIcon(){return Ce}async onOpen(){this._buildPanel(),this._modeSubscribers=[],this._leafChangeTimer=null,this._setupEventSubscriptions(),this._fetchVersion(),this._detectAndSwitch()}async onClose(){if(this._modeSubscribers&&this._modeSubscribers.length>0){for(let e of this._modeSubscribers)e.event==="active-leaf-change"?this.app.workspace.off("active-leaf-change",e.ref):e.event==="modify"&&this.app.vault.off("modify",e.ref);this._modeSubscribers=[]}this._leafChangeTimer&&(clearTimeout(this._leafChangeTimer),this._leafChangeTimer=null),this._cachedItems=null,this._cachedStats=null}_buildPanel(){let e=this.containerEl;e.empty(),e.addClass("paperforge-status-panel");let t=e.createEl("div",{cls:"paperforge-header"}),r=t.createEl("div",{cls:"paperforge-header-left"});r.createEl("div",{cls:"paperforge-header-logo",text:"P"}),this._modeContextEl=r.createEl("div",{cls:"paperforge-mode-context"}),this._headerTitle=r.createEl("h3",{cls:"paperforge-header-title",text:"PaperForge"}),this._versionBadge=r.createEl("span",{cls:"paperforge-header-badge",text:"v\u2014"});let n=t.createEl("button",{cls:"paperforge-header-refresh",attr:{"aria-label":"Refresh"}});n.innerHTML="\u21BB",n.addEventListener("click",()=>{this._invalidateIndex(),this._detectAndSwitch()}),this._messageEl=e.createEl("div",{cls:"paperforge-message"}),this._contentEl=e.createEl("div",{cls:"paperforge-content-area"})}_fetchVersion(){var s,l;let e=this.app.vault.adapter.basePath,t=this.app.plugins.plugins.paperforge,r=((s=t==null?void 0:t.manifest)==null?void 0:s.version)||"?",{path:n,extraArgs:a=[]}=L(e,(l=t==null?void 0:t.settings)!=null?l:null,void 0,void 0);lt(n,r,e,1e4,void 0).then(i=>{if(i.status==="not-installed")return;let c=i.pyVersion||"";this._paperforgeVersion=c.startsWith("v")?c:"v"+c,this._versionBadge&&this._versionBadge.setText(this._paperforgeVersion),this._driftBannerEl&&r&&this._paperforgeVersion!=="v"+r.replace(/^v/,"")?(this._driftBannerEl.style.display="block",this._driftBannerEl.setText(o("dashboard_drift_warning").replace("{0}",this._paperforgeVersion).replace("{1}","v"+r.replace(/^v/,"")))):this._driftBannerEl&&(this._driftBannerEl.style.display="none")})}_fetchStats(e){var s;if(!this._metricsEl)return;if(!e&&!this._cachedStats)this._metricsEl.empty(),this._metricsEl.createEl("div",{cls:"paperforge-status-loading",text:"Loading..."});else if(e&&!this._cachedStats)return;let t=this.app.vault.adapter.basePath,r=this.app.plugins.plugins.paperforge,{path:n,extraArgs:a=[]}=L(t,(s=r==null?void 0:r.settings)!=null?s:null,void 0,void 0);(0,fe.execFile)(n,[...a,"-m","paperforge","dashboard","--json"],{cwd:t,timeout:3e4},(l,i)=>{if(!l)try{let c=JSON.parse(i);if(c.ok&&c.data){let d=this._normalizeDashboardData(c.data);this._cachedStats=d,this._metricsEl.empty(),this._renderStats(d),this._renderOcr(d),this._dashboardPermissions=c.data.permissions||{};return}}catch(c){}this._fallbackFetchStats(e,t,r)})}_normalizeDashboardData(e){let t=e.stats||{},r=t.ocr_health||{},n=t.pdf_health||{},a=e.ocr_version_state||{},s=(r.done||0)+(r.pending||0)+(r.failed||0);return{total_papers:t.papers||0,formal_notes:t.papers||0,exports:0,bases:0,ocr:{total:s,pending:r.pending||0,processing:0,done:r.done||0,failed:r.failed||0},path_errors:(n.broken||0)+(n.missing||0),ocr_version_state:{total_papers:a.total_papers||0,derived_stale_count:a.derived_stale_count||0,raw_upgradable_count:a.raw_upgradable_count||0}}}_fallbackFetchStats(e,t,r){var s,l,i;let n=((s=r==null?void 0:r.settings)==null?void 0:s.system_dir)||"System",a=Oe.join(t,n,"PaperForge","indexes","formal-library.json");try{let c=pe.readFileSync(a,"utf-8"),d=JSON.parse(c),g=d.items||[],p={},f={pdf_health:{healthy:0,unhealthy:0},ocr_health:{healthy:0,unhealthy:0},note_health:{healthy:0,unhealthy:0},asset_health:{healthy:0,unhealthy:0}},y=0,b=0,m=0,x=0,w=0,E=0;for(let _ of g){_.note_path&&E++;let v=_.lifecycle||"pdf_ready";p[v]=(p[v]||0)+1;let k=_.health||{};for(let P of["pdf_health","ocr_health","note_health","asset_health"])(k[P]||"healthy")==="healthy"?f[P].healthy++:f[P].unhealthy++;let S=_.ocr_status||"";y++,S==="done"?b++:S==="pending"?m++:S==="processing"||S==="queued"||S==="running"?x++:w++}this._cachedStats={version:d.paperforge_version||((l=this._cachedStats)==null?void 0:l.version)||"\u2014",total_papers:g.length,formal_notes:E,exports:0,bases:0,ocr:{total:y,pending:m,processing:x,done:b,failed:w},path_errors:0,lifecycle_level_counts:p,health_aggregate:f},this._metricsEl.empty(),this._renderStats(this._cachedStats),this._renderOcr(this._cachedStats)}catch(c){!e&&!this._cachedStats&&this._metricsEl.createEl("div",{cls:"paperforge-status-loading",text:"No index \u2014 trying CLI..."});let{path:d,extraArgs:g=[]}=L(t,(i=r==null?void 0:r.settings)!=null?i:null,void 0,void 0);(0,fe.execFile)(d,[...g,"-m","paperforge","status","--json"],{cwd:t,timeout:3e4},(p,f)=>{if(p){if(this._cachedStats)return;this._metricsEl.createEl("div",{cls:"paperforge-status-error",text:`Cannot reach PaperForge CLI. +Make sure paperforge is installed and in your PATH.`});return}try{let y=JSON.parse(f);this._cachedStats=y,this._metricsEl.empty(),this._renderStats(y),this._renderOcr(y)}catch(y){this._cachedStats||this._metricsEl.createEl("div",{cls:"paperforge-status-error",text:"Invalid response from paperforge status."})}})}}_renderSkeleton(e){e.addClass("paperforge-loading")}_renderEmptyState(e,t){e.createEl("div",{cls:"paperforge-empty-state",text:t||"No data"})}_buildMetricBar(e,t,r){if(r<=0)return;let n=Math.min(100,t/r*100);e.createEl("div",{cls:"paperforge-metric-progress"}).createEl("div",{cls:"paperforge-metric-progress-fill",attr:{style:`width:${n.toFixed(1)}%`}})}_loadIndex(){var a;let e=this.app.vault.adapter.basePath,t=this.app.plugins.plugins.paperforge,r=((a=t==null?void 0:t.settings)==null?void 0:a.system_dir)||"System",n=Oe.join(e,r,"PaperForge","indexes","formal-library.json");try{let s=pe.readFileSync(n,"utf-8");return JSON.parse(s)}catch(s){return null}}_getCachedIndex(){if(!this._cachedItems){let e=this._loadIndex();this._cachedItems=e?e.items||[]:[]}return this._cachedItems}_findEntry(e){if(!e)return null;let t=this._getCachedIndex().find(r=>r.zotero_key===e)||null;return nt(this.app,t)}_patchCachedEntry(e,t){if(!e||!this._cachedItems)return;let r=this._cachedItems.findIndex(n=>n.zotero_key===e);r!==-1&&(this._cachedItems[r]=Ke(this._cachedItems[r],t))}_filterByDomain(e){return e?this._getCachedIndex().filter(t=>t.domain===e):[]}_renderStats(e){var s;if(this._versionBadge&&this._versionBadge.setText(this._paperforgeVersion||(e.version?"v"+e.version:"v\u2014")),!e||typeof e.total_papers=="undefined"){this._metricsEl&&this._renderSkeleton(this._metricsEl);return}if(!this._metricsEl)return;this._metricsEl.removeClass("paperforge-loading");let t=e.total_papers||0,r=e.formal_notes||0,n=[{value:t,label:"Papers",color:"var(--color-cyan)",barMax:0},{value:r,label:"Formal Notes",color:"var(--color-blue)",barMax:t},{value:e.exports||0,label:"Exports",color:"var(--color-purple)",barMax:0}];for(let l of n){let i=this._metricsEl.createEl("div",{cls:"paperforge-metric-card"});i.style.setProperty("--metric-color",l.color),i.createEl("div",{cls:"paperforge-metric-value",text:((s=l.value)==null?void 0:s.toString())||"\u2014"}),i.createEl("div",{cls:"paperforge-metric-label",text:l.label}),l.barMax>0&&this._buildMetricBar(i,l.value,l.barMax)}let a=e.ocr_version_state||{};if(a.total_papers>0&&(a.derived_stale_count>0||a.raw_upgradable_count>0)){let l=[];a.derived_stale_count>0&&l.push(`${a.derived_stale_count} stale`),a.raw_upgradable_count>0&&l.push(`${a.raw_upgradable_count} upgradable`);let i=this._metricsEl.createEl("div",{cls:"paperforge-metric-card"});i.style.setProperty("--metric-color","var(--color-yellow)"),i.createEl("div",{cls:"paperforge-metric-value",text:l.join(", ")}),i.createEl("div",{cls:"paperforge-metric-label",text:"OCR Version"})}}_renderOcr(e){if(!this._ocrSection)return;let t=e.ocr||{},r=t.total||0;if(r===0){this._ocrSection.style.display="none";return}this._ocrSection.style.display="block",this._ocrEmpty&&(this._ocrEmpty.style.display="none");let n=t.done||0,a=t.pending||0,s=t.processing||0,l=t.failed||0;if(this._ocrBadge&&(this._ocrBadge.removeClass("active","idle"),s>0?(this._ocrBadge.addClass("active"),this._ocrBadge.setText("Processing")):a>0?(this._ocrBadge.addClass("idle"),this._ocrBadge.setText("Pending")):(this._ocrBadge.addClass("idle"),this._ocrBadge.setText("Idle"))),this._ocrTrack){this._ocrTrack.empty(),s>0?this._ocrTrack.addClass("paperforge-processing"):this._ocrTrack.removeClass("paperforge-processing");let i=[{cls:"pending",count:a},{cls:"active",count:s},{cls:"done",count:n},{cls:"failed",count:l}];for(let c of i)if(c.count>0){let d=(c.count/r*100).toFixed(1);this._ocrTrack.createEl("div",{cls:`paperforge-progress-seg ${c.cls}`,attr:{style:`width:${d}%`}})}}if(this._ocrCounts){this._ocrCounts.empty();let i=[{cls:"pending",value:a,label:"Pending"},{cls:"active",value:s,label:"Processing"},{cls:"done",value:n,label:"Done"},{cls:"failed",value:l,label:"Failed"}];for(let c of i){let d=this._ocrCounts.createEl("div",{cls:"paperforge-ocr-count"});d.createEl("div",{cls:"paperforge-ocr-count-value",text:c.value.toString()}),d.createEl("div",{cls:"paperforge-ocr-count-label",text:c.label})}}}_renderLifecycleStepper(e,t,r){if(!t||!r){this._renderSkeleton(e);return}let n=[{key:"indexed",label:"Indexed"},{key:"pdf_ready",label:"PDF Ready"},{key:"fulltext_ready",label:"Fulltext Ready"},{key:"deep_read_done",label:"Deep Read"}],a=e.createEl("div",{cls:"paperforge-lifecycle-stepper"}),s=!1;for(let l of n){let i=a.createEl("div",{cls:"step"});i.createEl("div",{cls:"step-indicator"}),i.createEl("div",{cls:"step-label",text:l.label}),l.key===r?(i.addClass("current"),s=!0):s?i.addClass("pending"):i.addClass("completed")}}_renderHealthMatrix(e,t){if(!t){this._renderSkeleton(e);return}let r=[{key:"pdf_health",label:"PDF Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"ocr_health",label:"OCR Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"note_health",label:"Note Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"asset_health",label:"Asset Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"}],n=e.createEl("div",{cls:"paperforge-health-matrix"});for(let a of r){let s=t[a.key]||"healthy",l=n.createEl("div",{cls:"paperforge-health-cell"}),i,c,d;s==="healthy"||s==="ok"?(i=a.iconOk,c="ok",d=`${a.label}: OK`):s==="warn"||s==="warning"||s==="degraded"?(i=a.iconWarn,c="warn",d=`${a.label}: Needs Attention`):(i=a.iconFail,c="fail",d=`${a.label}: Failed`),l.addClass(c),l.setAttribute("title",d),l.createEl("div",{cls:"paperforge-health-cell-icon",text:i}),l.createEl("div",{cls:"paperforge-health-cell-label",text:a.label})}}_renderMaturityGauge(e,t,r){if(t==null||t===void 0){this._renderSkeleton(e);return}let n=e.createEl("div",{cls:"paperforge-maturity-gauge"}),a=n.createEl("div",{cls:"gauge-track"}),s=4,l=Math.max(1,Math.min(s,Math.round(t)));for(let i=1;i<=s;i++){let c=a.createEl("div",{cls:"gauge-segment"});i<=l&&(c.addClass("filled"),c.addClass(`level-${i}`))}if(n.createEl("div",{cls:"gauge-level",text:`Level ${l} / ${s}`}),l0){let c=n.createEl("ul",{cls:"gauge-blockers"});for(let d of i)c.createEl("li",{text:d})}}}_renderBarChart(e,t){if(!t||Object.keys(t).length===0){this._renderEmptyState(e,"No lifecycle data");return}let r=[{key:"indexed",label:"Indexed",cls:"stage-indexed"},{key:"pdf_ready",label:"PDF Ready",cls:"stage-pdf-ready"},{key:"fulltext_ready",label:"Fulltext Ready",cls:"stage-fulltext-ready"},{key:"deep_read_done",label:"Deep Read",cls:"stage-deep-read"}],n=e.createEl("div",{cls:"paperforge-bar-chart"}),a=Math.max(1,...r.map(s=>t[s.key]||0));for(let s of r){let l=t[s.key]||0,i=l/a*100,c=n.createEl("div",{cls:"bar-row"});c.createEl("div",{cls:"bar-label",text:s.label}),c.createEl("div",{cls:"bar-track"}).createEl("div",{cls:`bar-fill ${s.cls}`,attr:{style:`width:${i.toFixed(1)}%`}}),c.createEl("div",{cls:"bar-count",text:l.toString()})}}_invalidateIndex(){this._cachedItems=null}_extractZoteroKeyFromPath(e){return St(e)}_resolveModeForFile(e){if(!e)return{mode:"global",filePath:null,key:null,domain:null};let t=e.extension,r=e.path;if(t==="base")return{mode:"collection",filePath:r,key:null,domain:e.basename.trim()};if(t==="md"){let a=this.app.metadataCache.getFileCache(e),s=a&&a.frontmatter&&a.frontmatter.zotero_key;if(s)return{mode:"paper",filePath:r,key:s,domain:null}}if(t==="pdf"){let a=this._getCachedIndex();for(let s of a){let l=(s.pdf_path||"").match(/\[\[([^\]]+)\]\]/);if((l?l[1]:s.pdf_path)===r)return{mode:"paper",filePath:r,key:s.zotero_key,domain:null}}}let n=this._extractZoteroKeyFromPath(r);return n?{mode:"paper",filePath:r,key:n,domain:null}:{mode:"global",filePath:r,key:null,domain:null}}_detectAndSwitch(){let e=this._resolveModeForFile(this.app.workspace.getActiveFile());this._currentDomain=e.domain||null,this._currentPaperKey=e.key||null,this._currentPaperEntry=e.key?this._findEntry(e.key):null,this._switchMode(e.mode,e.filePath)}_switchMode(e,t){if(this._currentMode===e&&this._currentFilePath===t){this._refreshCurrentMode();return}if(this._currentMode=e,this._currentFilePath=t,this._techDetailsExpanded=!1,!!this._contentEl)switch(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader(e),e){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}_renderGlobalMode(){var ee,oe,ve,de,we,Se,ge;if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-global-view"});this._driftBannerEl=e.createEl("div",{cls:"paperforge-drift-banner"}),this._driftBannerEl.style.display="none";let t=this._getCachedIndex(),r=t.length,n=0,a=0,s=0;for(let R of t)R.has_pdf&&n++,R.ocr_status==="done"&&a++,R.deep_reading_status==="done"&&s++;let l=e.createEl("div",{cls:"paperforge-library-snapshot"});l.createEl("div",{cls:"paperforge-section-label",text:"Library Snapshot"});let i=l.createEl("div",{cls:"paperforge-snapshot-pills"}),c=[{value:r,label:"papers"},{value:n,label:"PDFs ready"},{value:a,label:"OCR done"},{value:s,label:"deep-read done"}];for(let R of c){let M=i.createEl("div",{cls:"paperforge-snapshot-pill"});M.createEl("span",{cls:"paperforge-snapshot-value",text:String(R.value)}),M.createEl("span",{cls:"paperforge-snapshot-label",text:" "+R.label})}let d=e.createEl("div",{cls:"paperforge-system-status"});d.createEl("div",{cls:"paperforge-section-label",text:"System Status"});let g=d.createEl("div",{cls:"paperforge-status-grid"}),p=this.app.plugins.plugins.paperforge,f=((ee=p==null?void 0:p.manifest)==null?void 0:ee.version)||"?",y=this._paperforgeVersion;if(!y)try{let R=this.app.vault.adapter.basePath,{path:M,extraArgs:re=[]}=L(R,(oe=p==null?void 0:p.settings)!=null?oe:null,void 0,void 0),J=(0,fe.execFileSync)(M,[...re,"-c","import paperforge; print(paperforge.__version__)"],{cwd:R,timeout:5e3,encoding:"utf-8",windowsHide:!0}).trim();J&&(y=J.startsWith("v")?J:"v"+J,this._paperforgeVersion=y)}catch(R){}y=y||"\u2014";let b=y==="v"+f;this._renderSystemStatusRow(g,"Runtime",b?"healthy":"mismatch",b?"v"+f:"plugin v"+f+" \u2260 CLI "+y);let m=this._loadIndex(),x=m&&m.items&&m.items.length>0;this._renderSystemStatusRow(g,"Index",x?"healthy":"missing",x?m.items.length+" entries":"formal-library.json not found");let w=((ve=p==null?void 0:p.settings)==null?void 0:ve.system_dir)||"System",E=this.app.vault.adapter.basePath,_=!1,v="No exports found";try{let R=Oe.join(E,w,"PaperForge","exports");if(pe.existsSync(R)){let M=pe.readdirSync(R).filter(re=>re.endsWith(".json"));_=M.length>0,v=_?M.length+" export(s)":"No JSON exports"}}catch(R){}this._renderSystemStatusRow(g,"Zotero Export",_?"healthy":"missing",v);let k=!!((de=p==null?void 0:p.settings)!=null&&de.paddleocr_api_key);if(!k)try{let R=((we=p==null?void 0:p.settings)==null?void 0:we.system_dir)||"System",M=Oe.join(E,R,"PaperForge",".env");if(pe.existsSync(M)){let J=pe.readFileSync(M,"utf-8").match(/^PADDLEOCR_API_TOKEN\s*=\s*(.+)$/m);k=!!(J&&J[1]&&J[1].trim())}}catch(R){}k||(k=!!(process.env.PADDLEOCR_API_TOKEN||process.env.PADDLEOCR_API_KEY||process.env.OCR_TOKEN)),this._renderSystemStatusRow(g,"OCR Token",k?"configured":"missing",k?"Configured":"Not set");let S=!1,P="",A=this.app.vault.adapter.basePath,T=Ye(A);S=ht(A),P=T&&((Se=T.summary)==null?void 0:Se.reason)||T&&((ge=T.summary)==null?void 0:ge.status)||"Unknown",this._renderSystemStatusRow(g,"Memory Layer",S?"healthy":"fail",P);let I=!b&&y!=="\u2014";if(I||!x||!_||!k){let R=e.createEl("div",{cls:"paperforge-issue-summary"});R.createEl("div",{cls:"paperforge-section-label",text:"\u9700\u8981\u5904\u7406"});let M=R.createEl("div",{cls:"paperforge-issue-list"});I&&M.createEl("div",{cls:"paperforge-issue-item",text:"Runtime version mismatch"}),x||M.createEl("div",{cls:"paperforge-issue-item",text:"Index missing or corrupted"}),_||M.createEl("div",{cls:"paperforge-issue-item",text:"No Zotero export found"}),k||M.createEl("div",{cls:"paperforge-issue-item",text:"PaddleOCR API key not configured"});let re=R.createEl("div",{cls:"paperforge-issue-actions"}),J=re.createEl("button",{cls:"paperforge-contextual-btn"});J.createEl("span",{text:"Run Doctor"}),J.addEventListener("click",()=>{let Pe=Y.find(Ve=>Ve.id==="paperforge-doctor");Pe&&this._runAction(Pe,J)});let ue=re.createEl("button",{cls:"paperforge-contextual-btn"});ue.createEl("span",{text:"Repair Issues"}),ue.addEventListener("click",()=>{let Pe=Y.find(Ve=>Ve.id==="paperforge-repair");Pe&&this._runAction(Pe,ue)})}let O=e.createEl("div",{cls:"paperforge-global-actions"});O.createEl("div",{cls:"paperforge-section-label",text:"Start Working"});let U=O.createEl("div",{cls:"paperforge-global-actions-row"}),q=U.createEl("button",{cls:"paperforge-contextual-btn primary"});q.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4C1}"}),q.createEl("span",{text:"Open Literature Hub"}),q.addEventListener("click",()=>{var re;let R=((re=p==null?void 0:p.settings)==null?void 0:re.base_dir)||"Bases",M=this.app.vault.getAbstractFileByPath(R);if(M){let J=null;if(M.children&&(J=M.children.find(ue=>ue.extension==="base")),J){let ue=this.app.workspace.getLeaf(!1);ue&&ue.openFile(J)}else new B.Notice("[!!] No .base file found in "+R,6e3)}else new B.Notice("[!!] Base directory not found: "+R,6e3)});let F=U.createEl("button",{cls:"paperforge-contextual-btn"});F.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),F.createEl("span",{text:"Sync Library"}),F.addEventListener("click",()=>{let R=Y.find(M=>M.id==="paperforge-sync");R&&this._runAction(R,F)});let D=U.createEl("button",{cls:"paperforge-contextual-btn"});D.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),D.createEl("span",{text:"Run OCR"}),D.addEventListener("click",()=>{let R=Y.find(M=>M.id==="paperforge-ocr");R&&this._runAction(R,D)});let X=U.createEl("button",{cls:"paperforge-contextual-btn warn"});X.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),X.createEl("span",{text:"Redo OCR"}),X.addEventListener("click",()=>{let R=Y.find(M=>M.id==="paperforge-ocr-redo");R&&this._runAction(R,X)})}_renderSystemStatusRow(e,t,r,n){let a=e.createEl("div",{cls:"paperforge-status-row"});a.createEl("span",{cls:"paperforge-status-dot"}).addClass(r==="healthy"||r==="configured"?"ok":"fail"),a.createEl("span",{cls:"paperforge-status-label",text:t}),a.createEl("span",{cls:"paperforge-status-detail",text:n||""})}_renderPaperMode(){let e=this._currentPaperEntry,t=this._currentPaperKey;if(!this._contentEl)return;if(!t){this._renderEmptyState(this._contentEl,"No paper data available.");return}if(!e){this._contentEl.createEl("div",{cls:"paperforge-content-placeholder",text:'Paper "'+t+'" not found in canonical index. Sync first.'});return}let r=this._contentEl.createEl("div",{cls:"paperforge-paper-view"}),n=r.createEl("div",{cls:"paperforge-paper-header"});n.createEl("div",{cls:"paperforge-paper-title pf-copy",text:e.title||"Untitled"}).addEventListener("click",()=>{navigator.clipboard.writeText(e.title||""),new B.Notice("Title copied")});let s=n.createEl("div",{cls:"paperforge-paper-meta"});e.authors&&e.authors.length>0&&s.createEl("span",{cls:"paperforge-paper-authors",text:e.authors.join(", ")}),e.year&&s.createEl("span",{cls:"paperforge-paper-year",text:String(e.year)});let l=r.createEl("div",{cls:"paperforge-status-strip"}),i=l.createEl("div",{cls:"paperforge-status-strip-left"}),c=l.createEl("div",{cls:"paperforge-status-strip-right"}),d=[{key:"pdf",label:"PDF",ok:e.has_pdf===!0},{key:"ocr",label:"OCR",ok:e.ocr_status==="done",pending:["pending","queued","processing"].includes(e.ocr_status||""),fail:["failed","blocked","done_incomplete","nopdf"].includes(e.ocr_status||"")},{key:"deep",label:"\u7CBE\u8BFB",ok:e.deep_reading_status==="done"}];for(let p of d){let f=i.createEl("span",{cls:"paperforge-status-pill"}),y="pending";p.ok?y="ok":p.fail?y="fail":p.pending&&(y="pending"),f.addClass(y);let b=p.ok?"\u2713":p.fail?"\u2717":"\u25CB";f.createEl("span",{cls:"paperforge-status-pill-icon",text:b}),f.createEl("span",{text:" "+p.label})}if(e.pdf_path){let p=c.createEl("button",{cls:"paperforge-contextual-btn"});p.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4C4}"}),p.createEl("span",{text:"\u6253\u5F00 PDF"}),p.addEventListener("click",()=>{let f=e.pdf_path.match(/\[\[([^\]]+)\]\]/),y=f?f[1]:e.pdf_path;this.app.vault.getAbstractFileByPath(y)?this.app.workspace.openLinkText(y,""):new B.Notice("[!!] PDF not found: "+y,6e3)})}if(e.fulltext_path){let p=c.createEl("button",{cls:"paperforge-contextual-btn"});p.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4DD}"}),p.createEl("span",{text:"\u6253\u5F00\u5168\u6587"}),p.addEventListener("click",()=>this._openFulltext(e.fulltext_path))}let g=c.createEl("button",{cls:"paperforge-contextual-btn"});if(g.createEl("span",{text:o("version_panel_title")}),g.addEventListener("click",()=>{this._switchToVersionMode(t)}),this._renderPaperOverviewCard(r,e),e.next_step==="ready"&&e.deep_reading_status==="done"){let p=r.createEl("div",{cls:"paperforge-complete-row"});p.createEl("span",{text:"\u2713"}),p.createEl("span",{text:"\u5DF2\u5B8C\u6210\uFF0C\u53EF\u76F4\u63A5\u4F7F\u7528"})}else this._renderNextStepCard(r,e,t);this._renderRecentDiscussionCard(r,e),this._renderPaperTechnicalDetails(r,e)}_renderPaperOverviewCard(e,t){let r=e.createEl("div",{cls:"paperforge-paper-overview"});r.createEl("div",{cls:"paperforge-paper-overview-header"}).createEl("span",{cls:"paperforge-paper-overview-title",text:"\u6587\u7AE0\u6982\u89C8"});let a=r.createEl("div",{cls:"paperforge-paper-overview-body"}),s=a.createEl("div",{cls:"paperforge-paper-overview-excerpt",text:"\u52A0\u8F7D\u4E2D..."});if(t.note_path){let l=this.app.vault.getAbstractFileByPath(t.note_path);l?this.app.vault.read(l).then(i=>{let c=this._extractOverviewFromNote(i);if(c){let d=c.length>200?c.slice(0,200)+"...":c;if(s.setText(d),c.length>200){let g=a.createEl("div",{cls:"paperforge-expand-container"}),p=g.createEl("button",{cls:"paperforge-expand-icon",title:"\u5C55\u5F00/\u6536\u8D77"});p.innerHTML='';let f=!1;g.addEventListener("click",()=>{s.setText(f?d:c),p.innerHTML=f?'':'',f=!f})}}else s.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8\u3002\u8FD0\u884C /pf-deep \u5F00\u59CB\u7CBE\u8BFB\u3002")}).catch(()=>{s.setText("\u65E0\u6CD5\u8BFB\u53D6\u7B14\u8BB0\u5185\u5BB9")}):s.setText("\u7B14\u8BB0\u6587\u4EF6\u4E0D\u5B58\u5728")}else s.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8")}_extractOverviewFromNote(e){if(!e)return null;let t=e.indexOf("## \u{1F50D} \u7CBE\u8BFB");if(t===-1)return null;let r=e.slice(t),n=["**\u4E00\u53E5\u8BDD\u603B\u89C8:**","**\u4E00\u53E5\u8BDD\u603B\u89C8**","**\u6587\u7AE0\u6458\u8981:**","**\u6587\u7AE0\u6458\u8981**"];for(let l of n){let i=r.indexOf(l);if(i!==-1){let c=r.slice(i+l.length),d=["**5 Cs","**Figure","**\u8BC1\u636E","### Pass 2","## "],g=c.length;for(let y of d){let b=c.indexOf(y);b!==-1&&b 300 - ? l.slice(0, 300) + "..." - : l; - } - _renderRecentDiscussionCard(r, n) { - let i = r.createEl("div", { cls: "paperforge-discussion-card" }); - if (((i.style.display = "none"), !n.note_path)) return; - let a = n.note_path.lastIndexOf("/"), - l = (a !== -1 ? n.note_path.substring(0, a) : ".") + "/ai/discussion.md"; - this.app.vault.adapter - .exists(l) - .then((u) => { - if (u) return this.app.vault.adapter.read(l); - }) - .then(async (u) => { - if (!u) return; - let p = this._parseDiscussionMD(u); - if (!p || p.length === 0) return; - ((i.style.display = "block"), - i - .createEl("div", { cls: "paperforge-discussion-header" }) - .createEl("span", { - cls: "paperforge-discussion-title", - text: "\u6700\u8FD1\u8BA8\u8BBA", - })); - for (let k of p) { - let g = i.createEl("div", { cls: "paperforge-discussion-item" }), - x = g.createEl("div", { cls: "paperforge-discussion-q" }); - (x.createEl("span", { - cls: "paperforge-discussion-q-label", - text: "\u63D0\u95EE\uFF1A", - }), - x.createEl("span", { - cls: "paperforge-discussion-q-text", - text: k.question, - })); - let C = g.createEl("div", { cls: "paperforge-discussion-a" }), - R = !1; - if ( - (k.answer && - k.answer.length > 500 && - ((R = !0), C.classList.add("paperforge-discussion-a-collapsed")), - await X.MarkdownRenderer.render( - this.app, - k.answer || "", - C, - l, - this - ), - R) - ) { - let S = !1; - ((g.style.cursor = "pointer"), - g.addEventListener("click", () => { - ((S = !S), - C.classList.toggle("paperforge-discussion-a-collapsed", !S), - C.classList.toggle("paperforge-discussion-a-expanded", S)); - })); - } - } - i.createEl("a", { - cls: "paperforge-discussion-viewall", - text: "\u67E5\u770B\u5168\u90E8\u8BA8\u8BBA \u2192", - }).addEventListener("click", (k) => { - (k.preventDefault(), - this.app.vault.getAbstractFileByPath(l) - ? this.app.workspace.openLinkText(l, "") - : new X.Notice( - "\u8BA8\u8BBA\u6587\u4EF6\u5C1A\u672A\u751F\u6210" - )); - }); - }) - .catch((u) => { - console.error("PaperForge: discussion.md read error", l, u.message); - }); - } - _parseDiscussionMD(r) { - let n = r.split(/\n## /).slice(1); - if (n.length === 0) return null; - let i = n[n.length - 1], - a = [], - c = i.split(/\*\*\u95EE\u9898:\*\*/).slice(1); - for (let l of c) { - let u = l.match(/\*\*\u89E3\u7B54:\*\*/); - if (!u) continue; - let p = l.substring(0, u.index).trim(), - h = l.substring(u.index + 3 + 4).trim(); - a.push({ question: p, answer: h }); - } - return a.slice(-3); - } - _renderPaperTechnicalDetails(r, n) { - let i = this._currentPaperKey, - a = r.createEl("div", { cls: "paperforge-technical-details" }), - c = a.createEl("button", { cls: "paperforge-technical-details-toggle" }), - l = a.createEl("div", { cls: "paperforge-technical-details-body" }); - ((l.style.display = "none"), - this._techDetailsExpanded - ? ((l.style.display = "block"), - c.setText("\u6280\u672F\u8BE6\u60C5 \u25BE")) - : c.setText("\u6280\u672F\u8BE6\u60C5 \u25B8"), - c.addEventListener("click", () => { - let g = l.style.display !== "none"; - ((l.style.display = g ? "none" : "block"), - c.setText( - g - ? "\u6280\u672F\u8BE6\u60C5 \u25B8" - : "\u6280\u672F\u8BE6\u60C5 \u25BE" - ), - (this._techDetailsExpanded = !g)); - })); - let u = l.createEl("div", { cls: "paperforge-workflow-toggles" }), - p = [ - { key: "do_ocr", label: "OCR", hint: "\u52A0\u5165 OCR" }, - { - key: "analyze", - label: "\u7CBE\u8BFB", - hint: "\u6807\u8BB0\u7CBE\u8BFB", - }, - ]; - for (let g of p) { - let x = u.createEl("label", { cls: "paperforge-workflow-toggle" }), - C = x.createEl("input", { - type: "checkbox", - cls: "paperforge-workflow-checkbox", - }); - ((C.checked = n[g.key] === !0), - x.createEl("span", { - cls: "paperforge-workflow-toggle-label", - text: g.label, - }), - x.createEl("span", { - cls: "paperforge-workflow-toggle-hint", - text: g.hint, - }), - C.addEventListener("change", async () => { - let R = n.note_path - ? this.app.vault.getAbstractFileByPath(n.note_path) - : null; - if (!R) { - new X.Notice("[!!] Note file not found", 6e3); - return; - } - let S = C.checked; - (await this.app.fileManager.processFrontMatter(R, (F) => { - F[g.key] = S; - }), - this._patchCachedEntry(i, { [g.key]: S }), - (this._currentPaperEntry = xr(this._currentPaperEntry, { - [g.key]: S, - }))); - })); - } - let h = n.health || {}, - b = [ - ["PDF Health", h.pdf_health || "\u2014"], - ["OCR Status", n.ocr_status || "\u2014"], - ["Asset Health", h.asset_health || "\u2014"], - ["Note Path", n.note_path || "\u2014"], - ["Fulltext Path", n.fulltext_path || "\u2014"], - ], - k = new Set(["Note Path", "Fulltext Path", "Key"]); - for (let [g, x] of b) { - let C = l.createEl("div", { cls: "paperforge-technical-row" }); - C.createEl("span", { cls: "paperforge-technical-label", text: g }); - let R = C.createEl("span", { - cls: "paperforge-technical-value", - text: String(x), - }); - k.has(g) && - x && - x !== "\u2014" && - (R.addClass("pf-copy"), - R.addEventListener("click", () => { - (navigator.clipboard.writeText(x), new X.Notice(g + " copied")); - })); - } - } - _renderNextStepCard(r, n, i) { - var p, h; - let a = n.next_step || "ready", - c = { - sync: { - label: "Sync Needed", - text: "This paper needs to be synced from Zotero. Click to run sync.", - cmd: "sync", - icon: "\u21BB", - }, - ocr: { - label: "OCR Needed", - text: "Fulltext is missing but PDF is present. Click to run OCR.", - cmd: "ocr", - icon: "\u229E", - }, - repair: { - label: "Repair Needed", - text: "State divergence or path errors detected. Click to repair.", - cmd: "repair", - icon: "\u21BA", - }, - "rebuild index": { - label: "Rebuild Needed", - text: "Index may be stale. Click to run sync to rebuild.", - cmd: "sync", - icon: "\u21BB", - }, - "/pf-deep": { - label: "Ready for Deep Reading", - text: "Fulltext is ready. Copy /pf-deep command and run in your agent.", - cmd: null, - icon: "\u{1F50D}", - }, - ready: { - label: "All Set", - text: "This paper is fully processed and ready for use.", - cmd: "ready", - icon: "\u2713", - }, - }, - l = c[a] || c.ready, - u = r.createEl("div", { cls: "paperforge-next-step-card" }); - if ( - (a === "ready" && u.addClass("ready"), - u.createEl("div", { - cls: "paperforge-next-step-label", - text: "Recommended Next Step", - }), - u.createEl("div", { cls: "paperforge-next-step-text", text: l.text }), - l.cmd && l.cmd !== "ready") - ) { - let b = u.createEl("button", { cls: "paperforge-next-step-trigger" }); - (b.createEl("span", { text: l.icon + " " + l.label }), - b.addEventListener("click", () => { - let k = Pe.find((g) => g.cmd === l.cmd); - k && this._runAction(k, b); - })); - } else if (a === "/pf-deep") { - let b = u.createEl("button", { cls: "paperforge-next-step-trigger" }); - (b.createEl("span", { text: "\u{1F4CB} " + f("copy_pf_deep_cmd") }), - b.addEventListener("click", () => { - let R = "/pf-deep " + i; - navigator.clipboard - .writeText(R) - .then(() => { - (b.setText("\u2713 " + f("copied")), - new X.Notice(R + " copied")); - }) - .catch(() => { - new X.Notice("[!!] Clipboard write failed", 6e3); - }); - })); - let k = - ((h = - (p = this.app.plugins.plugins.paperforge) == null - ? void 0 - : p.settings) == null - ? void 0 - : h.agent_platform) || "opencode", - x = - { - opencode: "OpenCode", - claude: "Claude Code", - cursor: "Cursor", - github_copilot: "GitHub Copilot", - windsurf: "Windsurf", - codex: "Codex", - gemini: "Gemini CLI", - cline: "Cline", - }[k] || k; - u.createEl("div", { cls: "paperforge-agent-platform-label" }).setText( - f("run_in_agent").replace("{0}", x) - ); - } else - a === "ready" && - u - .createEl("button", { cls: "paperforge-next-step-trigger" }) - .createEl("span", { text: "\u2713 " + l.label }); - } - _openFulltext(r) { - if (!r) { - new X.Notice("[!!] No fulltext path available for this paper", 6e3); - return; - } - let n = this.app.vault.getAbstractFileByPath(r); - n - ? this.app.workspace.openLinkText(n.path, "") - : new X.Notice("[!!] Fulltext file not found: " + r, 6e3); - } - _renderCollectionMode() { - let r = this._currentDomain || "Unknown", - n = this._filterByDomain(r); - if (n.length === 0) { - this._renderGlobalMode(); - return; - } - if (!this._contentEl) return; - let i = this._contentEl.createEl("div", { - cls: "paperforge-collection-view", - }), - a = n.length, - c = 0, - l = 0, - u = 0, - p = 0, - h = 0, - b = 0, - k = 0; - for (let v of n) { - (v.has_pdf && c++, - v.ocr_status === "done" && l++, - v.ocr_status === "done" && v.analyze === !0 && u++, - v.deep_reading_status === "done" && p++); - let w = v.ocr_status || ""; - w === "pending" || w === "queued" - ? h++ - : w === "processing" - ? b++ - : (w === "failed" || - w === "blocked" || - w === "done_incomplete" || - w === "nopdf") && - k++; - } - i.createEl("div", { cls: "paperforge-collection-header" }).createEl("div", { - cls: "paperforge-collection-title", - text: r, - }); - let x = i.createEl("div", { cls: "paperforge-workflow-overview" }); - x.createEl("div", { - cls: "paperforge-section-label", - text: "Workflow Overview", - }); - let C = x.createEl("div", { cls: "paperforge-workflow-funnel" }), - R = [ - { value: a, label: "Total" }, - { value: c, label: "PDF Ready" }, - { value: l, label: "OCR Done" }, - { value: p, label: "Deep Read" }, - ]; - for (let v = 0; v < R.length; v++) { - let w = C.createEl("div", { cls: "paperforge-workflow-stage" }); - (w.createEl("div", { - cls: "paperforge-workflow-stage-value", - text: String(R[v].value), - }), - w.createEl("div", { - cls: "paperforge-workflow-stage-label", - text: R[v].label, - }), - v < R.length - 1 && - C.createEl("div", { - cls: "paperforge-workflow-arrow", - text: "\u2192", - })); - } - if (h + b + l + k > 0) { - let v = i.createEl("div", { cls: "paperforge-ocr-section" }), - w = v.createEl("div", { cls: "paperforge-collection-ocr-header" }); - w.createEl("h4", { cls: "paperforge-ocr-title", text: "OCR Pipeline" }); - let O = w.createEl("span", { cls: "paperforge-ocr-badge idle" }); - b > 0 - ? (O.addClass("active"), O.setText("Processing")) - : h > 0 - ? O.setText("Pending") - : (O.addClass("idle"), O.setText("Idle")); - let M = v.createEl("div", { cls: "paperforge-progress-track" }); - b > 0 && M.addClass("paperforge-processing"); - let I = h + b + l + k, - J = [ - { cls: "pending", count: h }, - { cls: "active", count: b }, - { cls: "done", count: l }, - { cls: "failed", count: k }, - ]; - for (let se of J) - if (se.count > 0) { - let G = ((se.count / I) * 100).toFixed(1); - M.createEl("div", { - cls: `paperforge-progress-seg ${se.cls}`, - attr: { style: `width:${G}%` }, - }); - } - let q = v.createEl("div", { cls: "paperforge-ocr-counts" }), - te = [ - { cls: "pending", value: h, label: "Pending" }, - { cls: "active", value: b, label: "Processing" }, - { cls: "done", value: l, label: "Done" }, - { cls: "failed", value: k, label: "Attention" }, - ]; - for (let se of te) { - let G = q.createEl("div", { cls: "paperforge-ocr-count" }); - (G.createEl("div", { - cls: "paperforge-ocr-count-value", - text: se.value.toString(), - }), - G.createEl("div", { - cls: "paperforge-ocr-count-label", - text: se.label, - })); - } - } - let S = i.createEl("div", { cls: "paperforge-collection-actions" }), - F = S.createEl("button", { cls: "paperforge-contextual-btn primary" }); - (F.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u229E", - }), - F.createEl("span", { text: "Run OCR" }), - F.addEventListener("click", () => { - let v = Pe.find((w) => w.id === "paperforge-ocr"); - v && this._runAction(v, F); - })); - let B = S.createEl("button", { cls: "paperforge-contextual-btn" }); - (B.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u21BB", - }), - B.createEl("span", { text: "Sync Library" }), - B.addEventListener("click", () => { - let v = Pe.find((w) => w.id === "paperforge-sync"); - v && this._runAction(v, B); - })); - let A = S.createEl("button", { cls: "paperforge-contextual-btn warn" }); - (A.createEl("span", { - cls: "paperforge-contextual-btn-icon", - text: "\u21BA", - }), - A.createEl("span", { text: "Redo OCR" }), - A.addEventListener("click", () => { - let v = Pe.find((w) => w.id === "paperforge-ocr-redo"); - v && this._runAction(v, A); - }), - this.renderSearchSection(i)); - } - _refreshCurrentMode() { - if (!(!this._currentMode || !this._contentEl)) { - (this._contentEl.empty(), - this._contentEl.addClass("switching"), - this._invalidateIndex(), - (this._currentPaperEntry = this._currentPaperKey - ? this._findEntry(this._currentPaperKey) - : null), - this._renderModeHeader(this._currentMode)); - try { - switch (this._currentMode) { - case "global": - this._renderGlobalMode(); - break; - case "paper": - this._renderPaperMode(); - break; - case "collection": - this._renderCollectionMode(); - break; - case "versions": - this._renderVersionMode(); - break; - } - } finally { - setTimeout(() => { - this._contentEl && this._contentEl.removeClass("switching"); - }, 50); - } - } - } - _switchToVersionMode(r) { - let i = this.app.vault.adapter.basePath, - a = typeof i == "string" ? i : ""; - if (!a) { - new X.Notice("Cannot determine vault path"); - return; - } - ((this._versionPapers = Br(a)), - (this._versionFilter = ""), - (this._currentMode = "versions"), - (this._currentFilePath = null), - (this._techDetailsExpanded = !1), - this._contentEl && - (this._contentEl.empty(), - this._contentEl.removeClass("switching"), - this._renderModeHeader("versions"), - this._renderVersionMode())); - } - _renderVersionMode() { - if (!this._contentEl) return; - let r = this._contentEl.createEl("div", { - cls: "paperforge-version-panel", - }), - i = this.app.vault.adapter.basePath, - a = typeof i == "string" ? i : ""; - if (!a) { - r.createEl("div", { - cls: "paperforge-status-error", - text: "Could not determine vault path", - }); - return; - } - (!this._versionPapers || this._versionPapers.length === 0) && - (this._versionPapers = Br(a)); - let c = r.createEl("div", { cls: "paperforge-version-left" }), - l = r.createEl("div", { cls: "paperforge-version-right" }), - u = c.createEl("input", { - cls: "paperforge-version-filter", - attr: { type: "text", placeholder: f("version_filter_placeholder") }, - }); - u.value = this._versionFilter; - let p = c.createEl("div", { cls: "paperforge-version-paper-list" }), - h = () => { - p.empty(); - let F = this._versionFilter.toLowerCase(), - B = this._versionPapers - ? this._versionPapers.filter( - (v) => - !F || - v.key.toLowerCase().includes(F) || - v.title.toLowerCase().includes(F) - ) - : []; - if (B.length === 0) { - p.createEl("div", { - cls: "paperforge-meta", - text: f("version_no_backups"), - }); - return; - } - let A = p.createEl("div", { - cls: "paperforge-meta", - text: f("version_papers_count").replace("{n}", String(B.length)), - }); - for (let v of B) { - let w = p.createEl("div", { cls: "paperforge-version-paper-item" }), - O = w.createEl("span", { - cls: "paperforge-version-paper-title", - text: v.title, - }), - M = w.createEl("span", { - cls: "paperforge-version-paper-versions", - text: v.versions.map((I) => I.label).join(" "), - }); - w.addEventListener("click", () => { - (p - .querySelectorAll(".paperforge-version-paper-item.selected") - .forEach((I) => I.removeClass("selected")), - w.addClass("selected"), - k(v)); - }); - } - }; - u.addEventListener("input", () => { - ((this._versionFilter = u.value), h()); - }); - let b = l.createEl("div", { cls: "paperforge-version-timeline-area" }), - k = (F) => { - if ( - (b.empty(), - b - .createEl("div", { cls: "paperforge-version-timeline-header" }) - .createEl("span", { cls: "pf-title", text: F.title }), - F.versions.length === 0) - ) { - b.createEl("div", { - cls: "paperforge-meta", - text: f("version_no_backups"), - }); - return; - } - let A = b.createEl("div", { cls: "paperforge-version-timeline" }); - for (let v of F.versions) { - let w = v.label === F.currentLabel, - O = A.createEl("div", { - cls: - "paperforge-version-entry" + - (w ? " paperforge-version-current" : ""), - }), - M = O.createEl("div", { cls: "paperforge-version-dot" }), - I = O.createEl("div", { cls: "paperforge-version-content" }), - J = I.createEl("div", { cls: "paperforge-version-label-row" }); - (J.createEl("span", { - cls: "paperforge-version-label", - text: v.label, - }), - w && - J.createEl("span", { - cls: "paperforge-version-current-tag", - text: f("version_current"), - })); - let q = v.created_at ? v.created_at.slice(0, 10) : ""; - I.createEl("div", { - cls: "paperforge-meta", - text: q + " \u2014 " + v.source, - }); - let te = v.fulltext_size - ? v.fulltext_size > 1024 - ? (v.fulltext_size / 1024).toFixed(0) + "KB" - : v.fulltext_size + "B" - : ""; - te && I.createEl("div", { cls: "paperforge-meta", text: te }); - let se = I.createEl("div", { cls: "paperforge-version-actions" }); - (se - .createEl("button", { - cls: "pf-btn-primary", - text: f("version_restore_btn"), - }) - .addEventListener("click", () => { - Un(a, F.key, v.label) - ? new X.Notice( - f("version_restore_done").replace("{label}", v.label) - ) - : new X.Notice("Restore failed", 6e3); - }), - F.versions.length > 1 && - !w && - se - .createEl("button", { - cls: "pf-btn-secondary", - text: f("version_compare_btn"), - }) - .addEventListener("click", () => { - x(F, v.label, F.currentLabel); - })); - } - }, - g = l.createEl("div", { cls: "paperforge-version-compare" }); - g.style.display = "none"; - let x = (F, B, A) => { - let v = Wn(a, F.key, B, A); - ((g.style.display = "block"), g.empty()); - let w = g.createEl("div", { cls: "paperforge-version-compare-header" }); - if ( - (w.createEl("span", { - cls: "pf-title", - text: f("version_compare_title") - .replace("{vA}", B) - .replace("{vB}", A), - }), - w.createEl("span", { - cls: "paperforge-meta", - text: f("version_compare_paragraphs").replace( - "{n}", - String(v.length) - ), - }), - v.length === 0) - ) { - g.createEl("div", { cls: "paperforge-meta", text: "No changes" }); - return; - } - let O = g.createEl("div", { cls: "paperforge-version-diff-list" }); - for (let M of v) { - let I = O.createEl("div", { cls: "paperforge-version-diff-row" }), - J = - M.type === "added" ? "[+]" : M.type === "removed" ? "[-]" : "[~]", - q = M.heading || "paragraph " + (M.paragraphIndex + 1); - (I.createEl("span", { - cls: "paperforge-version-diff-label", - text: J + " " + q, - }), - M.oldText && - I.createEl("pre", { - cls: "paperforge-version-diff-old", - text: M.oldText.slice(0, 200), - }), - M.newText && - I.createEl("pre", { - cls: "paperforge-version-diff-new", - text: M.newText.slice(0, 200), - })); - } - }, - C = r.createEl("div", { cls: "paperforge-version-actions-bar" }), - R = C.createEl("button", { - cls: "pf-btn-primary", - text: f("version_restore_selected"), - }), - S = C.createEl("button", { - cls: "pf-btn-secondary", - text: f("version_clear_old").replace("{size}", ""), - }); - h(); - } - renderSearchSection(r) { - ((this._searchContainer = r.createEl("div", { - cls: "paperforge-search-section", - })), - this._searchContainer - .createEl("div", { cls: "paperforge-search-header" }) - .createEl("span", { cls: "pf-label", text: "Search" })); - let i = this._searchContainer.createEl("div", { - cls: "paperforge-search-input-row", - }), - a = i.createEl("span", { cls: "paperforge-search-mode", text: "M" }); - ((this._searchInput = i.createEl("input", { - cls: "paperforge-search-input", - attr: { - type: "text", - placeholder: "Search papers... (@ for deep search)", - }, - })), - (this._searchResultsEl = this._searchContainer.createEl("div", { - cls: "paperforge-search-results", - })), - this._searchInput.addEventListener("input", () => { - var l; - let c = ((l = this._searchInput) == null ? void 0 : l.value) || ""; - (c.startsWith("@") && !c.startsWith("@ ") - ? (a.setText("@"), a.addClass("deep")) - : (a.setText("M"), a.removeClass("deep")), - clearTimeout(this._searchTimer), - !c.startsWith("@") && - c.trim() && - (this._searchTimer = setTimeout(() => { - this.executeSearch({ source: "sqljs" }); - }, 200))); - }), - this._searchInput.addEventListener("keydown", (c) => { - c.key === "Enter" && - (c.preventDefault(), - this._searchTimer && - (clearTimeout(this._searchTimer), (this._searchTimer = void 0)), - this.executeSearch({ source: "cli" })); - })); - } - async executeSearch(r = {}) { - if (!this._searchInput || !this._searchResultsEl) return; - let n = this._searchInput.value.trim(); - if (!n) return; - let i = n.startsWith("@"), - a = i ? n.slice(1).trim() : n; - if (!a) return; - let c = i ? "retrieve" : "search", - l = this.app.vault.adapter, - u = ""; - if (l && typeof l == "object" && "basePath" in l) { - let R = l.basePath; - u = typeof R == "string" ? R : ""; - } - if ( - (this._searchResultsEl.empty(), - c === "search" && (r.source === "auto" || r.source === "sqljs") && u) - ) - try { - if ( - (!this._sqlJsInitialized && - !this._sqlJsFailed && - (await Gn(u), (this._sqlJsInitialized = !0)), - this._sqlJsInitialized) - ) { - let R = Qn(a, 20); - if (R !== null) { - this.renderSearchResults(R, !1); - return; - } - } - } catch (R) { - (console.error("PaperForge sql.js search failed:", R), - (this._sqlJsFailed = !0)); - } - if ( - (this._searchResultsEl.createEl("div", { - cls: "paperforge-search-loading", - text: "Searching...", - }), - !u) - ) { - this._renderSearchError("Could not determine vault path"); - return; - } - let p = null, - b = this.app.plugins; - if (b && typeof b == "object" && "plugins" in b) { - let R = b.plugins; - if (R && typeof R == "object" && "paperforge" in R) { - let S = R.paperforge; - S && typeof S == "object" && "settings" in S && (p = S.settings); - } - } - let { path: k, extraArgs: g = [] } = re(u, p, void 0, void 0), - x = (0, et.spawn)(k, [...g, "-m", "paperforge", c, a, "--json"], { - cwd: u, - timeout: 3e4, - }), - C = []; - (x.stdout.on("data", (R) => { - C.push(R.toString("utf-8")); - }), - x.stderr.on("data", () => {}), - x.on("close", (R) => { - if (R !== 0) { - this._renderSearchError(`Search failed (exit ${R})`); - return; - } - let S = C.join(""), - F = S.indexOf("{"), - B = S.lastIndexOf("}"), - A = ""; - if (F !== -1 && B > F) A = S.slice(F, B + 1); - else { - let v = S.indexOf("["), - w = S.lastIndexOf("]"); - v !== -1 && w > v && (A = S.slice(v, w + 1)); - } - if (!A) { - this._renderSearchError("No JSON output from CLI"); - return; - } - try { - let v = JSON.parse(A), - w = []; - if (v && typeof v == "object" && "data" in v) { - let O = v.data; - if (O && typeof O == "object") { - let M = O; - "matches" in M && Array.isArray(M.matches) - ? (w = M.matches) - : "results" in M && Array.isArray(M.results) && (w = M.results); - } - } - this.renderSearchResults(w, i); - } catch (v) { - let w = v instanceof Error ? v.message : String(v); - this._renderSearchError("Failed to parse results: " + w); - } - }), - x.on("error", (R) => { - this._renderSearchError("Process error: " + R.message); - })); - } - renderSearchResults(r, n) { - if (!this._searchResultsEl) return; - if ((this._searchResultsEl.empty(), r.length === 0)) { - this._searchResultsEl.createEl("div", { - cls: "paperforge-search-empty", - text: "No results found.", - }); - return; - } - let i = this._searchResultsEl.createEl("div", { - cls: "paperforge-search-results-header", - }); - (i.createEl("span", { - text: `${r.length} result${r.length !== 1 ? "s" : ""}`, - }), - i.createEl("span", { - cls: "paperforge-search-mode", - text: n ? "@" : "M", - })); - for (let a of r) { - if (!a || typeof a != "object") continue; - let c = a, - l = this._searchResultsEl.createEl("div", { - cls: "paperforge-search-result-card", - attr: { role: "button" }, - }), - u = - typeof c.title == "string" - ? c.title - : typeof c.file_name == "string" - ? c.file_name - : "(untitled)"; - l.createEl("div", { cls: "paperforge-search-result-title", text: u }); - let p = typeof c.zotero_key == "string" ? c.zotero_key : "", - h = - typeof c.main_note_path == "string" && c.main_note_path - ? c.main_note_path - : null, - b = typeof c.note_path == "string" && c.note_path ? c.note_path : null, - k = h || b; - if (!k && p) { - let C = this._getCachedIndex().find( - (R) => - R !== null && - typeof R == "object" && - "zotero_key" in R && - R.zotero_key === p - ); - if (C && typeof C == "object") { - let R = C; - k = - typeof R.main_note_path == "string" && R.main_note_path - ? R.main_note_path - : typeof R.note_path == "string" && R.note_path - ? R.note_path - : null; - } - } - k - ? l.addEventListener("click", (x) => { - let C = x.ctrlKey || x.metaKey; - this.app.workspace.openLinkText(k, "", C); - }) - : l.addEventListener("click", () => { - new X.Notice("[!!] Note not found: " + (p || "unknown"), 6e3); - }); - let g = l.createEl("div", { cls: "paperforge-search-result-meta" }); - if ( - (typeof c.authors == "string" - ? g.createEl("span", { - cls: "paperforge-search-result-author", - text: c.authors, - }) - : Array.isArray(c.authors) && - g.createEl("span", { - cls: "paperforge-search-result-author", - text: c.authors.slice(0, 3).join("; "), - }), - (typeof c.year == "number" || typeof c.year == "string") && - g.createEl("span", { - cls: "paperforge-search-result-year", - text: String(c.year), - }), - typeof c.journal == "string" && - c.journal && - g.createEl("span", { - cls: "paperforge-search-result-journal", - text: c.journal, - }), - c.score !== void 0) - ) { - let x = c.score, - C = typeof x == "number" ? x.toFixed(3) : String(x); - g.createEl("span", { - cls: "paperforge-search-result-score", - text: "Score: " + C, - }); - } - if ( - (typeof c.domain == "string" && - c.domain && - l.createEl("span", { - cls: "paperforge-search-result-tag", - text: c.domain, - }), - typeof c.abstract == "string" && c.abstract) - ) { - let x = c.abstract; - l.createEl("div", { - cls: "paperforge-search-result-abstract", - text: x.length > 200 ? x.slice(0, 200) + "..." : x, - }); - } - if (n && typeof c.matched_text == "string" && c.matched_text) { - let x = c.matched_text; - l.createEl("div", { - cls: "paperforge-search-result-source", - text: x.length > 300 ? x.slice(0, 300) + "..." : x, - }); - } - } - } - _renderSearchError(r) { - this._searchResultsEl && - (this._searchResultsEl.empty(), - this._searchResultsEl.createEl("div", { - cls: "paperforge-search-error", - text: r, - })); - } - _runAction(r, n) { - var g, x; - if (r.disabled) { - new X.Notice( - `[i] ${r.disabledMsg || "This action is not yet available."}`, - 6e3 - ); - return; - } - if (n.classList.contains("running")) return; - n.addClass("running"); - let i = this.app.vault.adapter.basePath; - this._showMessage("Processing...", "running"); - let a = Array.isArray(r.args) ? [...r.args] : []; - if (r.needsKey) { - let C = this.app.workspace.getActiveFile(), - R = null; - if (C) { - let S = this.app.metadataCache.getFileCache(C); - if ( - (S && S.frontmatter && S.frontmatter.zotero_key - ? (R = S.frontmatter.zotero_key) - : (R = this._extractZoteroKeyFromPath(C.path)), - R) - ) - a = [...a, R]; - else if (S && S.frontmatter) { - (this._showMessage( - "[!!] No zotero_key in active note frontmatter", - "error" - ), - new X.Notice( - "[!!] Open a paper note with a zotero_key in its frontmatter first", - 6e3 - ), - n.removeClass("running")); - return; - } else { - (this._showMessage("[!!] No frontmatter in active note", "error"), - new X.Notice( - "[!!] The active note has no frontmatter with a zotero_key", - 6e3 - ), - n.removeClass("running")); - return; - } - } else { - (this._showMessage("[!!] No active note open", "error"), - new X.Notice( - "[!!] Open a paper note with a zotero_key in its frontmatter first", - 6e3 - ), - n.removeClass("running")); - return; - } - } - r.needsFilter && (a = [...a, "--all"]); - let c = r.needsFilter ? 6e4 : r.needsKey ? 3e4 : 6e5, - { path: l, extraArgs: u = [] } = re( - i, - (x = - (g = this.app.plugins.plugins.paperforge) == null - ? void 0 - : g.settings) != null - ? x - : null, - void 0, - void 0 - ), - p = (0, et.spawn)(l, [...u, "-m", "paperforge", r.cmd, ...a], { - cwd: i, - timeout: c, - }), - h = [], - b = Date.now(), - k = setInterval(() => this._fetchStats(!0), 4e3); - (p.stdout.on("data", (C) => { - let R = C.toString("utf-8") - .split( - ` -` - ) - .filter(Boolean); - for (let S of R) { - let F = S.trim(); - F && - (h.push(F), - this._showMessage( - h.slice(-8).join(` -`), - "running" - )); - } - }), - p.stderr.on("data", (C) => { - let R = C.toString("utf-8") - .split( - ` -` - ) - .filter(Boolean); - for (let S of R) { - if (S.includes("\r") || S.includes("%") || S.includes("\u2588")) - continue; - let F = S.trim(); - F && - !F.match(/^\d+%|^\|/) && - (h.push(F), - this._showMessage( - h.slice(-8).join(` -`), - "running" - )); - } - }), - p.on("close", (C) => { - (clearInterval(k), n.removeClass("running")); - let R = ((Date.now() - b) / 1e3).toFixed(1); - if (C !== 0) { - let S = h.slice(-3).join(" | ") || "exit code " + C; - (r.cmd === "repair" || r.cmd === "ocr") && C === 1 - ? (this._showMessage("[WARN] " + S, "running"), - new X.Notice("[WARN] " + r.cmd + " partial: " + S, 8e3), - this._fetchStats(!0)) - : (this._showMessage("[!!] " + S, "error"), - new X.Notice("[!!] " + r.cmd + " failed: " + S, 8e3)); - } else if (r.needsKey || r.needsFilter) { - let S = h.join(` -`); - if (S.trim()) - try { - (JSON.parse(S), - navigator.clipboard - .writeText(S) - .then(() => { - let F = `${R}s \u2014 ${S.length} chars copied`; - (this._showMessage("[OK] " + r.title + ": " + F, "ok"), - new X.Notice( - "[OK] " + r.okMsg + " \u2014 " + S.length + " chars" - )); - }) - .catch((F) => { - (this._showMessage( - "[!!] Clipboard write failed: " + F.message, - "error" - ), - new X.Notice("[!!] Clipboard error", 6e3)); - })); - } catch (F) { - (this._showMessage("[!!] Invalid JSON from " + r.title, "error"), - new X.Notice( - "[!!] " + - r.title + - " returned invalid JSON: " + - F.message.slice(0, 100), - 8e3 - )); - } - else - (this._showMessage("[!!] No output from context command", "error"), - new X.Notice("[!!] Context command returned empty output", 8e3)); - this._fetchStats(!0); - } else { - let F = - h.filter((A) => A.match(/updated \d+/)).pop() || - h[h.length - 1] || - "", - B = `${R}s \u2014 ${F}`; - (this._showMessage("[OK] " + r.title + ": " + B, "ok"), - new X.Notice("[OK] " + r.okMsg), - this._contentEl && this._contentEl.removeClass("switching"), - (this._cachedStats = null)); - try { - this._fetchStats(!1); - } catch (A) { - console.log("[PF] fetchStats error:", A); - } - (console.log("[PF] close cmd=" + r.cmd + " id=" + r.id), - r.cmd === "sync" && - Qt(this.app, this.app.plugins.plugins.paperforge, i)); - } - }), - p.on("error", (C) => { - (n.removeClass("running"), - this._contentEl && this._contentEl.removeClass("switching"), - this._showMessage("[!!] " + C.message, "error"), - new X.Notice("[!!] Cannot start: " + C.message, 8e3)); - })); - } - _showMessage(r, n) { - this._messageEl && - (this._messageEl.setText(r), - (this._messageEl.className = `paperforge-message msg-${n}`)); - } - _renderModeHeader(r) { - if (!this._modeContextEl) return; - this._modeContextEl.empty(); - let n = this._modeContextEl.createEl("span", { - cls: "paperforge-mode-badge", - }), - i = ""; - switch (r) { - case "global": - (n.addClass("global"), - n.setText("Global"), - this._headerTitle && this._headerTitle.setText("PaperForge")); - break; - case "paper": - (n.addClass("paper"), - n.setText("Paper"), - this._headerTitle && this._headerTitle.setText("Paper"), - this._currentPaperEntry && this._currentPaperEntry.title - ? (i = this._currentPaperEntry.title) - : this._currentPaperKey - ? ((i = this._currentPaperKey), - this._modeContextEl.createEl("span", { - cls: "paperforge-mode-warning", - text: "Not found in index", - })) - : (i = "Unknown paper")); - break; - case "collection": - (n.addClass("collection"), - n.setText("Collection"), - this._headerTitle && this._headerTitle.setText("Collection"), - (i = this._currentDomain || "Unknown Domain")); - break; - case "versions": - (n.addClass("versions"), - n.setText(f("version_panel_title")), - this._headerTitle && - this._headerTitle.setText(f("version_panel_title"))); - break; - } - i && - this._modeContextEl.createEl("span", { - cls: "paperforge-mode-name", - text: i, - }); - } - _setupEventSubscriptions() { - let r = this.app.workspace.on("active-leaf-change", () => { - (this._leafChangeTimer && clearTimeout(this._leafChangeTimer), - (this._leafChangeTimer = setTimeout(() => { - let i = this._resolveModeForFile(this.app.workspace.getActiveFile()), - a = i.mode, - c = i.filePath; - (this._currentMode === a && this._currentFilePath === c) || - this._detectAndSwitch(); - }, 300))); - }); - this._modeSubscribers.push({ event: "active-leaf-change", ref: r }); - let n = this.app.vault.on("modify", (i) => { - i && - i.path && - i.path.endsWith("formal-library.json") && - (this._invalidateIndex(), this._refreshCurrentMode()); - }); - this._modeSubscribers.push({ event: "modify", ref: n }); - } - static async open(r) { - let n = r.app.workspace.getLeavesOfType(it); - if (n.length > 0) { - r.app.workspace.revealLeaf(n[0]); - return; - } - let i = r.app.workspace.getRightLeaf(!1); - i && - (await i.setViewState({ type: it, active: !0 }), - r.app.workspace.revealLeaf(i)); - } -}; -var ar = class extends de.Plugin { - constructor() { - super(...arguments); - this._lastExportMtime = 0; - this._lastOcrMtimes = {}; - this._autoSyncRunning = !1; - this._lastSyncTime = null; - this._pollTimer = null; - this._embedProcess = null; - this._embedProgress = { current: 0, total: 0, key: "" }; - this._embedStderr = ""; - this._memoryStatusText = null; - } - async onload() { - (await this.loadSettings(), - this.saveSettings(), - kn(this.app), - this.registerView(it, (n) => new yt(n))); - try { - (0, de.addIcon)(Ct, xn); - } catch (n) {} - (this.addRibbonIcon(Ct, "PaperForge Dashboard", () => yt.open(this)), - Pe.find((n) => n.id === "paperforge-ocr-redo") && - this.addRibbonIcon("reset", "PaperForge: Redo OCR", () => { - let n = this.app.vault.adapter.basePath; - new de.Notice("PaperForge: Redo OCR starting..."); - let { path: i, extraArgs: a } = re(n, this.settings, void 0, void 0); - (0, He.execFile)( - i, - [...a, "-m", "paperforge", "ocr", "redo"], - { cwd: n, timeout: 6e5 }, - (c, l, u) => { - if (c) { - new de.Notice("PaperForge: Redo OCR failed"); - return; - } - new de.Notice("PaperForge: Redo OCR done"); - } - ); - }), - this.addSettingTab(new er(this.app, this)), - this.addCommand({ - id: "paperforge-status-panel", - name: `PaperForge: ${f("guide_open")}`, - callback: () => yt.open(this), - })); - for (let n of Pe) - this.addCommand({ - id: n.id, - name: `PaperForge: ${n.title}`, - callback: () => { - if (n.disabled) { - new de.Notice( - `[i] ${n.disabledMsg || "This action is not yet available."}`, - 6e3 - ); - return; - } - let i = this.app.vault.adapter.basePath; - new de.Notice(`PaperForge: running ${n.cmd}...`); - let { path: a, extraArgs: c = [] } = re( - i, - this.settings, - void 0, - void 0 - ), - l = Array.isArray(n.args) ? [...n.args] : []; - (0, He.execFile)( - a, - [...c, "-m", "paperforge", n.cmd, ...l], - { cwd: i, timeout: 3e5 }, - (u, p, h) => { - if (u) { - new de.Notice( - `[!!] ${n.cmd} failed: ${(h || u.message).slice(0, 120)}`, - 8e3 - ); - return; - } - new de.Notice( - `[OK] ${ - n.okMsg || - p - .trim() - .split( - ` -` - )[0] - .slice(0, 80) - }` - ); - } - ); - }, - }); - (this.settings.auto_update_on_startup === !0 && - this.settings.setup_complete && - setTimeout(() => this._autoUpdate(), 3e3), - this._startFilePolling(), - this._firstLaunchSnapshotMigration(), - this._checkReleaseNotes()); - } - _firstLaunchSnapshotMigration() { - let r = this.app.vault.adapter.basePath; - if (!r) return; - let i = Te(r).memoryStatePath; - if (!le.existsSync(i)) { - let a = re(r, this.settings, void 0, void 0); - [ - ["runtime-health", "--json"], - ["memory", "status", "--json"], - ["embed", "status", "--json"], - ].forEach((l) => { - let u = [...a.extraArgs, "-m", "paperforge", "--vault", r, ...l]; - (0, He.execFile)( - a.path, - u, - { cwd: r, timeout: 6e4, windowsHide: !0 }, - () => {} - ); - }); - } - } - _autoUpdate() { - let r = this.app.vault.adapter.basePath, - { path: n, extraArgs: i = [] } = re(r, this.settings, void 0, void 0), - a = this.manifest.version, - c = `paperforge==${a}`, - l = `git+https://github.com/LLLin000/PaperForge.git@${a}`, - u = (p, h) => { - (0, He.spawn)(n, [...i, "-m", "pip", "install", "--upgrade", p], { - cwd: r, - timeout: 12e4, - env: ot(), - }).on("close", (k) => h(k === 0)); - }; - (0, He.execFile)( - n, - [...i, "-c", "import paperforge; print(paperforge.__version__)"], - { cwd: r, timeout: 1e4 }, - (p, h) => { - let b = (g) => { - (console.log( - `[PaperForge] Auto-update: trying PyPI (paperforge==${a})` - ), - u(c, (x) => { - if (x) { - (console.log("[PaperForge] Auto-update: installed via PyPI"), - new de.Notice(`[OK] PaperForge CLI ${g}`, 5e3)); - return; - } - (console.warn( - "[PaperForge] Auto-update: PyPI failed, falling back to git..." - ), - u(l, (C) => { - C && - (console.log("[PaperForge] Auto-update: installed via git"), - new de.Notice(`[OK] PaperForge CLI ${g} (via git)`, 5e3)); - })); - })); - }; - if (p) { - b("installed"); - return; - } - let k = h.trim(); - k !== a && b(`${k} -> ${a}`); - } - ); - } - _startFilePolling() { - let r = this.app.vault.adapter.basePath; - this._pollTimer = setInterval(() => { - (this._checkExports(r), this._checkOcr(r)); - }, 12e4); - } - _checkExports(r) { - if (this._autoSyncRunning) return; - let n = Te(r).exportsDir; - if (!le.existsSync(n)) return; - let i = 0; - try { - le.readdirSync(n).forEach((a) => { - if (!a.endsWith(".json")) return; - let c = le.statSync(bt.join(n, a)); - c.mtimeMs > i && (i = c.mtimeMs); - }); - } catch (a) { - return; - } - i > this._lastExportMtime && - ((this._lastExportMtime = i), this._autoSync(r)); - } - _autoSync(r) { - if (this._autoSyncRunning) return; - this._autoSyncRunning = !0; - let n = re(r, this.settings, void 0, void 0); - if (!n.path) { - this._autoSyncRunning = !1; - return; - } - let i = `"${n.path}" -m paperforge --vault "${r}" sync`; - (0, He.exec)(i, { timeout: 12e4, encoding: "utf-8" }, (a, c, l) => { - ((this._autoSyncRunning = !1), - (this._memoryStatusText = null), - a || (this._lastSyncTime = new Date().toLocaleTimeString())); - try { - let u = Te(r).exportsDir, - p = 0; - (le.readdirSync(u).forEach((h) => { - h.endsWith(".json") && - (p = Math.max(p, le.statSync(bt.join(u, h)).mtimeMs)); - }), - (this._lastExportMtime = p)); - } catch (u) {} - }); - } - _checkOcr(r) { - if (this._autoSyncRunning) return; - let n = Te(r).ocrDir; - if (le.existsSync(n)) - try { - le.readdirSync(n, { withFileTypes: !0 }).forEach((i) => { - if (!i.isDirectory()) return; - let a = bt.join(n, i.name, "meta.json"); - if (!le.existsSync(a)) return; - let c = le.statSync(a), - l = this._lastOcrMtimes[i.name] || 0; - if ( - c.mtimeMs <= l || - ((this._lastOcrMtimes[i.name] = c.mtimeMs), this._autoSyncRunning) - ) - return; - this._autoSyncRunning = !0; - let u = re(r, this.settings, void 0, void 0); - if (!u.path) { - this._autoSyncRunning = !1; - return; - } - let p = `"${u.path}" -m paperforge --vault "${r}" sync`; - (0, He.exec)(p, { timeout: 3e4, encoding: "utf-8" }, () => { - ((this._autoSyncRunning = !1), (this._memoryStatusText = null)); - }); - }); - } catch (i) {} - } - readPaperforgeJson() { - let r = this.app.vault.adapter.basePath, - n = bt.join(r, "paperforge.json"), - i = { - system_dir: "System", - resources_dir: "Resources", - literature_dir: "Literature", - base_dir: "Bases", - }; - try { - if (!le.existsSync(n)) return i; - let a = le.readFileSync(n, "utf-8"), - c = JSON.parse(a), - l = c.vault_config || {}; - return { - system_dir: l.system_dir || c.system_dir || i.system_dir, - resources_dir: l.resources_dir || c.resources_dir || i.resources_dir, - literature_dir: - l.literature_dir || c.literature_dir || i.literature_dir, - base_dir: l.base_dir || c.base_dir || i.base_dir, - }; - } catch (a) { - return ( - console.warn( - "PaperForge: Failed to read paperforge.json, using defaults", - a - ), - i - ); - } - } - savePaperforgeJson(r) { - let n = this.app.vault.adapter.basePath, - i = bt.join(n, "paperforge.json"), - a = {}; - try { - le.existsSync(i) && (a = JSON.parse(le.readFileSync(i, "utf-8"))); - } catch (l) { - console.warn("PaperForge: Failed to read paperforge.json for update", l); - } - (!a.vault_config || typeof a.vault_config != "object") && - (a.vault_config = {}); - let c = ["system_dir", "resources_dir", "literature_dir", "base_dir"]; - for (let l of c) r[l] !== void 0 && (a.vault_config[l] = r[l]); - a.schema_version || (a.schema_version = "2"); - for (let l of c) delete a[l]; - try { - if ( - (le.writeFileSync(i, JSON.stringify(a, null, 2), "utf-8"), - this.settings) - ) { - let l = this.readPaperforgeJson(); - ((this.settings.system_dir = l.system_dir), - (this.settings.resources_dir = l.resources_dir), - (this.settings.literature_dir = l.literature_dir), - (this.settings.base_dir = l.base_dir)); - } - } catch (l) { - (console.error("PaperForge: Failed to write paperforge.json", l), - new de.Notice( - "PaperForge: Failed to save configuration to paperforge.json" - )); - } - } - onunload() { - (this._pollTimer && clearInterval(this._pollTimer), - this.app.workspace.detachLeavesOfType(it)); - } - async loadSettings() { - ((this.settings = Object.assign({}, Ft, await this.loadData())), - this.settings.features && - Ft.features && - (this.settings.features = Object.assign( - {}, - Ft.features, - this.settings.features || {} - )), - this.settings.frozen_skills || (this.settings.frozen_skills = {})); - let r = this.readPaperforgeJson(); - if ( - ((this.settings.system_dir = r.system_dir), - (this.settings.resources_dir = r.resources_dir), - (this.settings.literature_dir = r.literature_dir), - (this.settings.base_dir = r.base_dir), - this.settings.python_path && this.settings.python_path.trim()) - ) { - let n = this.settings.python_path.trim(); - le.existsSync(n) - ? (this.settings._python_path_stale = !1) - : (console.warn( - `PaperForge: Saved python_path "${n}" no longer exists - showing stale warning` - ), - (this.settings._python_path_stale = !0)); - } - } - async saveSettings() { - let r = {}; - for (let n of Object.keys(Ft)) - n in this.settings && (r[n] = this.settings[n]); - await this.saveData(r); - } - _checkReleaseNotes() { - let r = this.manifest.version; - if (this.settings.last_seen_version === r) return; - let c = (Sr().versions || []).find((u) => u.version === r); - class l extends de.Modal { - constructor(p, h) { - (super(p), (this._entry = h)); - } - onOpen() { - let { contentEl: p } = this; - if ( - (p.createEl("h2", { - text: `PaperForge v${r} \u66F4\u65B0\u8BF4\u660E`, - }), - this._entry) - ) { - if ( - (p.createEl("p", { - text: this._entry.title, - cls: "paperforge-modal-subtitle", - }), - this._entry.breaking_or_migration && - this._entry.breaking_or_migration.length > 0) - ) { - p.createEl("h4", { - text: "\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F", - }); - for (let h of this._entry.breaking_or_migration) - p.createEl("p", { - text: `\u2022 ${h}`, - cls: "paperforge-modal-item", - }); - } - if (this._entry.new_features && this._entry.new_features.length > 0) { - p.createEl("h4", { text: "\u65B0\u529F\u80FD" }); - for (let h of this._entry.new_features) - p.createEl("p", { - text: `\u2022 ${h}`, - cls: "paperforge-modal-item", - }); - } - if (this._entry.fixes && this._entry.fixes.length > 0) { - p.createEl("h4", { text: "\u4FEE\u590D" }); - for (let h of this._entry.fixes) - p.createEl("p", { - text: `\u2022 ${h}`, - cls: "paperforge-modal-item", - }); - } - if ( - this._entry.recommended_actions && - this._entry.recommended_actions.length > 0 - ) { - let h = p.createEl("div", { - cls: "paperforge-release-recommended", - }); - (h.createEl("h4", { text: "\u5EFA\u8BAE\u64CD\u4F5C", cls: "" }), - (h.style.marginBottom = "8px")); - for (let b of this._entry.recommended_actions) - h.createEl("p", { - text: `\u2022 ${b}`, - cls: "paperforge-release-item-bold", - }); - } - } else - p.createEl("p", { - text: - "\u7248\u672C\u5DF2\u66F4\u65B0\u81F3 v" + - r + - "\uFF0C\u8BF7\u524D\u5F80\u8BBE\u7F6E \u2192 \u66F4\u65B0\u4E0E\u624B\u518C \u67E5\u770B\u5B8C\u6574\u66F4\u65B0\u8BB0\u5F55\u3002", - }); - new de.Setting(p).addButton((h) => - h - .setButtonText("\u77E5\u9053\u4E86") - .setCta() - .onClick(() => { - this.close(); - }) - ); - } - onClose() { - let { contentEl: p } = this; - p.empty(); - } - } - (new l(this.app, c).open(), - (this.settings.last_seen_version = r), - this.saveSettings()); - } -}; +`)[0].trim();return!s||s.startsWith("###")||s.startsWith("##")?null:s.length>300?s.slice(0,300)+"...":s}_renderRecentDiscussionCard(e,t){let r=e.createEl("div",{cls:"paperforge-discussion-card"});if(r.style.display="none",!t.note_path)return;let n=t.note_path.lastIndexOf("/"),s=(n!==-1?t.note_path.substring(0,n):".")+"/ai/discussion.md";this.app.vault.adapter.exists(s).then(l=>{if(l)return this.app.vault.adapter.read(s)}).then(async l=>{if(!l)return;let i=this._parseDiscussionMD(l);if(!i||i.length===0)return;r.style.display="block",r.createEl("div",{cls:"paperforge-discussion-header"}).createEl("span",{cls:"paperforge-discussion-title",text:"\u6700\u8FD1\u8BA8\u8BBA"});for(let g of i){let p=r.createEl("div",{cls:"paperforge-discussion-item"}),f=p.createEl("div",{cls:"paperforge-discussion-q"});f.createEl("span",{cls:"paperforge-discussion-q-label",text:"\u63D0\u95EE\uFF1A"}),f.createEl("span",{cls:"paperforge-discussion-q-text",text:g.question});let y=p.createEl("div",{cls:"paperforge-discussion-a"}),b=!1;if(g.answer&&g.answer.length>500&&(b=!0,y.classList.add("paperforge-discussion-a-collapsed")),await B.MarkdownRenderer.render(this.app,g.answer||"",y,s,this),b){let m=!1;p.style.cursor="pointer",p.addEventListener("click",()=>{m=!m,y.classList.toggle("paperforge-discussion-a-collapsed",!m),y.classList.toggle("paperforge-discussion-a-expanded",m)})}}r.createEl("a",{cls:"paperforge-discussion-viewall",text:"\u67E5\u770B\u5168\u90E8\u8BA8\u8BBA \u2192"}).addEventListener("click",g=>{g.preventDefault(),this.app.vault.getAbstractFileByPath(s)?this.app.workspace.openLinkText(s,""):new B.Notice("\u8BA8\u8BBA\u6587\u4EF6\u5C1A\u672A\u751F\u6210")})}).catch(l=>{console.error("PaperForge: discussion.md read error",s,l.message)})}_parseDiscussionMD(e){let t=e.split(/\n## /).slice(1);if(t.length===0)return null;let r=t[t.length-1],n=[],a=r.split(/\*\*\u95EE\u9898:\*\*/).slice(1);for(let s of a){let l=s.match(/\*\*\u89E3\u7B54:\*\*/);if(!l)continue;let i=s.substring(0,l.index).trim(),c=s.substring(l.index+3+4).trim();n.push({question:i,answer:c})}return n.slice(-3)}_renderPaperTechnicalDetails(e,t){let r=this._currentPaperKey,n=e.createEl("div",{cls:"paperforge-technical-details"}),a=n.createEl("button",{cls:"paperforge-technical-details-toggle"}),s=n.createEl("div",{cls:"paperforge-technical-details-body"});s.style.display="none",this._techDetailsExpanded?(s.style.display="block",a.setText("\u6280\u672F\u8BE6\u60C5 \u25BE")):a.setText("\u6280\u672F\u8BE6\u60C5 \u25B8"),a.addEventListener("click",()=>{let p=s.style.display!=="none";s.style.display=p?"none":"block",a.setText(p?"\u6280\u672F\u8BE6\u60C5 \u25B8":"\u6280\u672F\u8BE6\u60C5 \u25BE"),this._techDetailsExpanded=!p});let l=s.createEl("div",{cls:"paperforge-workflow-toggles"}),i=[{key:"do_ocr",label:"OCR",hint:"\u52A0\u5165 OCR"},{key:"analyze",label:"\u7CBE\u8BFB",hint:"\u6807\u8BB0\u7CBE\u8BFB"}];for(let p of i){let f=l.createEl("label",{cls:"paperforge-workflow-toggle"}),y=f.createEl("input",{type:"checkbox",cls:"paperforge-workflow-checkbox"});y.checked=t[p.key]===!0,f.createEl("span",{cls:"paperforge-workflow-toggle-label",text:p.label}),f.createEl("span",{cls:"paperforge-workflow-toggle-hint",text:p.hint}),y.addEventListener("change",async()=>{let b=t.note_path?this.app.vault.getAbstractFileByPath(t.note_path):null;if(!b){new B.Notice("[!!] Note file not found",6e3);return}let m=y.checked;await this.app.fileManager.processFrontMatter(b,x=>{x[p.key]=m}),this._patchCachedEntry(r,{[p.key]:m}),this._currentPaperEntry=Ke(this._currentPaperEntry,{[p.key]:m})})}let c=t.health||{},d=[["PDF Health",c.pdf_health||"\u2014"],["OCR Status",t.ocr_status||"\u2014"],["Asset Health",c.asset_health||"\u2014"],["Note Path",t.note_path||"\u2014"],["Fulltext Path",t.fulltext_path||"\u2014"]],g=new Set(["Note Path","Fulltext Path","Key"]);for(let[p,f]of d){let y=s.createEl("div",{cls:"paperforge-technical-row"});y.createEl("span",{cls:"paperforge-technical-label",text:p});let b=y.createEl("span",{cls:"paperforge-technical-value",text:String(f)});g.has(p)&&f&&f!=="\u2014"&&(b.addClass("pf-copy"),b.addEventListener("click",()=>{navigator.clipboard.writeText(f),new B.Notice(p+" copied")}))}}_renderNextStepCard(e,t,r){var i,c;let n=t.next_step||"ready",a={sync:{label:"Sync Needed",text:"This paper needs to be synced from Zotero. Click to run sync.",cmd:"sync",icon:"\u21BB"},ocr:{label:"OCR Needed",text:"Fulltext is missing but PDF is present. Click to run OCR.",cmd:"ocr",icon:"\u229E"},repair:{label:"Repair Needed",text:"State divergence or path errors detected. Click to repair.",cmd:"repair",icon:"\u21BA"},"rebuild index":{label:"Rebuild Needed",text:"Index may be stale. Click to run sync to rebuild.",cmd:"sync",icon:"\u21BB"},"/pf-deep":{label:"Ready for Deep Reading",text:"Fulltext is ready. Copy /pf-deep command and run in your agent.",cmd:null,icon:"\u{1F50D}"},ready:{label:"All Set",text:"This paper is fully processed and ready for use.",cmd:"ready",icon:"\u2713"}},s=a[n]||a.ready,l=e.createEl("div",{cls:"paperforge-next-step-card"});if(n==="ready"&&l.addClass("ready"),l.createEl("div",{cls:"paperforge-next-step-label",text:"Recommended Next Step"}),l.createEl("div",{cls:"paperforge-next-step-text",text:s.text}),s.cmd&&s.cmd!=="ready"){let d=l.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:s.icon+" "+s.label}),d.addEventListener("click",()=>{let g=Y.find(p=>p.cmd===s.cmd);g&&this._runAction(g,d)})}else if(n==="/pf-deep"){let d=l.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:"\u{1F4CB} "+o("copy_pf_deep_cmd")}),d.addEventListener("click",()=>{let b="/pf-deep "+r;navigator.clipboard.writeText(b).then(()=>{d.setText("\u2713 "+o("copied")),new B.Notice(b+" copied")}).catch(()=>{new B.Notice("[!!] Clipboard write failed",6e3)})});let g=((c=(i=this.app.plugins.plugins.paperforge)==null?void 0:i.settings)==null?void 0:c.agent_platform)||"opencode",f={opencode:"OpenCode",claude:"Claude Code",cursor:"Cursor",github_copilot:"GitHub Copilot",windsurf:"Windsurf",codex:"Codex",gemini:"Gemini CLI",cline:"Cline"}[g]||g;l.createEl("div",{cls:"paperforge-agent-platform-label"}).setText(o("run_in_agent").replace("{0}",f))}else n==="ready"&&l.createEl("button",{cls:"paperforge-next-step-trigger"}).createEl("span",{text:"\u2713 "+s.label})}_openFulltext(e){if(!e){new B.Notice("[!!] No fulltext path available for this paper",6e3);return}let t=this.app.vault.getAbstractFileByPath(e);t?this.app.workspace.openLinkText(t.path,""):new B.Notice("[!!] Fulltext file not found: "+e,6e3)}_renderCollectionMode(){let e=this._currentDomain||"Unknown",t=this._filterByDomain(e);if(t.length===0){this._renderGlobalMode();return}if(!this._contentEl)return;let r=this._contentEl.createEl("div",{cls:"paperforge-collection-view"}),n=t.length,a=0,s=0,l=0,i=0,c=0,d=0,g=0;for(let _ of t){_.has_pdf&&a++,_.ocr_status==="done"&&s++,_.ocr_status==="done"&&_.analyze===!0&&l++,_.deep_reading_status==="done"&&i++;let v=_.ocr_status||"";v==="pending"||v==="queued"?c++:v==="processing"?d++:(v==="failed"||v==="blocked"||v==="done_incomplete"||v==="nopdf")&&g++}r.createEl("div",{cls:"paperforge-collection-header"}).createEl("div",{cls:"paperforge-collection-title",text:e});let f=r.createEl("div",{cls:"paperforge-workflow-overview"});f.createEl("div",{cls:"paperforge-section-label",text:"Workflow Overview"});let y=f.createEl("div",{cls:"paperforge-workflow-funnel"}),b=[{value:n,label:"Total"},{value:a,label:"PDF Ready"},{value:s,label:"OCR Done"},{value:i,label:"Deep Read"}];for(let _=0;_0){let _=r.createEl("div",{cls:"paperforge-ocr-section"}),v=_.createEl("div",{cls:"paperforge-collection-ocr-header"});v.createEl("h4",{cls:"paperforge-ocr-title",text:"OCR Pipeline"});let k=v.createEl("span",{cls:"paperforge-ocr-badge idle"});d>0?(k.addClass("active"),k.setText("Processing")):c>0?k.setText("Pending"):(k.addClass("idle"),k.setText("Idle"));let S=_.createEl("div",{cls:"paperforge-progress-track"});d>0&&S.addClass("paperforge-processing");let P=c+d+s+g,A=[{cls:"pending",count:c},{cls:"active",count:d},{cls:"done",count:s},{cls:"failed",count:g}];for(let z of A)if(z.count>0){let O=(z.count/P*100).toFixed(1);S.createEl("div",{cls:`paperforge-progress-seg ${z.cls}`,attr:{style:`width:${O}%`}})}let T=_.createEl("div",{cls:"paperforge-ocr-counts"}),I=[{cls:"pending",value:c,label:"Pending"},{cls:"active",value:d,label:"Processing"},{cls:"done",value:s,label:"Done"},{cls:"failed",value:g,label:"Attention"}];for(let z of I){let O=T.createEl("div",{cls:"paperforge-ocr-count"});O.createEl("div",{cls:"paperforge-ocr-count-value",text:z.value.toString()}),O.createEl("div",{cls:"paperforge-ocr-count-label",text:z.label})}}let m=r.createEl("div",{cls:"paperforge-collection-actions"}),x=m.createEl("button",{cls:"paperforge-contextual-btn primary"});x.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),x.createEl("span",{text:"Run OCR"}),x.addEventListener("click",()=>{let _=Y.find(v=>v.id==="paperforge-ocr");_&&this._runAction(_,x)});let w=m.createEl("button",{cls:"paperforge-contextual-btn"});w.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),w.createEl("span",{text:"Sync Library"}),w.addEventListener("click",()=>{let _=Y.find(v=>v.id==="paperforge-sync");_&&this._runAction(_,w)});let E=m.createEl("button",{cls:"paperforge-contextual-btn warn"});E.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),E.createEl("span",{text:"Redo OCR"}),E.addEventListener("click",()=>{let _=Y.find(v=>v.id==="paperforge-ocr-redo");_&&this._runAction(_,E)}),this.renderSearchSection(r)}_refreshCurrentMode(){if(!(!this._currentMode||!this._contentEl)){this._contentEl.empty(),this._contentEl.addClass("switching"),this._invalidateIndex(),this._currentPaperEntry=this._currentPaperKey?this._findEntry(this._currentPaperKey):null,this._renderModeHeader(this._currentMode);try{switch(this._currentMode){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}finally{setTimeout(()=>{this._contentEl&&this._contentEl.removeClass("switching")},50)}}}_switchToVersionMode(e){let r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){new B.Notice("Cannot determine vault path");return}this._versionPapers=tt(n),this._versionFilter="",this._currentMode="versions",this._currentFilePath=null,this._techDetailsExpanded=!1,this._contentEl&&(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader("versions"),this._renderVersionMode())}_renderVersionMode(){if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-version-panel"}),r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){e.createEl("div",{cls:"paperforge-status-error",text:"Could not determine vault path"});return}(!this._versionPapers||this._versionPapers.length===0)&&(this._versionPapers=tt(n));let a=e.createEl("div",{cls:"paperforge-version-left"}),s=e.createEl("div",{cls:"paperforge-version-right"}),l=a.createEl("input",{cls:"paperforge-version-filter",attr:{type:"text",placeholder:o("version_filter_placeholder")}});l.value=this._versionFilter;let i=a.createEl("div",{cls:"paperforge-version-paper-list"}),c=()=>{i.empty();let x=this._versionFilter.toLowerCase(),w=this._versionPapers?this._versionPapers.filter(_=>!x||_.key.toLowerCase().includes(x)||_.title.toLowerCase().includes(x)):[];if(w.length===0){i.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let E=i.createEl("div",{cls:"paperforge-meta",text:o("version_papers_count").replace("{n}",String(w.length))});for(let _ of w){let v=i.createEl("div",{cls:"paperforge-version-paper-item"}),k=v.createEl("span",{cls:"paperforge-version-paper-title",text:_.title}),S=v.createEl("span",{cls:"paperforge-version-paper-versions",text:_.versions.map(P=>P.label).join(" ")});v.addEventListener("click",()=>{i.querySelectorAll(".paperforge-version-paper-item.selected").forEach(P=>P.removeClass("selected")),v.addClass("selected"),g(_)})}};l.addEventListener("input",()=>{this._versionFilter=l.value,c()});let d=s.createEl("div",{cls:"paperforge-version-timeline-area"}),g=x=>{if(d.empty(),d.createEl("div",{cls:"paperforge-version-timeline-header"}).createEl("span",{cls:"pf-title",text:x.title}),x.versions.length===0){d.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let E=d.createEl("div",{cls:"paperforge-version-timeline"});for(let _ of x.versions){let v=_.label===x.currentLabel,k=E.createEl("div",{cls:"paperforge-version-entry"+(v?" paperforge-version-current":"")}),S=k.createEl("div",{cls:"paperforge-version-dot"}),P=k.createEl("div",{cls:"paperforge-version-content"}),A=P.createEl("div",{cls:"paperforge-version-label-row"});A.createEl("span",{cls:"paperforge-version-label",text:_.label}),v&&A.createEl("span",{cls:"paperforge-version-current-tag",text:o("version_current")});let T=_.created_at?_.created_at.slice(0,10):"";P.createEl("div",{cls:"paperforge-meta",text:T+" \u2014 "+_.source});let I=_.fulltext_size?_.fulltext_size>1024?(_.fulltext_size/1024).toFixed(0)+"KB":_.fulltext_size+"B":"";I&&P.createEl("div",{cls:"paperforge-meta",text:I});let z=P.createEl("div",{cls:"paperforge-version-actions"});z.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_btn")}).addEventListener("click",()=>{Ct(n,x.key,_.label)?new B.Notice(o("version_restore_done").replace("{label}",_.label)):new B.Notice("Restore failed",6e3)}),x.versions.length>1&&!v&&z.createEl("button",{cls:"pf-btn-secondary",text:o("version_compare_btn")}).addEventListener("click",()=>{f(x,_.label,x.currentLabel)})}},p=s.createEl("div",{cls:"paperforge-version-compare"});p.style.display="none";let f=(x,w,E)=>{let _=Ft(n,x.key,w,E);p.style.display="block",p.empty();let v=p.createEl("div",{cls:"paperforge-version-compare-header"});if(v.createEl("span",{cls:"pf-title",text:o("version_compare_title").replace("{vA}",w).replace("{vB}",E)}),v.createEl("span",{cls:"paperforge-meta",text:o("version_compare_paragraphs").replace("{n}",String(_.length))}),_.length===0){p.createEl("div",{cls:"paperforge-meta",text:"No changes"});return}let k=p.createEl("div",{cls:"paperforge-version-diff-list"});for(let S of _){let P=k.createEl("div",{cls:"paperforge-version-diff-row"}),A=S.type==="added"?"[+]":S.type==="removed"?"[-]":"[~]",T=S.heading||"paragraph "+(S.paragraphIndex+1);P.createEl("span",{cls:"paperforge-version-diff-label",text:A+" "+T}),S.oldText&&P.createEl("pre",{cls:"paperforge-version-diff-old",text:S.oldText.slice(0,200)}),S.newText&&P.createEl("pre",{cls:"paperforge-version-diff-new",text:S.newText.slice(0,200)})}},y=e.createEl("div",{cls:"paperforge-version-actions-bar"}),b=y.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_selected")}),m=y.createEl("button",{cls:"pf-btn-secondary",text:o("version_clear_old").replace("{size}","")});c()}renderSearchSection(e){this._searchContainer=e.createEl("div",{cls:"paperforge-search-section"}),this._searchContainer.createEl("div",{cls:"paperforge-search-header"}).createEl("span",{cls:"pf-label",text:"Search"});let r=this._searchContainer.createEl("div",{cls:"paperforge-search-input-row"}),n=r.createEl("span",{cls:"paperforge-search-mode",text:"M"});this._searchInput=r.createEl("input",{cls:"paperforge-search-input",attr:{type:"text",placeholder:"Search papers... (@ for deep search)"}}),this._searchResultsEl=this._searchContainer.createEl("div",{cls:"paperforge-search-results"}),this._searchInput.addEventListener("input",()=>{var s;let a=((s=this._searchInput)==null?void 0:s.value)||"";a.startsWith("@")&&!a.startsWith("@ ")?(n.setText("@"),n.addClass("deep")):(n.setText("M"),n.removeClass("deep")),clearTimeout(this._searchTimer),!a.startsWith("@")&&a.trim()&&(this._searchTimer=setTimeout(()=>{this.executeSearch()},200))}),this._searchInput.addEventListener("keydown",a=>{a.key==="Enter"&&(a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0),this.executeSearch())})}async executeSearch(){if(!this._searchInput||!this._searchResultsEl)return;let e=this._searchInput.value.trim();if(!e)return;let t=e.startsWith("@"),r=t?e.slice(1).trim():e;if(!r)return;let n=t?"retrieve":"search",a=this.app.vault.adapter,s="";if(a&&typeof a=="object"&&"basePath"in a){let b=a.basePath;s=typeof b=="string"?b:""}if(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-loading",text:"Searching..."}),!s){this._renderSearchError("Could not determine vault path");return}let l=null,c=this.app.plugins;if(c&&typeof c=="object"&&"plugins"in c){let b=c.plugins;if(b&&typeof b=="object"&&"paperforge"in b){let m=b.paperforge;m&&typeof m=="object"&&"settings"in m&&(l=m.settings)}}let{path:d,extraArgs:g=[]}=L(s,l,void 0,void 0),p=n==="retrieve"?["--deep"]:[],f=(0,fe.spawn)(d,[...g,"-m","paperforge",n,r,...p,"--json"],{cwd:s,timeout:3e4}),y=[];f.stdout.on("data",b=>{y.push(b.toString("utf-8"))}),f.stderr.on("data",()=>{}),f.on("close",b=>{if(b!==0){this._renderSearchError(`Search failed (exit ${b})`);return}let m=y.join(""),x=m.indexOf("{"),w=m.lastIndexOf("}"),E="";if(x!==-1&&w>x)E=m.slice(x,w+1);else{let _=m.indexOf("["),v=m.lastIndexOf("]");_!==-1&&v>_&&(E=m.slice(_,v+1))}if(!E){this._renderSearchError("No JSON output from CLI");return}try{let _=JSON.parse(E),v=[];if(_&&typeof _=="object"&&"data"in _){let k=_.data;if(k&&typeof k=="object"){let S=k;"matches"in S&&Array.isArray(S.matches)&&(v=S.matches)}}this.renderSearchResults(v,t)}catch(_){let v=_ instanceof Error?_.message:String(_);this._renderSearchError("Failed to parse results: "+v)}}),f.on("error",b=>{this._renderSearchError("Process error: "+b.message)})}renderSearchResults(e,t){if(!this._searchResultsEl)return;if(this._searchResultsEl.empty(),e.length===0){this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty",text:"No results found."});return}let r=this._searchResultsEl.createEl("div",{cls:"paperforge-search-results-header"});r.createEl("span",{text:`${e.length} result${e.length!==1?"s":""}`}),r.createEl("span",{cls:"paperforge-search-mode",text:t?"@":"M"});for(let n of e){if(!n||typeof n!="object")continue;let a=n,s=this._searchResultsEl.createEl("div",{cls:"paperforge-search-result-card",attr:{role:"button"}}),l=typeof a.title=="string"?a.title:typeof a.file_name=="string"?a.file_name:"(untitled)";s.createEl("div",{cls:"paperforge-search-result-title",text:l});let i=typeof a.zotero_key=="string"?a.zotero_key:"",c=typeof a.main_note_path=="string"&&a.main_note_path?a.main_note_path:null,d=typeof a.note_path=="string"&&a.note_path?a.note_path:null,g=c||d;if(!g&&i){let y=this._getCachedIndex().find(b=>b!==null&&typeof b=="object"&&"zotero_key"in b&&b.zotero_key===i);if(y&&typeof y=="object"){let b=y;g=typeof b.main_note_path=="string"&&b.main_note_path?b.main_note_path:typeof b.note_path=="string"&&b.note_path?b.note_path:null}}g?s.addEventListener("click",f=>{let y=f.ctrlKey||f.metaKey;this.app.workspace.openLinkText(g,"",y)}):s.addEventListener("click",()=>{new B.Notice("[!!] Note not found: "+(i||"unknown"),6e3)});let p=s.createEl("div",{cls:"paperforge-search-result-meta"});if(typeof a.first_author=="string"&&a.first_author&&p.createEl("span",{cls:"paperforge-search-result-author",text:a.first_author}),typeof a.journal=="string"&&a.journal&&p.createEl("span",{cls:"paperforge-search-result-journal",text:a.journal}),a.score!==void 0){let f=a.score,y=typeof f=="number"?f.toFixed(3):String(f);p.createEl("span",{cls:"paperforge-search-result-score",text:"Score: "+y})}if(typeof a.domain=="string"&&a.domain&&s.createEl("span",{cls:"paperforge-search-result-tag",text:a.domain}),typeof a.abstract=="string"&&a.abstract){let f=a.abstract;s.createEl("div",{cls:"paperforge-search-result-abstract",text:f.length>200?f.slice(0,200)+"...":f})}if(t&&typeof a.text=="string"&&a.text){let f=a.text;s.createEl("div",{cls:"paperforge-search-result-source",text:f.length>300?f.slice(0,300)+"...":f})}}}_renderSearchError(e){this._searchResultsEl&&(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-error",text:e}))}_runAction(e,t){var p,f;if(e.disabled){new B.Notice(`[i] ${e.disabledMsg||"This action is not yet available."}`,6e3);return}if(t.classList.contains("running"))return;t.addClass("running");let r=this.app.vault.adapter.basePath;this._showMessage("Processing...","running");let n=Array.isArray(e.args)?[...e.args]:[];if(e.needsKey){let y=this.app.workspace.getActiveFile(),b=null;if(y){let m=this.app.metadataCache.getFileCache(y);if(m&&m.frontmatter&&m.frontmatter.zotero_key?b=m.frontmatter.zotero_key:b=this._extractZoteroKeyFromPath(y.path),b)n=[...n,b];else if(m&&m.frontmatter){this._showMessage("[!!] No zotero_key in active note frontmatter","error"),new B.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}else{this._showMessage("[!!] No frontmatter in active note","error"),new B.Notice("[!!] The active note has no frontmatter with a zotero_key",6e3),t.removeClass("running");return}}else{this._showMessage("[!!] No active note open","error"),new B.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}}e.needsFilter&&(n=[...n,"--all"]);let a=e.needsFilter?6e4:e.needsKey?3e4:6e5,{path:s,extraArgs:l=[]}=L(r,(f=(p=this.app.plugins.plugins.paperforge)==null?void 0:p.settings)!=null?f:null,void 0,void 0),i=(0,fe.spawn)(s,[...l,"-m","paperforge",e.cmd,...n],{cwd:r,timeout:a}),c=[],d=Date.now(),g=setInterval(()=>this._fetchStats(!0),4e3);i.stdout.on("data",y=>{let b=y.toString("utf-8").split(` +`).filter(Boolean);for(let m of b){let x=m.trim();x&&(c.push(x),this._showMessage(c.slice(-8).join(` +`),"running"))}}),i.stderr.on("data",y=>{let b=y.toString("utf-8").split(` +`).filter(Boolean);for(let m of b){if(m.includes("\r")||m.includes("%")||m.includes("\u2588"))continue;let x=m.trim();x&&!x.match(/^\d+%|^\|/)&&(c.push(x),this._showMessage(c.slice(-8).join(` +`),"running"))}}),i.on("close",y=>{clearInterval(g),t.removeClass("running");let b=((Date.now()-d)/1e3).toFixed(1);if(y!==0){let m=c.slice(-3).join(" | ")||"exit code "+y;(e.cmd==="repair"||e.cmd==="ocr")&&y===1?(this._showMessage("[WARN] "+m,"running"),new B.Notice("[WARN] "+e.cmd+" partial: "+m,8e3),this._fetchStats(!0)):(this._showMessage("[!!] "+m,"error"),new B.Notice("[!!] "+e.cmd+" failed: "+m,8e3))}else if(e.needsKey||e.needsFilter){let m=c.join(` +`);if(m.trim())try{JSON.parse(m),navigator.clipboard.writeText(m).then(()=>{let x=`${b}s \u2014 ${m.length} chars copied`;this._showMessage("[OK] "+e.title+": "+x,"ok"),new B.Notice("[OK] "+e.okMsg+" \u2014 "+m.length+" chars")}).catch(x=>{this._showMessage("[!!] Clipboard write failed: "+x.message,"error"),new B.Notice("[!!] Clipboard error",6e3)})}catch(x){this._showMessage("[!!] Invalid JSON from "+e.title,"error"),new B.Notice("[!!] "+e.title+" returned invalid JSON: "+x.message.slice(0,100),8e3)}else this._showMessage("[!!] No output from context command","error"),new B.Notice("[!!] Context command returned empty output",8e3);this._fetchStats(!0)}else{let x=c.filter(E=>E.match(/updated \d+/)).pop()||c[c.length-1]||"",w=`${b}s \u2014 ${x}`;this._showMessage("[OK] "+e.title+": "+w,"ok"),new B.Notice("[OK] "+e.okMsg),this._contentEl&&this._contentEl.removeClass("switching"),this._cachedStats=null;try{this._fetchStats(!1)}catch(E){console.log("[PF] fetchStats error:",E)}console.log("[PF] close cmd="+e.cmd+" id="+e.id),e.cmd==="sync"&&Ne(this.app,this.app.plugins.plugins.paperforge,r)}}),i.on("error",y=>{t.removeClass("running"),this._contentEl&&this._contentEl.removeClass("switching"),this._showMessage("[!!] "+y.message,"error"),new B.Notice("[!!] Cannot start: "+y.message,8e3)})}_showMessage(e,t){this._messageEl&&(this._messageEl.setText(e),this._messageEl.className=`paperforge-message msg-${t}`)}_renderModeHeader(e){if(!this._modeContextEl)return;this._modeContextEl.empty();let t=this._modeContextEl.createEl("span",{cls:"paperforge-mode-badge"}),r="";switch(e){case"global":t.addClass("global"),t.setText("Global"),this._headerTitle&&this._headerTitle.setText("PaperForge");break;case"paper":t.addClass("paper"),t.setText("Paper"),this._headerTitle&&this._headerTitle.setText("Paper"),this._currentPaperEntry&&this._currentPaperEntry.title?r=this._currentPaperEntry.title:this._currentPaperKey?(r=this._currentPaperKey,this._modeContextEl.createEl("span",{cls:"paperforge-mode-warning",text:"Not found in index"})):r="Unknown paper";break;case"collection":t.addClass("collection"),t.setText("Collection"),this._headerTitle&&this._headerTitle.setText("Collection"),r=this._currentDomain||"Unknown Domain";break;case"versions":t.addClass("versions"),t.setText(o("version_panel_title")),this._headerTitle&&this._headerTitle.setText(o("version_panel_title"));break}r&&this._modeContextEl.createEl("span",{cls:"paperforge-mode-name",text:r})}_setupEventSubscriptions(){let e=this.app.workspace.on("active-leaf-change",()=>{this._leafChangeTimer&&clearTimeout(this._leafChangeTimer),this._leafChangeTimer=setTimeout(()=>{let r=this._resolveModeForFile(this.app.workspace.getActiveFile()),n=r.mode,a=r.filePath;this._currentMode===n&&this._currentFilePath===a||this._detectAndSwitch()},300)});this._modeSubscribers.push({event:"active-leaf-change",ref:e});let t=this.app.vault.on("modify",r=>{r&&r.path&&r.path.endsWith("formal-library.json")&&(this._invalidateIndex(),this._refreshCurrentMode())});this._modeSubscribers.push({event:"modify",ref:t})}static async open(e){let t=e.app.workspace.getLeavesOfType(_e);if(t.length>0){e.app.workspace.revealLeaf(t[0]);return}let r=e.app.workspace.getRightLeaf(!1);r&&(await r.setViewState({type:_e,active:!0}),e.app.workspace.revealLeaf(r))}};var He=class extends K.Plugin{constructor(){super(...arguments);this._lastExportMtime=0;this._lastOcrMtimes={};this._autoSyncRunning=!1;this._lastSyncTime=null;this._pollTimer=null;this._embedProcess=null;this._embedProgress={current:0,total:0,key:""};this._embedStderr="";this._memoryStatusText=null}async onload(){await this.loadSettings(),this.saveSettings(),at(this.app),this.registerView(_e,t=>new Ee(t));try{(0,K.addIcon)(Ce,st)}catch(t){}this.addRibbonIcon(Ce,"PaperForge Dashboard",()=>Ee.open(this)),Y.find(t=>t.id==="paperforge-ocr-redo")&&this.addRibbonIcon("reset","PaperForge: Redo OCR",()=>{let t=this.app.vault.adapter.basePath;new K.Notice("PaperForge: Redo OCR starting...");let{path:r,extraArgs:n}=L(t,this.settings,void 0,void 0);(0,ie.execFile)(r,[...n,"-m","paperforge","ocr","redo"],{cwd:t,timeout:6e5},(a,s,l)=>{if(a){new K.Notice("PaperForge: Redo OCR failed");return}new K.Notice("PaperForge: Redo OCR done")})}),this.addSettingTab(new je(this.app,this)),this.addCommand({id:"paperforge-status-panel",name:`PaperForge: ${o("guide_open")}`,callback:()=>Ee.open(this)});for(let t of Y)this.addCommand({id:t.id,name:`PaperForge: ${t.title}`,callback:()=>{if(t.disabled){new K.Notice(`[i] ${t.disabledMsg||"This action is not yet available."}`,6e3);return}let r=this.app.vault.adapter.basePath;new K.Notice(`PaperForge: running ${t.cmd}...`);let{path:n,extraArgs:a=[]}=L(r,this.settings,void 0,void 0),s=Array.isArray(t.args)?[...t.args]:[];(0,ie.execFile)(n,[...a,"-m","paperforge",t.cmd,...s],{cwd:r,timeout:3e5},(l,i,c)=>{if(l){new K.Notice(`[!!] ${t.cmd} failed: ${(c||l.message).slice(0,120)}`,8e3);return}new K.Notice(`[OK] ${t.okMsg||i.trim().split(` +`)[0].slice(0,80)}`)})}});this.settings.auto_update_on_startup===!0&&this.settings.setup_complete&&setTimeout(()=>this._autoUpdate(),3e3),this._startFilePolling(),this._firstLaunchSnapshotMigration(),this._checkReleaseNotes()}_firstLaunchSnapshotMigration(){let e=this.app.vault.adapter.basePath;if(!e)return;let r=Q(e).memoryStatePath;if(!H.existsSync(r)){let n=L(e,this.settings,void 0,void 0);[["runtime-health","--json"],["memory","status","--json"],["embed","status","--json"]].forEach(s=>{let l=[...n.extraArgs,"-m","paperforge","--vault",e,...s];(0,ie.execFile)(n.path,l,{cwd:e,timeout:6e4,windowsHide:!0},()=>{})})}}_autoUpdate(){let e=this.app.vault.adapter.basePath,{path:t,extraArgs:r=[]}=L(e,this.settings,void 0,void 0),n=this.manifest.version,a=`paperforge==${n}`,s=`git+https://github.com/LLLin000/PaperForge.git@${n}`,l=(i,c)=>{(0,ie.spawn)(t,[...r,"-m","pip","install","--upgrade",i],{cwd:e,timeout:12e4,env:me()}).on("close",g=>c(g===0))};(0,ie.execFile)(t,[...r,"-c","import paperforge; print(paperforge.__version__)"],{cwd:e,timeout:1e4},(i,c)=>{let d=p=>{console.log(`[PaperForge] Auto-update: trying PyPI (paperforge==${n})`),l(a,f=>{if(f){console.log("[PaperForge] Auto-update: installed via PyPI"),new K.Notice(`[OK] PaperForge CLI ${p}`,5e3);return}console.warn("[PaperForge] Auto-update: PyPI failed, falling back to git..."),l(s,y=>{y&&(console.log("[PaperForge] Auto-update: installed via git"),new K.Notice(`[OK] PaperForge CLI ${p} (via git)`,5e3))})})};if(i){d("installed");return}let g=c.trim();g!==n&&d(`${g} -> ${n}`)})}_startFilePolling(){let e=this.app.vault.adapter.basePath;this._pollTimer=setInterval(()=>{this._checkExports(e),this._checkOcr(e)},12e4)}_checkExports(e){if(this._autoSyncRunning)return;let t=Q(e).exportsDir;if(!H.existsSync(t))return;let r=0;try{H.readdirSync(t).forEach(n=>{if(!n.endsWith(".json"))return;let a=H.statSync(ke.join(t,n));a.mtimeMs>r&&(r=a.mtimeMs)})}catch(n){return}r>this._lastExportMtime&&(this._lastExportMtime=r,this._autoSync(e))}_autoSync(e){if(this._autoSyncRunning)return;this._autoSyncRunning=!0;let t=L(e,this.settings,void 0,void 0);if(!t.path){this._autoSyncRunning=!1;return}let r=`"${t.path}" -m paperforge --vault "${e}" sync`;(0,ie.exec)(r,{timeout:12e4,encoding:"utf-8"},(n,a,s)=>{this._autoSyncRunning=!1,this._memoryStatusText=null,n||(this._lastSyncTime=new Date().toLocaleTimeString());try{let l=Q(e).exportsDir,i=0;H.readdirSync(l).forEach(c=>{c.endsWith(".json")&&(i=Math.max(i,H.statSync(ke.join(l,c)).mtimeMs))}),this._lastExportMtime=i}catch(l){}})}_checkOcr(e){if(this._autoSyncRunning)return;let t=Q(e).ocrDir;if(H.existsSync(t))try{H.readdirSync(t,{withFileTypes:!0}).forEach(r=>{if(!r.isDirectory())return;let n=ke.join(t,r.name,"meta.json");if(!H.existsSync(n))return;let a=H.statSync(n),s=this._lastOcrMtimes[r.name]||0;if(a.mtimeMs<=s||(this._lastOcrMtimes[r.name]=a.mtimeMs,this._autoSyncRunning))return;this._autoSyncRunning=!0;let l=L(e,this.settings,void 0,void 0);if(!l.path){this._autoSyncRunning=!1;return}let i=`"${l.path}" -m paperforge --vault "${e}" sync`;(0,ie.exec)(i,{timeout:3e4,encoding:"utf-8"},()=>{this._autoSyncRunning=!1,this._memoryStatusText=null})})}catch(r){}}readPaperforgeJson(){let e=this.app.vault.adapter.basePath,t=ke.join(e,"paperforge.json"),r={system_dir:"System",resources_dir:"Resources",literature_dir:"Literature",base_dir:"Bases"};try{if(!H.existsSync(t))return r;let n=H.readFileSync(t,"utf-8"),a=JSON.parse(n),s=a.vault_config||{};return{system_dir:s.system_dir||a.system_dir||r.system_dir,resources_dir:s.resources_dir||a.resources_dir||r.resources_dir,literature_dir:s.literature_dir||a.literature_dir||r.literature_dir,base_dir:s.base_dir||a.base_dir||r.base_dir}}catch(n){return console.warn("PaperForge: Failed to read paperforge.json, using defaults",n),r}}savePaperforgeJson(e){let t=this.app.vault.adapter.basePath,r=ke.join(t,"paperforge.json"),n={};try{H.existsSync(r)&&(n=JSON.parse(H.readFileSync(r,"utf-8")))}catch(s){console.warn("PaperForge: Failed to read paperforge.json for update",s)}(!n.vault_config||typeof n.vault_config!="object")&&(n.vault_config={});let a=["system_dir","resources_dir","literature_dir","base_dir"];for(let s of a)e[s]!==void 0&&(n.vault_config[s]=e[s]);n.schema_version||(n.schema_version="2");for(let s of a)delete n[s];try{if(H.writeFileSync(r,JSON.stringify(n,null,2),"utf-8"),this.settings){let s=this.readPaperforgeJson();this.settings.system_dir=s.system_dir,this.settings.resources_dir=s.resources_dir,this.settings.literature_dir=s.literature_dir,this.settings.base_dir=s.base_dir}}catch(s){console.error("PaperForge: Failed to write paperforge.json",s),new K.Notice("PaperForge: Failed to save configuration to paperforge.json")}}onunload(){this._pollTimer&&clearInterval(this._pollTimer),this.app.workspace.detachLeavesOfType(_e)}async loadSettings(){this.settings=Object.assign({},Fe,await this.loadData()),this.settings.features&&Fe.features&&(this.settings.features=Object.assign({},Fe.features,this.settings.features||{})),this.settings.frozen_skills||(this.settings.frozen_skills={});let e=this.readPaperforgeJson();if(this.settings.system_dir=e.system_dir,this.settings.resources_dir=e.resources_dir,this.settings.literature_dir=e.literature_dir,this.settings.base_dir=e.base_dir,this.settings.python_path&&this.settings.python_path.trim()){let t=this.settings.python_path.trim();H.existsSync(t)?this.settings._python_path_stale=!1:(console.warn(`PaperForge: Saved python_path "${t}" no longer exists - showing stale warning`),this.settings._python_path_stale=!0)}}async saveSettings(){let e={};for(let t of Object.keys(Fe))t in this.settings&&(e[t]=this.settings[t]);await this.saveData(e)}_checkReleaseNotes(){let e=this.manifest.version;if(this.settings.last_seen_version===e)return;let a=(qe().versions||[]).find(l=>l.version===e);class s extends K.Modal{constructor(i,c){super(i),this._entry=c}onOpen(){let{contentEl:i}=this;if(i.createEl("h2",{text:`PaperForge v${e} \u66F4\u65B0\u8BF4\u660E`}),this._entry){if(i.createEl("p",{text:this._entry.title,cls:"paperforge-modal-subtitle"}),this._entry.breaking_or_migration&&this._entry.breaking_or_migration.length>0){i.createEl("h4",{text:"\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F"});for(let c of this._entry.breaking_or_migration)i.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.new_features&&this._entry.new_features.length>0){i.createEl("h4",{text:"\u65B0\u529F\u80FD"});for(let c of this._entry.new_features)i.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.fixes&&this._entry.fixes.length>0){i.createEl("h4",{text:"\u4FEE\u590D"});for(let c of this._entry.fixes)i.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.recommended_actions&&this._entry.recommended_actions.length>0){let c=i.createEl("div",{cls:"paperforge-release-recommended"});c.createEl("h4",{text:"\u5EFA\u8BAE\u64CD\u4F5C",cls:""}),c.style.marginBottom="8px";for(let d of this._entry.recommended_actions)c.createEl("p",{text:`\u2022 ${d}`,cls:"paperforge-release-item-bold"})}}else i.createEl("p",{text:"\u7248\u672C\u5DF2\u66F4\u65B0\u81F3 v"+e+"\uFF0C\u8BF7\u524D\u5F80\u8BBE\u7F6E \u2192 \u66F4\u65B0\u4E0E\u624B\u518C \u67E5\u770B\u5B8C\u6574\u66F4\u65B0\u8BB0\u5F55\u3002"});new K.Setting(i).addButton(c=>c.setButtonText("\u77E5\u9053\u4E86").setCta().onClick(()=>{this.close()}))}onClose(){let{contentEl:i}=this;i.empty()}}new s(this.app,a).open(),this.settings.last_seen_version=e,this.saveSettings()}}; diff --git a/paperforge/plugin/package-lock.json b/paperforge/plugin/package-lock.json index c289cc20..21c8d2e5 100644 --- a/paperforge/plugin/package-lock.json +++ b/paperforge/plugin/package-lock.json @@ -7,12 +7,8 @@ "": { "name": "paperforge-plugin", "version": "1.0.0", - "dependencies": { - "sql.js": "^1.14.1" - }, "devDependencies": { "@types/node": "^20.0.0", - "@types/sql.js": "^1.4.11", "builtin-modules": "^3.3.0", "esbuild": "^0.25.0", "husky": "^9.1.7", @@ -1004,13 +1000,6 @@ "@types/tern": "*" } }, - "node_modules/@types/emscripten": { - "version": "1.41.5", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", - "integrity": "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -1029,17 +1018,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/@types/sql.js": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@types/sql.js/-/sql.js-1.4.11.tgz", - "integrity": "sha512-QXIx38p2ZThJaK9vP5ZdqdlRe1FG9I8SmCZOS7FHfB/2qPAjZwkL7/vlfPg6N/oWHuuOaGg/P/IRwfP2W0kWVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/emscripten": "*", - "@types/node": "*" - } - }, "node_modules/@types/tern": { "version": "0.23.9", "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", @@ -2439,12 +2417,6 @@ "node": ">=0.10.0" } }, - "node_modules/sql.js": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sql.js/-/sql.js-1.14.1.tgz", - "integrity": "sha512-gcj8zBWU5cFsi9WUP+4bFNXAyF1iRpA3LLyS/DP5xlrNzGmPIizUeBggKa8DbDwdqaKwUcTEnChtd2grWo/x/A==", - "license": "MIT" - }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", diff --git a/paperforge/plugin/package.json b/paperforge/plugin/package.json index 903801ea..59d6ac10 100644 --- a/paperforge/plugin/package.json +++ b/paperforge/plugin/package.json @@ -13,7 +13,6 @@ }, "devDependencies": { "@types/node": "^20.0.0", - "@types/sql.js": "^1.4.11", "builtin-modules": "^3.3.0", "esbuild": "^0.25.0", "husky": "^9.1.7", @@ -24,8 +23,5 @@ "prettier": "^3.8.4", "typescript": "^5.4.0", "vitest": "^2.1.0" - }, - "dependencies": { - "sql.js": "^1.14.1" } } diff --git a/paperforge/plugin/sql-wasm.wasm b/paperforge/plugin/sql-wasm.wasm deleted file mode 100644 index b32b66473d5a3947a89eaa0cd54caef9e0cda9ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 659730 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%0AUur`umG`g>}HDGtk^` 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
tD`saR49Z|p;*n+SI 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

)(o>u<`n8?u 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 mW_H2e4cY_R3)%t(9| diff --git a/paperforge/plugin/src/services/db.ts b/paperforge/plugin/src/services/db.ts deleted file mode 100644 index 8ff1ebf2..00000000 --- a/paperforge/plugin/src/services/db.ts +++ /dev/null @@ -1,119 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import initSqlJs from "sql.js"; -import type { - Database as SqlJsDatabase, - Statement as SqlJsStatement, - SqlValue, -} from "sql.js"; - -// ── Types ── - -export interface SearchResultItem { - zotero_key: string; - title: string; - first_author: string; - year: string; - journal: string; - domain: string; - abstract: string; - rank: number; -} - -// ── Module-level state (lazy init) ── - -let _db: SqlJsDatabase | null = null; -let _queryStmt: SqlJsStatement | null = null; - -// ── FTS5 query transform ── -// FTS5 requires explicit operators between terms: "rotator cuff" → "rotator AND cuff" -// Quoted phrases like '"rotator cuff"' are passed through verbatim. - -function transformFtsQuery(input: string): string { - input = input.trim(); - if (!input) return ""; - - // Already a quoted phrase — pass through as-is - if (input.startsWith('"') && input.endsWith('"')) { - return input; - } - - const terms = input.split(/\s+/).filter(Boolean); - if (terms.length === 0) return ""; - return terms.join(" AND "); -} - -// ── Database init (lazy) ── - -function sqlValueToString(v: SqlValue): string { - if (v === null || v === undefined) return ""; - if (typeof v === "string") return v; - if (v instanceof Uint8Array) return new TextDecoder().decode(v); - return String(v); -} - -function sqlValueToNumber(v: SqlValue): number { - if (v === null || v === undefined) return 0; - if (typeof v === "number") return v; - return Number(v); -} - -export async function initDatabase(vaultPath: string): Promise { - const dbPath = path.join( - vaultPath, - "System", - "PaperForge", - "indexes", - "paperforge.db" - ); - - if (!fs.existsSync(dbPath)) { - throw new Error(`PaperForge database not found at ${dbPath}`); - } - - const SQL = await initSqlJs({ - locateFile: (file: string) => path.join(__dirname, file), - }); - - const buffer = fs.readFileSync(dbPath); - _db = new SQL.Database(new Uint8Array(buffer)); - - _queryStmt = _db.prepare( - `SELECT zotero_key, title, first_author, year, journal, domain, abstract, rank - FROM paper_fts - WHERE paper_fts MATCH ? - ORDER BY rank - LIMIT ?` - ); -} - -// ── Search ── - -export function searchMetadata( - query: string, - limit: number = 20 -): SearchResultItem[] | null { - if (!_db || !_queryStmt) return null; - - const transformed = transformFtsQuery(query); - if (!transformed) return []; - - _queryStmt.bind([transformed, limit]); - - const results: SearchResultItem[] = []; - while (_queryStmt.step()) { - const row = _queryStmt.getAsObject(); - results.push({ - zotero_key: sqlValueToString(row.zotero_key), - title: sqlValueToString(row.title), - first_author: sqlValueToString(row.first_author), - year: sqlValueToString(row.year), - journal: sqlValueToString(row.journal), - domain: sqlValueToString(row.domain), - abstract: sqlValueToString(row.abstract), - rank: sqlValueToNumber(row.rank), - }); - } - _queryStmt.reset(); - return results; -} diff --git a/paperforge/plugin/src/views/dashboard.ts b/paperforge/plugin/src/views/dashboard.ts index b6ffa9e9..2b2a9ea6 100644 --- a/paperforge/plugin/src/views/dashboard.ts +++ b/paperforge/plugin/src/views/dashboard.ts @@ -51,11 +51,6 @@ import { restoreVersion, compareVersions, } from "../services/version-history"; -import { - initDatabase, - searchMetadata, - type SearchResultItem, -} from "../services/db"; // ── Interface for plugin ref used by static open ── @@ -101,8 +96,6 @@ export class PaperForgeStatusView extends ItemView { _searchInput: HTMLInputElement | null = null; _searchResultsEl: HTMLElement | null = null; _searchTimer: ReturnType | undefined = undefined; - _sqlJsInitialized: boolean = false; - _sqlJsFailed: boolean = false; constructor(leaf: WorkspaceLeaf) { super(leaf); @@ -2396,7 +2389,7 @@ export class PaperForgeStatusView extends ItemView { cls: "paperforge-search-results", }); - // Detect @ mode prefix + debounced metadata search via sql.js + // Detect @ mode prefix + debounced metadata search this._searchInput.addEventListener("input", () => { const val = this._searchInput?.value || ""; if (val.startsWith("@") && !val.startsWith("@ ")) { @@ -2411,7 +2404,7 @@ export class PaperForgeStatusView extends ItemView { // Debounced metadata search for non-@ queries if (!val.startsWith("@") && val.trim()) { this._searchTimer = setTimeout(() => { - this.executeSearch({ source: "sqljs" }); + this.executeSearch(); }, 200); } }); @@ -2424,12 +2417,12 @@ export class PaperForgeStatusView extends ItemView { clearTimeout(this._searchTimer); this._searchTimer = undefined; } - this.executeSearch({ source: "cli" }); + this.executeSearch(); } }); } - async executeSearch(options: { source?: "auto" | "cli" | "sqljs" } = {}) { + async executeSearch() { if (!this._searchInput || !this._searchResultsEl) return; const raw = this._searchInput.value.trim(); if (!raw) return; @@ -2440,7 +2433,7 @@ export class PaperForgeStatusView extends ItemView { const mode = isDeep ? "retrieve" : "search"; - // Resolve vault path (used by both sql.js and CLI paths) + // Resolve vault path for CLI search const adapter = this.app.vault.adapter; let vaultPath = ""; if (adapter && typeof adapter === "object" && "basePath" in adapter) { @@ -2449,34 +2442,7 @@ export class PaperForgeStatusView extends ItemView { } this._searchResultsEl.empty(); - - // ── sql.js metadata search path (non-@ queries only) ── - if ( - mode === "search" && - (options.source === "auto" || options.source === "sqljs") - ) { - if (vaultPath) { - try { - if (!this._sqlJsInitialized && !this._sqlJsFailed) { - await initDatabase(vaultPath); - this._sqlJsInitialized = true; - } - if (this._sqlJsInitialized) { - const results = searchMetadata(query, 20); - if (results !== null) { - this.renderSearchResults(results, false); - return; - } - } - } catch (e) { - console.error("PaperForge sql.js search failed:", e); - this._sqlJsFailed = true; - } - } - // sql.js unavailable — fall through to CLI - } - - // ── CLI search path (deep search or sql.js fallback) ── + // ── CLI search path (deep search only) ── this._searchResultsEl.createEl("div", { cls: "paperforge-search-loading", text: "Searching...", @@ -2515,10 +2481,10 @@ export class PaperForgeStatusView extends ItemView { undefined, undefined ); - + const deepFlag = mode === "retrieve" ? ["--deep"] : []; const child = spawn( pythonExe, - [...pyExtra, "-m", "paperforge", mode, query, "--json"], + [...pyExtra, "-m", "paperforge", mode, query, ...deepFlag, "--json"], { cwd: vaultPath, timeout: 30000 } ); @@ -2561,11 +2527,9 @@ export class PaperForgeStatusView extends ItemView { const d = (parsed as Record).data; if (d && typeof d === "object") { const dd = d as Record; - // search output: data.matches + // Unified PFResult v1: data.matches if ("matches" in dd && Array.isArray(dd.matches)) { results = dd.matches as unknown[]; - } else if ("results" in dd && Array.isArray(dd.results)) { - results = dd.results as unknown[]; } } } @@ -2674,21 +2638,10 @@ export class PaperForgeStatusView extends ItemView { cls: "paperforge-search-result-meta", }); - if (typeof rec["authors"] === "string") { + if (typeof rec["first_author"] === "string" && rec["first_author"]) { meta.createEl("span", { cls: "paperforge-search-result-author", - text: rec["authors"], - }); - } else if (Array.isArray(rec["authors"])) { - meta.createEl("span", { - cls: "paperforge-search-result-author", - text: (rec["authors"] as string[]).slice(0, 3).join("; "), - }); - } - if (typeof rec["year"] === "number" || typeof rec["year"] === "string") { - meta.createEl("span", { - cls: "paperforge-search-result-year", - text: String(rec["year"]), + text: rec["first_author"], }); } if (typeof rec["journal"] === "string" && rec["journal"]) { @@ -2727,10 +2680,10 @@ export class PaperForgeStatusView extends ItemView { // @ mode: matched text if ( isDeep && - typeof rec["matched_text"] === "string" && - rec["matched_text"] + typeof rec["text"] === "string" && + rec["text"] ) { - const mt = rec["matched_text"] as string; + const mt = rec["text"] as string; card.createEl("div", { cls: "paperforge-search-result-source", text: mt.length > 300 ? mt.slice(0, 300) + "..." : mt, From fc1dca429ca7b364d271c20506b2873c418c2b5c Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:10:36 +0800 Subject: [PATCH 02/21] Unify PFResult envelope: data.matches with consistent field names, --deep flag - search.py: normalize FTS results to unified field set (score from rank, add text/heading/source keys). Result key unchanged (already 'matches'). - retrieve.py: rename data.chunks to data.matches in standard and deep paths. Map field names: paper_id->zotero_key, chunk_text->text, section_path->heading. Expand enrichment SQL to fetch journal and domain. --deep flag already wired in CLI parser. - tests/cli/test_json_contracts.py: add contract tests verifying PFResult envelope shape, data.matches key presence, unified field names, --deep flag acceptance, and field type correctness. --- paperforge/commands/retrieve.py | 61 ++++++++++++++++----- paperforge/commands/search.py | 17 ++++++ tests/cli/test_json_contracts.py | 91 ++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 13 deletions(-) diff --git a/paperforge/commands/retrieve.py b/paperforge/commands/retrieve.py index f162c188..a501a21d 100644 --- a/paperforge/commands/retrieve.py +++ b/paperforge/commands/retrieve.py @@ -48,7 +48,7 @@ def run(args: argparse.Namespace) -> int: # ── @ Deep Search mode: query rewrite + hybrid retrieval ────── if deep: try: - chunks = hybrid_search(vault, query, limit=limit) + raw_chunks = hybrid_search(vault, query, limit=limit) except Exception as e: result = PFResult( ok=False, @@ -59,10 +59,26 @@ def run(args: argparse.Namespace) -> int: print(result.to_json() if args.json else result.error.message, file=sys.stderr if not args.json else sys.stdout) return 1 + # Normalize to unified PFResult match format + matches: list[dict] = [] + for c in raw_chunks: + matches.append({ + "zotero_key": c.get("paper_id", ""), + "title": c.get("title", ""), + "first_author": c.get("first_author", ""), + "year": c.get("year", ""), + "journal": c.get("journal", ""), + "domain": c.get("domain", ""), + "abstract": "", + "score": c.get("score", 0), + "text": c.get("text", ""), + "heading": c.get("heading", ""), + "source": c.get("source", "deep"), + }) data = { "query": query, - "chunks": chunks, - "count": len(chunks), + "matches": matches, + "count": len(matches), "deep": True, "route_explanation": { "primary_arm": "deep_search", @@ -72,7 +88,7 @@ def run(args: argparse.Namespace) -> int: } warnings: list[str] = [] next_actions: list[dict] = [] - if len(chunks) == 0: + if len(matches) == 0: warnings.append("Deep search returned no results for the query.") result = PFResult( ok=True, command="retrieve", version=PF_VERSION, data=data, warnings=warnings, next_actions=next_actions @@ -80,9 +96,9 @@ def run(args: argparse.Namespace) -> int: if args.json: print(result.to_json()) else: - print(f"{len(chunks)} deep search results for: {query}") - for c in chunks: - print(f" [{c.get('source', '?')}] {c.get('title', c.get('paper_id', '?'))} ({c.get('year', '?')}): {c.get('text', '')[:80]}...") + print(f"{len(matches)} deep search results for: {query}") + for c in matches: + print(f" [{c.get('source', '?')}] {c.get('title', c.get('zotero_key', '?'))} ({c.get('year', '?')}): {c.get('text', '')[:80]}...") return 0 # ── Standard vector retrieve ────────────────────────────────── @@ -156,7 +172,7 @@ def run(args: argparse.Namespace) -> int: try: for c in chunks: row = conn.execute( - "SELECT citation_key, title, year, first_author FROM papers WHERE zotero_key=?", + "SELECT citation_key, title, year, first_author, journal, domain FROM papers WHERE zotero_key=?", (c["paper_id"],), ).fetchone() if row: @@ -164,13 +180,32 @@ def run(args: argparse.Namespace) -> int: c["title"] = row["title"] c["year"] = row["year"] c["first_author"] = row["first_author"] + c["journal"] = row["journal"] or "" + c["domain"] = row["domain"] or "" finally: conn.close() + # Normalize to unified PFResult match format + matches: list[dict] = [] + for c in chunks: + matches.append({ + "zotero_key": c.get("paper_id", ""), + "title": c.get("title", ""), + "first_author": c.get("first_author", ""), + "year": c.get("year", ""), + "journal": c.get("journal", ""), + "domain": c.get("domain", ""), + "abstract": "", + "score": c.get("score", 0), + "text": c.get("chunk_text", ""), + "heading": c.get("section_path", ""), + "source": c.get("source", "vector"), + }) + data = { "query": query, - "chunks": chunks, - "count": len(chunks), + "matches": matches, + "count": len(matches), "route_explanation": { "primary_arm": "vector_retrieve", "compatibility_mode": False, @@ -237,8 +272,8 @@ def run(args: argparse.Namespace) -> int: if args.json: print(result.to_json()) else: - print(f"{len(chunks)} chunks for: {query}") - for c in chunks: + print(f"{len(matches)} matches for: {query}") + for c in matches: print( - f" [{c.get('section_path', '')}] {c.get('citation_key', '')} p{c.get('page_number', 0)}: {c['chunk_text'][:80]}..." + f" [{c.get('heading', '')}] {c.get('zotero_key', '')}: {c.get('text', '')[:80]}..." ) diff --git a/paperforge/commands/search.py b/paperforge/commands/search.py index f7e0fb0e..c37d33fe 100644 --- a/paperforge/commands/search.py +++ b/paperforge/commands/search.py @@ -46,6 +46,23 @@ def run(args: argparse.Namespace) -> int: lifecycle=args.lifecycle or "", next_step=args.next_step or "", ) + # Normalize to unified PFResult match format + unified: list[dict] = [] + for r in results: + unified.append({ + "zotero_key": r.get("zotero_key", ""), + "title": r.get("title", ""), + "first_author": r.get("first_author", ""), + "year": r.get("year", ""), + "journal": r.get("journal", ""), + "domain": r.get("domain", ""), + "abstract": r.get("abstract", ""), + "score": r.get("rank", 0), + "text": r.get("abstract", ""), + "heading": "", + "source": "fts", + }) + results = unified data = { "query": query, "matches": results, diff --git a/tests/cli/test_json_contracts.py b/tests/cli/test_json_contracts.py index 6624f2fa..e6d0aebd 100644 --- a/tests/cli/test_json_contracts.py +++ b/tests/cli/test_json_contracts.py @@ -112,3 +112,94 @@ class TestContextJson: """context without key/--domain/--all should exit 1.""" result = cli_invoker(["context"]) assert result.returncode != 0 + + +class TestSearchJson: + """Contract: 'paperforge search --json' returns PFResult with data.matches.""" + + ENVELOPE_KEYS = {"ok", "command", "version", "data", "error"} + + def test_search_no_memory_db_returns_error(self, cli_invoker): + """search on a vault without memory DB returns ok:false with error.""" + result = cli_invoker(["search", "test", "--json"]) + parsed = assert_valid_json(result.stdout) + assert_json_shape(parsed, self.ENVELOPE_KEYS) + assert parsed["ok"] is False + assert "code" in parsed["error"], "error.code is missing" + assert "message" in parsed["error"], "error.message is missing" + assert result.returncode != 0 + + def test_search_matches_key_present(self, cli_invoker): + """search --json output has top-level PFResult envelope and data.matches key when successful.""" + result = cli_invoker(["search", "test", "--json"]) + parsed = assert_valid_json(result.stdout) + assert_json_shape(parsed, self.ENVELOPE_KEYS) + if parsed["ok"]: + data = parsed["data"] + assert "matches" in data, "data.matches key is missing" + assert isinstance(data["matches"], list), "data.matches should be a list" + assert "count" in data, "data.count is missing" + # Verify unified field names on first match if any + if data["matches"]: + m = data["matches"][0] + for field in ("zotero_key", "title", "first_author", "year", "journal", "domain", "abstract", "score", "text", "heading", "source"): + assert field in m, f"match field '{field}' is missing" + + def test_search_matches_field_types(self, cli_invoker): + """search match fields have correct types when results exist.""" + result = cli_invoker(["search", "test", "--json", "--limit", "5"]) + parsed = assert_valid_json(result.stdout) + if parsed["ok"] and parsed["data"]["matches"]: + m = parsed["data"]["matches"][0] + assert isinstance(m["zotero_key"], str), "zotero_key should be str" + assert isinstance(m["title"], str), "title should be str" + assert isinstance(m["score"], (int, float)), "score should be numeric" + + +class TestRetrieveJson: + """Contract: 'paperforge retrieve --json' returns PFResult with data.matches.""" + + ENVELOPE_KEYS = {"ok", "command", "version", "data", "error"} + + def test_retrieve_no_memory_db_returns_error(self, cli_invoker): + """retrieve on a vault without memory DB returns ok:false with error.""" + result = cli_invoker(["retrieve", "test", "--json"]) + parsed = assert_valid_json(result.stdout) + assert_json_shape(parsed, self.ENVELOPE_KEYS) + assert parsed["ok"] is False + assert "code" in parsed["error"], "error.code is missing" + assert "message" in parsed["error"], "error.message is missing" + assert result.returncode != 0 + + def test_retrieve_matches_key_present(self, cli_invoker): + """retrieve --json output has data.matches key when successful.""" + result = cli_invoker(["retrieve", "test", "--json"]) + parsed = assert_valid_json(result.stdout) + assert_json_shape(parsed, self.ENVELOPE_KEYS) + if parsed["ok"]: + data = parsed["data"] + assert "matches" in data, "data.matches key is missing" + assert isinstance(data["matches"], list), "data.matches should be a list" + if data["matches"]: + m = data["matches"][0] + for field in ("zotero_key", "title", "first_author", "year", "journal", "domain", "abstract", "score", "text", "heading", "source"): + assert field in m, f"match field '{field}' is missing" + + def test_retrieve_deep_flag_accepted(self, cli_invoker): + """retrieve --deep --json is accepted (may return empty results on minimal vault).""" + result = cli_invoker(["retrieve", "test", "--deep", "--json"]) + parsed = assert_valid_json(result.stdout) + assert_json_shape(parsed, self.ENVELOPE_KEYS) + # --deep may succeed (ok:true) or fail (ok:false) depending on vault state — just validate shape + if parsed["ok"]: + assert "matches" in parsed["data"], "data.matches key is missing" + + def test_retrieve_matches_field_types(self, cli_invoker): + """retrieve match fields have correct types when results exist.""" + result = cli_invoker(["retrieve", "test", "--json", "--limit", "5"]) + parsed = assert_valid_json(result.stdout) + if parsed["ok"] and parsed["data"]["matches"]: + m = parsed["data"]["matches"][0] + assert isinstance(m["zotero_key"], str), "zotero_key should be str" + assert isinstance(m["score"], (int, float)), "score should be numeric" + assert isinstance(m["text"], str), "text should be str" From aa9f1de2784598b1f298ee57fa84a6402a3f1120 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:55:11 +0800 Subject: [PATCH 03/21] fix: add missing CREATE_VEC_FULLTEXT_META to vec0 schema The vec_fulltext_meta table DDL was referenced by ensure_schema() but never defined. ADD the missing CREATE_VEC_FULLTEXT_META variable so the meta table is created alongside vec_body_meta and vec_objects_meta. --- paperforge/memory/schema.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/paperforge/memory/schema.py b/paperforge/memory/schema.py index 0ff1d16e..d619b352 100644 --- a/paperforge/memory/schema.py +++ b/paperforge/memory/schema.py @@ -235,6 +235,16 @@ CREATE_VEC_FULLTEXT = _vec_table_ddl("vec_fulltext") CREATE_VEC_BODY = _vec_table_ddl("vec_body") CREATE_VEC_OBJECTS = _vec_table_ddl("vec_objects") +CREATE_VEC_FULLTEXT_META = """ +CREATE TABLE IF NOT EXISTS vec_fulltext_meta ( + rowid INTEGER PRIMARY KEY, + paper_id TEXT NOT NULL, + chunk_index INTEGER, + text TEXT, + source TEXT +); +""" + CREATE_VEC_BODY_META = """ CREATE TABLE IF NOT EXISTS vec_body_meta ( rowid INTEGER PRIMARY KEY, From 40326d675966dee124a644539b17d520a41ea05e Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:55:16 +0800 Subject: [PATCH 04/21] fix: add vec0 k-NN health probe to embed status embed status now runs a zero-vector k-NN query on each vec0 table that has companion meta rows. If the probe fails (table dropped, extension unavailable, index corrupted), healthy=false and corrupted=true are reported even when meta row counts > 0. Includes integration test that drops vec_fulltext and verifies healthy=false. --- paperforge/embedding/status.py | 20 +++- tests/integration/test_health_probe.py | 138 +++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 tests/integration/test_health_probe.py diff --git a/paperforge/embedding/status.py b/paperforge/embedding/status.py index 38319e4e..7ca0befe 100644 --- a/paperforge/embedding/status.py +++ b/paperforge/embedding/status.py @@ -1,11 +1,12 @@ from __future__ import annotations +import json as _json import logging from pathlib import Path from paperforge.embedding._config import get_api_model from paperforge.memory.db import ensure_vec_extension, get_connection, get_memory_db_path -from paperforge.memory.schema import ensure_schema +from paperforge.memory.schema import VEC_EMBEDDING_DIM, ensure_schema logger = logging.getLogger(__name__) @@ -27,13 +28,28 @@ def get_embed_status(vault: Path) -> dict: ensure_vec_extension(conn) except Exception: pass - ensure_schema(conn) row_ft = conn.execute("SELECT COUNT(*) AS cnt FROM vec_fulltext_meta").fetchone() chunk_count = row_ft["cnt"] if row_ft else 0 row_body = conn.execute("SELECT COUNT(*) AS cnt FROM vec_body_meta").fetchone() body_chunk_count = row_body["cnt"] if row_body else 0 row_obj = conn.execute("SELECT COUNT(*) AS cnt FROM vec_objects_meta").fetchone() object_chunk_count = row_obj["cnt"] if row_obj else 0 + + # -- vec0 k-NN health probe -- + total_meta = chunk_count + body_chunk_count + object_chunk_count + if total_meta > 0: + zero_vec = [0.0] * VEC_EMBEDDING_DIM + zero_json = _json.dumps(zero_vec) + for vec_table, meta_count in [ + ("vec_fulltext", chunk_count), + ("vec_body", body_chunk_count), + ("vec_objects", object_chunk_count), + ]: + if meta_count > 0: + conn.execute( + f"SELECT 1 FROM {vec_table} WHERE embedding MATCH ? AND k = 1", + (zero_json,), + ) except Exception as exc: healthy = False error = str(exc) diff --git a/tests/integration/test_health_probe.py b/tests/integration/test_health_probe.py new file mode 100644 index 00000000..fdf76d3c --- /dev/null +++ b/tests/integration/test_health_probe.py @@ -0,0 +1,138 @@ +"""Integration tests for embed status vec0 health probe. + +Verifies that embed status --json returns healthy=false when a vec0 table +with meta rows is dropped (simulating corruption). +""" + +from __future__ import annotations + +import json +import subprocess +from pathlib import Path + +import pytest + +PYTHON = Path(r"D:\L\OB\Literature-hub\.venv\Scripts\python.exe") +REPO_ROOT = Path(__file__).resolve().parent.parent.parent + + +def _build_vault(tmp_path: Path) -> Path: + """Build a minimal vault with paperforge.json and a seeded memory DB.""" + vault = tmp_path / "vault" + vault.mkdir(parents=True) + (vault / "paperforge.json").write_text( + '{"vault_config":{"system_dir":"System"}}', encoding="utf-8" + ) + (vault / "System" / "PaperForge").mkdir(parents=True) + return vault + + +def _run_embed_status(vault: Path) -> dict: + """Run embed status --json and return the parsed data dict.""" + result = subprocess.run( + [ + str(PYTHON), + "-m", + "paperforge", + "--vault", + str(vault), + "embed", + "status", + "--json", + ], + capture_output=True, + text=True, + cwd=str(REPO_ROOT), + timeout=30, + ) + assert result.returncode == 0, f"embed status failed:\n{result.stderr}" + parsed = json.loads(result.stdout) + assert parsed["ok"] is True + return parsed["data"] + + +def _db_path(vault: Path) -> Path: + """Resolve paperforge.db path using the same logic as get_memory_db_path.""" + from paperforge.memory.db import get_memory_db_path + return get_memory_db_path(vault) + + +@pytest.fixture +def vault_with_vec0(tmp_path: Path) -> Path: + """Create a vault with a seeded paperforge.db containing vec0 tables + meta rows.""" + vault = _build_vault(tmp_path) + + # Create DB schema explicitly (embed status doesn't auto-create) + from paperforge.memory.db import get_connection, get_memory_db_path, ensure_vec_extension + from paperforge.memory.schema import ensure_schema + + db_path = get_memory_db_path(vault) + db_path.parent.mkdir(parents=True, exist_ok=True) + conn = get_connection(db_path) + ensure_vec_extension(conn) + ensure_schema(conn) + conn.close() + + # Insert data via a separate connection with vec0 loaded + import sqlite3 + + conn = sqlite3.connect(str(db_path)) + try: + conn.enable_load_extension(True) + import sqlite_vec + sqlite_vec.load(conn) + conn.enable_load_extension(False) + except Exception: + pass + + # Insert meta row into vec_fulltext_meta so total_meta > 0 + conn.execute( + "INSERT INTO vec_fulltext_meta (rowid, paper_id, chunk_index, text, source) " + "VALUES (1, 'TESTKEY', 0, 'test', 'fulltext')" + ) + + # Insert a zero vector into vec_fulltext so the k-NN probe works + zero_vec = [0.0] * 1536 + vec_json = json.dumps(zero_vec) + conn.execute( + "INSERT INTO vec_fulltext (rowid, embedding) VALUES (1, ?)", + (vec_json,), + ) + + conn.commit() + conn.close() + return vault + + +class TestHealthProbe: + """embed status --json runs vec0 k-NN probe and reports healthy=false when vec0 broken.""" + + def test_healthy_when_vec0_ok(self, vault_with_vec0: Path): + """When vec0 tables are intact, health probe passes.""" + data = _run_embed_status(vault_with_vec0) + assert data["healthy"] is True, f"Expected healthy=True, got {data}" + assert data["corrupted"] is False + assert data["chunk_count"] >= 1 + + def test_unhealthy_when_vec0_table_dropped(self, vault_with_vec0: Path): + """When a vec0 virtual table is dropped but meta rows exist, healthy=false.""" + db_path = _db_path(vault_with_vec0) + import sqlite3 + + conn = sqlite3.connect(str(db_path)) + try: + conn.enable_load_extension(True) + import sqlite_vec + sqlite_vec.load(conn) + conn.enable_load_extension(False) + except Exception: + pass + conn.execute("DROP TABLE IF EXISTS vec_fulltext") + conn.commit() + conn.close() + + data = _run_embed_status(vault_with_vec0) + assert data["healthy"] is False, f"Expected healthy=False after dropping vec table, got {data}" + assert data["corrupted"] is True + err = data.get("error", "").lower() + assert "vec0 probe failed" in err or "no such table" in err, f"Unexpected error: {data.get('error')}" From 0bc054e7b00646c6e731b11b06a8ad24502432f0 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:55:21 +0800 Subject: [PATCH 05/21] fix: cooperative stop with state settlement and build-loop cancellation embed stop now sets status=stopping, waits for the build PID to exit (8s timeout), force-kills as last resort, then settles to idle. Build loop checks the cancellation flag (read_vector_build_state) between papers in the main loop and drains in-flight work before cleanly exiting without marking 'completed'. Fixes pre-existing UnboundLocalError from a local import shadowing the global mark_vector_build_state symbol in the run() function. --- paperforge/commands/embed.py | 55 +++++--- tests/integration/test_stop_idle_resume.py | 154 +++++++++++++++++++++ 2 files changed, 188 insertions(+), 21 deletions(-) create mode 100644 tests/integration/test_stop_idle_resume.py diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index 6711eb76..6de40077 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -159,32 +159,34 @@ def run(args: argparse.Namespace) -> int: if sub == "stop": state = read_vector_build_state(vault) pid = state.get("pid", 0) - if pid and state["status"] == "running": - import signal - - try: - os.kill(pid, signal.SIGTERM) - except Exception as exc: - result = PFResult( - ok=False, - command="embed stop", - version=PF_VERSION, - error=PFError(code=ErrorCode.INTERNAL_ERROR, message=f"Failed to stop embed build: {exc}"), - data={"state": "running", "pid": pid}, - ) - if args.json: - print(result.to_json()) - else: - print(result.error.message, file=sys.stderr) - return 1 + _st = state.get("status", "") + if pid and _st in ("running", "stopping"): mark_vector_build_state(vault, status="stopping", message="Stop requested") - result = PFResult(ok=True, command="embed stop", version=PF_VERSION, data={"state": "stopping", "pid": pid}) + # Wait for build process to notice the flag and exit (8s timeout) + import time as _time + _deadline = _time.time() + 8.0 + while _time.time() < _deadline: + if not _pid_alive(pid): + break + _time.sleep(0.2) + # Force-kill if still alive after timeout + if _pid_alive(pid): + import signal + try: + os.kill(pid, signal.SIGTERM) + except Exception: + pass + # Settle to idle, preserving progress + _current = read_vector_build_state(vault).get("current", state.get("current", 0)) + mark_vector_build_state(vault, status="idle", current=_current, pid=0, message="") + result = PFResult(ok=True, command="embed stop", version=PF_VERSION, data={"state": "stopped"}) else: result = PFResult(ok=True, command="embed stop", version=PF_VERSION, data={"state": "idle"}) if args.json: print(result.to_json()) else: - print("Stop requested." if result.data["state"] == "stopping" else "No active build.") + msg = "Build stopped." if result.data["state"] == "stopped" else "No active build." + print(msg) return 0 @@ -287,7 +289,6 @@ def run(args: argparse.Namespace) -> int: if stale: msg = "Previous build appears stale (crashed?). Recovering and rebuilding from scratch." print(msg) - from paperforge.embedding.build_state import mark_vector_build_state mark_vector_build_state(vault, status="idle", current=0, pid=0) resume = False @@ -397,6 +398,11 @@ def run(args: argparse.Namespace) -> int: if not key: continue + # ponytail: check cancellation flag between papers + if read_vector_build_state(vault).get("status") == "stopping": + logger.info("Build cancelled at paper %s", key) + break + has_body = _has_body_units_in_db(vault, key) has_object = _has_object_units_in_db(vault, key) @@ -581,6 +587,13 @@ def run(args: argparse.Namespace) -> int: print(result.to_json() if args.json else result.error.message, file=sys.stderr if not args.json else sys.stdout) return 1 + + # Check if we stopped or were cancelled — exit cleanly without marking completed + if read_vector_build_state(vault).get("status") == "stopping": + logger.info("Build stopped, exiting cleanly") + print("EMBED_DONE", flush=True) + return 0 + mark_vector_build_state( vault, status="completed", diff --git a/tests/integration/test_stop_idle_resume.py b/tests/integration/test_stop_idle_resume.py new file mode 100644 index 00000000..d49f4cd2 --- /dev/null +++ b/tests/integration/test_stop_idle_resume.py @@ -0,0 +1,154 @@ +"""Integration tests for the build lifecycle stop → idle → resume cycle. + +Verifies that embed stop --json marks build as stopping, settles to idle, +and that resume can continue a build from progress. +""" + +from __future__ import annotations + +import json +import subprocess +from pathlib import Path + +import pytest + +PYTHON = Path(r"D:\L\OB\Literature-hub\.venv\Scripts\python.exe") +REPO_ROOT = Path(__file__).resolve().parent.parent.parent + + +def _build_vault(tmp_path: Path) -> Path: + """Build a minimal vault with paperforge.json.""" + vault = tmp_path / "vault" + vault.mkdir(parents=True) + (vault / "paperforge.json").write_text( + '{"vault_config":{"system_dir":"System"}}', encoding="utf-8" + ) + (vault / "System" / "PaperForge").mkdir(parents=True) + return vault + + +def _run_embed_stop(vault: Path) -> dict: + """Run embed stop --json and return parsed data.""" + result = subprocess.run( + [ + str(PYTHON), + "-m", + "paperforge", + "--vault", + str(vault), + "embed", + "stop", + "--json", + ], + capture_output=True, + text=True, + cwd=str(REPO_ROOT), + timeout=30, + ) + parsed = json.loads(result.stdout) + return parsed + + +def _run_embed_status(vault: Path) -> dict: + """Run embed status --json and return parsed data.""" + result = subprocess.run( + [ + str(PYTHON), + "-m", + "paperforge", + "--vault", + str(vault), + "embed", + "status", + "--json", + ], + capture_output=True, + text=True, + cwd=str(REPO_ROOT), + timeout=30, + ) + assert result.returncode == 0 + parsed = json.loads(result.stdout) + assert parsed["ok"] is True + return parsed["data"] + + +def _mark_running(vault: Path, pid: int, current: int = 5, total: int = 100) -> None: + """Set build_state to 'running' with the given PID.""" + from paperforge.embedding.build_state import mark_vector_build_state + + mark_vector_build_state( + vault, + status="running", + pid=pid, + current=current, + total=total, + paper_id="TESTKEY", + model="test-model", + mode="api", + ) + + +def _read_build_state(vault: Path) -> dict: + """Read build_state table.""" + from paperforge.embedding.build_state import read_vector_build_state + + return read_vector_build_state(vault) + + +class TestStopIdleResume: + """Stop → idle → resume lifecycle.""" + + def test_stop_returns_stopped_and_idle(self, tmp_path: Path): + """embed stop --json returns {state: stopped} when a build is running, and settles to idle.""" + vault = _build_vault(tmp_path) + + # Set build to running with a dead PID (not 0 — 0 is falsy in Python) + _mark_running(vault, pid=99999, current=5, total=100) + + # Stop + result = _run_embed_stop(vault) + assert result["ok"] is True, f"Stop returned error: {result}" + assert result["data"]["state"] == "stopped", f"Expected stopped, got {result['data']['state']}" + + # Verify build state settled to idle + bs = _read_build_state(vault) + assert bs["status"] == "idle", f"Expected idle, got {bs}" + assert bs["pid"] == 0 + + def test_stop_when_idle_stays_idle(self, tmp_path: Path): + """embed stop --json on idle build returns {state: idle}.""" + vault = _build_vault(tmp_path) + + result = _run_embed_stop(vault) + assert result["ok"] is True + assert result["data"]["state"] == "idle" + + bs = _read_build_state(vault) + assert bs["status"] == "idle" + + def test_resume_after_stop_reads_progress(self, tmp_path: Path): + """After stop, status shows the idle state with progress, and resume mode continues from there.""" + vault = _build_vault(tmp_path) + + _mark_running(vault, pid=99998, current=42, total=200) + + # Stop + _run_embed_stop(vault) + + # Status should report progress and idle state + status = _run_embed_status(vault) + bs = status.get("build_state", {}) + assert bs.get("status") == "idle" + assert bs.get("current", 0) == 42 + assert bs.get("total", 0) == 200 + + # Resume mode: verify that a subsequent --resume build picks up from idle + # (we can't do a full build without a real vault, so we check that + # the resume path isn't blocked by the idle state) + from paperforge.embedding.build_state import read_vector_build_state + + bs_read = read_vector_build_state(vault) + assert bs_read["status"] == "idle" + # A resume build call would check this and start fresh or continue + # The state is correctly idle which allows resume From ec810b10a943694f8ea1534fb50d246e8f6ef3b9 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:55:26 +0800 Subject: [PATCH 06/21] feat: plugin reads embed status --json live, polls during build, stop without kill getVectorRuntime now calls embed status --json synchronously with a 2s time-based cache before falling back to the JSON snapshot. During build, a 2s polling interval reads embed status --json for live build state and detects remote stop. Stop button calls embed stop --json only (no direct .kill() on the child process), letting the CLI handle cooperative stop. ISettingPlugin interface extended with _embedPollInterval and _embedPolling properties. --- .../plugin/src/services/memory-state.ts | 41 +- paperforge/plugin/src/settings.ts | 560 +++++++++++++----- 2 files changed, 457 insertions(+), 144 deletions(-) diff --git a/paperforge/plugin/src/services/memory-state.ts b/paperforge/plugin/src/services/memory-state.ts index 2ce60c46..61aaa2a8 100644 --- a/paperforge/plugin/src/services/memory-state.ts +++ b/paperforge/plugin/src/services/memory-state.ts @@ -164,9 +164,48 @@ export function getMemoryRuntime(vaultPath: string): MemoryRuntime | null { return readJSONFile(paths.memoryStatePath) as MemoryRuntime | null; } +let _vectorRuntimeCache: { vaultPath: string; result: VectorRuntime | null; ts: number } | null = null; + export function getVectorRuntime(vaultPath: string): VectorRuntime | null { const paths = resolveVaultPaths(vaultPath); - return readJSONFile(paths.vectorStatePath) as VectorRuntime | null; + // Time-based cache: use snapshot within the 2s window + const now = Date.now(); + if (_vectorRuntimeCache && _vectorRuntimeCache.vaultPath === vaultPath && now - _vectorRuntimeCache.ts < 2000) { + return _vectorRuntimeCache.result; + } + // Try live embed status --json; fall back to JSON snapshot + let pythonPath = ""; + const venvCandidates = [ + path.join(vaultPath, ".paperforge-test-venv", "Scripts", "python.exe"), + path.join(vaultPath, ".venv", "Scripts", "python.exe"), + path.join(vaultPath, "venv", "Scripts", "python.exe"), + ]; + for (let i = 0; i < venvCandidates.length; i++) { + if (fs.existsSync(venvCandidates[i])) { + pythonPath = venvCandidates[i]; + break; + } + } + if (pythonPath) { + try { + const out = execFileSync(pythonPath, ["-m", "paperforge", "--vault", vaultPath, "embed", "status", "--json"], { + encoding: "utf-8", + timeout: 10000, + windowsHide: true, + }); + const parsed = JSON.parse(out); + if (parsed.ok && parsed.data) { + const result = parsed.data as VectorRuntime; + _vectorRuntimeCache = { vaultPath, result, ts: now }; + return result; + } + } catch { + // fall through to snapshot + } + } + const result = readJSONFile(paths.vectorStatePath) as VectorRuntime | null; + _vectorRuntimeCache = { vaultPath, result, ts: now }; + return result; } export function getRuntimeHealth( diff --git a/paperforge/plugin/src/settings.ts b/paperforge/plugin/src/settings.ts index 46f64d76..1af1c1cc 100644 --- a/paperforge/plugin/src/settings.ts +++ b/paperforge/plugin/src/settings.ts @@ -56,6 +56,8 @@ interface ISettingPlugin { _embedProcess?: unknown; _embedProgress?: { current: number; total: number; key: string }; _embedStderr?: string; + _embedPollInterval?: ReturnType | null; + _embedPolling?: boolean; } export class PaperForgeSettingTab extends PluginSettingTab { @@ -74,6 +76,8 @@ export class PaperForgeSettingTab extends PluginSettingTab { private _customPathDescEl: HTMLElement | null = null; private _checkEl: HTMLDivElement | null = null; activeTab = "setup"; + private _buildState: string = "idle"; + private _buildProgress: { current: number; total: number; key: string } = { current: 0, total: 0, key: "" }; constructor(app: App, plugin: ISettingPlugin) { super(app, plugin as any); @@ -1146,7 +1150,7 @@ export class PaperForgeSettingTab extends PluginSettingTab { cls: "paperforge-embed-header", }); embedHeader.createEl("span", { - text: t("feat_rebuild_vectors"), + text: t("retrieval_rebuild_vectors"), cls: "setting-item-name", }); @@ -1156,12 +1160,19 @@ export class PaperForgeSettingTab extends PluginSettingTab { const embedStatusText = embedSection.createEl("div", { cls: "paperforge-embed-status-text", + attr: { "aria-live": "polite" }, }); const renderEmbedUI = () => { embedControls.empty(); embedStatusText.empty(); - const buildState: any = (getVectorRuntime(vp) || {}).build_state || {}; + + const vr = getVectorRuntime(vp); + const bsRaw = vr?.build_state; + const buildState: Record = + bsRaw && typeof bsRaw === "object" && !Array.isArray(bsRaw) + ? (bsRaw as Record) + : {}; this.plugin._embedProgress = this.plugin._embedProgress || { current: 0, total: 0, @@ -1170,168 +1181,431 @@ export class PaperForgeSettingTab extends PluginSettingTab { if (!this.plugin._embedProcess && buildState.status === "running") { this.plugin._embedProgress = { - current: buildState.current || 0, - total: buildState.total || 1, - key: buildState.paper_id || "", + current: + typeof buildState.current === "number" ? buildState.current : 0, + total: + typeof buildState.total === "number" ? buildState.total : 1, + key: + typeof buildState.paper_id === "string" + ? buildState.paper_id + : "", }; } const { current, total, key } = this.plugin._embedProgress; - const isRunning = - !!this.plugin._embedProcess || buildState.status === "running"; - if (isRunning) { - const track = embedControls.createEl("div", { - cls: "paperforge-progress-track", - }); - track.style.cssText = "flex:1;"; - const pct = total > 0 ? ((current / total) * 100).toFixed(1) : "0"; - const doneSeg = track.createEl("div", { - cls: "paperforge-progress-seg done", - }); - doneSeg.style.cssText = `width:${pct}%; min-width:${current > 0 ? "2px" : "0"};`; - if (current < total) { - const pendingSeg = track.createEl("div", { - cls: "paperforge-progress-seg pending", - }); - pendingSeg.style.cssText = `width:${(100 - parseFloat(pct)).toFixed(1)}%;`; + // Safely access fields from VectorRuntime index signature + const bodyChunkCount = + typeof vr?.body_chunk_count === "number" ? vr.body_chunk_count : 0; + const objectChunkCount = + typeof vr?.object_chunk_count === "number" + ? vr.object_chunk_count + : 0; + const chunkCount = + typeof vr?.chunk_count === "number" ? vr.chunk_count : 0; + const totalChunks = chunkCount + bodyChunkCount + objectChunkCount; + const hasChunks = totalChunks > 0; + const isCorrupted = + vr !== null && typeof vr.corrupted === "boolean" && vr.corrupted; + const isBuilding = !!this.plugin._embedProcess; + const isStale = + !this.plugin._embedProcess && buildState.status === "running"; + // deps_installed is a defined boolean? property on VectorRuntime + const depsInstalled = + vr?.deps_installed !== undefined ? !!vr.deps_installed : true; + + const status = + typeof buildState.status === "string" ? buildState.status : ""; + const buildMessage = + typeof buildState.message === "string" ? buildState.message : ""; + + const startBuild = (flag: string) => { + // ── Destructive warnings ── + if (flag === "--resume" && hasChunks && !isCorrupted) { + const msg = t("retrieval_rebuild_warning").replace( + "{n}", + String(totalChunks) + ); + if (!confirm(msg)) return; } - embedStatusText.createEl("span", { - cls: "paperforge-embed-progress-text", - text: `${current}/${total} papers`, - }); - if (key) { - embedStatusText.createEl("span", { - cls: "paperforge-embed-progress-key", - text: ` (${key})`, - }); + if (flag === "--force" && hasChunks && !isCorrupted) { + const msg = + "Force rebuild will replace " + + totalChunks + + " existing chunk(s). Continue?"; + if (!confirm(msg)) return; } - const stopBtn = embedControls.createEl("button"); - stopBtn.setText("Stop"); - stopBtn.className = "mod-warning"; - stopBtn.addEventListener("click", () => { - this._callPython(["embed", "stop", "--json"], { timeout: 8000 }); - if (this.plugin._embedProcess) { - (this.plugin._embedProcess as any).kill(); - this.plugin._embedProcess = null; - } - this.display(); + const py = getCachedPython(vp, this.plugin.settings); + if (!py.path) { + new Notice(t("retrieval_no_python")); + return; + } + const env = Object.assign({}, process.env, { + PYTHONIOENCODING: "utf-8", + PYTHONUTF8: "1", + VECTOR_DB_API_KEY: + this.plugin.settings.vector_db_api_key || "", + VECTOR_DB_API_BASE: + this.plugin.settings.vector_db_api_base || "", + VECTOR_DB_API_MODEL: + this.plugin.settings.vector_db_api_model || "", }); - } else { - const embedInfo = getVectorRuntime(vp); - const embedChunks = - (embedInfo?.chunk_count ?? 0) + - ((embedInfo?.body_chunk_count as number) ?? 0) + - ((embedInfo?.object_chunk_count as number) ?? 0); - const hasChunks = embedChunks > 0; - const isCorrupted = embedInfo ? !!embedInfo.corrupted : false; - - const startBuild = (flag: string) => { - const py = getCachedPython(vp, this.plugin.settings); - if (!py.path) { - new Notice(t("feat_no_python")); - return; - } - const env = Object.assign({}, process.env, { - PYTHONIOENCODING: "utf-8", - PYTHONUTF8: "1", - VECTOR_DB_API_KEY: this.plugin.settings.vector_db_api_key || "", - VECTOR_DB_API_BASE: this.plugin.settings.vector_db_api_base || "", - VECTOR_DB_API_MODEL: this.plugin.settings.vector_db_api_model || "", - }); - this.plugin._embedStderr = ""; - this.plugin._embedProgress = { current: 0, total: 0, key: "" }; - this.plugin._embedProcess = this._callPython( - ["embed", "build", flag], - { - stream: true, - env: env, - onData: (data: any) => { - const lines = data.toString("utf-8").split("\n"); - for (const line of lines) { - if (line.startsWith("EMBED_START:")) { - this.plugin._embedProgress!.total = - parseInt(line.split(":")[1]) || 0; - } else if (line.startsWith("EMBED_PROGRESS:")) { - const parts = line.split(":"); - this.plugin._embedProgress!.current = - parseInt(parts[1]) || 0; - this.plugin._embedProgress!.key = parts[3] || ""; - } else if (line.startsWith("EMBED_DONE")) { - this.plugin._embedProcess = null; - this.plugin._embedProgress!.current = - this.plugin._embedProgress!.total; - } - } - this.display(); - }, - onStderr: (data: any) => { - if (!this.plugin._embedStderr) this.plugin._embedStderr = ""; - this.plugin._embedStderr += data.toString("utf-8"); - }, - onError: (err: any) => { - this.plugin._embedProcess = null; - new Notice( - t("feat_build_failed") + ": " + (err.message || err) - ); - this.display(); - }, - onClose: (code: number | null) => { - this.plugin._embedProcess = null; - if (code === 0) { + this.plugin._embedStderr = ""; + this.plugin._embedProgress = { current: 0, total: 0, key: "" }; + this.plugin._embedProcess = this._callPython( + ["embed", "build", flag], + { + stream: true, + env: env, + onData: (data: unknown) => { + // Node stream emits Buffer; data can also be string + const text = + typeof data === "string" + ? data + : Buffer.isBuffer(data) + ? data.toString("utf-8") + : String(data); + const lines = text.split("\n"); + for (const line of lines) { + if (line.startsWith("EMBED_START:")) { + this.plugin._embedProgress!.total = + parseInt(line.split(":")[1]) || 0; + } else if (line.startsWith("EMBED_PROGRESS:")) { + const parts = line.split(":"); + this.plugin._embedProgress!.current = + parseInt(parts[1]) || 0; + this.plugin._embedProgress!.key = parts[3] || ""; + } else if (line.startsWith("EMBED_DONE")) { + this.plugin._embedProcess = null; this.plugin._embedProgress!.current = this.plugin._embedProgress!.total; - this.plugin.saveSettings(); - this._embedStatusText = getVectorStatusText(vp); - new Notice(t("feat_build_complete")); - } else { - this._embedStatusText = null; - const errMsg = (this.plugin._embedStderr || "").slice(0, 200); - new Notice( - t("feat_build_failed") + (errMsg ? ": " + errMsg : ""), - 8000 - ); } + } + this.display(); + }, + onStderr: (data: unknown) => { + if (!this.plugin._embedStderr) this.plugin._embedStderr = ""; - this.display(); - this._refreshSnapshots(vp); - }, - } - ); + this.plugin._embedStderr += String(data); + }, + onError: (err: Error) => { + this.plugin._embedProcess = null; + new Notice( + t("feat_build_failed") + ": " + (err.message || err) + ); + this.display(); + }, + onClose: (code: number | null) => { + clearInterval(this.plugin._embedPollInterval ?? undefined); + this.plugin._embedPollInterval = null; + this.plugin._embedProcess = null; + if (code === 0) { + this.plugin._embedProgress!.current = + this.plugin._embedProgress!.total; + this.plugin.saveSettings(); + this._embedStatusText = getVectorStatusText(vp); + new Notice(t("feat_build_complete")); + } else { + this._embedStatusText = null; + const errMsg = ( + this.plugin._embedStderr || "" + ).slice(0, 200); + new Notice( + t("feat_build_failed") + + (errMsg ? ": " + errMsg : ""), + 8000 + ); + } + this.plugin._embedStderr = ""; + this.display(); + this._refreshSnapshots(vp); + }, + } + ); - this.display(); - }; - - if (isCorrupted) { - const warnEl = embedSection.createEl("div"); - warnEl.style.cssText = - "padding:8px 12px; margin:8px 0; background:var(--background-modifier-warning); border-radius:4px; font-size:12px; display:flex; align-items:center; justify-content:space-between;"; - warnEl.createEl("span", { text: t("feat_vector_corrupted") }); - const forceBtn = warnEl.createEl("button", { - text: t("feat_vector_rebuild_force_btn"), + // Poll embed status every 2s during build for live state + clearInterval(this.plugin._embedPollInterval ?? undefined); + this.plugin._embedPollInterval = setInterval(() => { + if (this.plugin._embedPolling) return; + this.plugin._embedPolling = true; + this._callPython(["embed", "status", "--json"], { + timeout: 5000, + onClose: (_code: number | null, stdout: string) => { + this.plugin._embedPolling = false; + if (_code === 0 && stdout) { + try { + const result = JSON.parse(stdout); + const data = result.data; + if (data && data.build_state) { + const bs = data.build_state; + if (bs.status === "stopping" || bs.status === "idle") { + if (this.plugin._embedProcess) { + this.plugin._embedProcess = null; + clearInterval(this.plugin._embedPollInterval ?? undefined); + this.plugin._embedPollInterval = null; + this.display(); + } + } + if ( + bs.current !== undefined && + bs.total !== undefined + ) { + this.plugin._embedProgress!.current = bs.current; + this.plugin._embedProgress!.total = + bs.total || 1; + this.plugin._embedProgress!.key = + bs.paper_id || ""; + } + } + } catch {} + } + }, }); - forceBtn.className = "mod-cta"; - forceBtn.addEventListener("click", () => startBuild("--force")); + }, 2000); + + this.display(); + }; + + // Detect runtime version mismatch from health data + const health = getRuntimeHealth(vp); + let runtimeMismatch = false; + if (health && typeof health.summary === "object" && health.summary !== null && "status" in health.summary) { + runtimeMismatch = health.summary.status === "version_mismatch"; + } + + // ── State determination (priority order) ── + let uiState: string; + if (!depsInstalled) { + uiState = "deps-missing"; + } else if (runtimeMismatch) { + uiState = "runtime-mismatch"; + } else if (status === "stopping") { + uiState = "stopping"; + } else if (isBuilding && status === "running") { + uiState = "building"; + } else if (status === "failed") { + uiState = "failed"; + } else if (status === "stopped") { + uiState = "stopped"; + } else if (isStale) { + uiState = "stale"; + } else if (isCorrupted) { + uiState = "corrupted"; + } else if (hasChunks) { + uiState = "ready"; + } else { + uiState = "idle"; + } + + // ── State rendering ── + switch (uiState) { + case "building": { + const track = embedControls.createEl("div", { + cls: "paperforge-progress-track", + }); + track.style.cssText = "flex:1;"; + const pct = + total > 0 + ? ((current / total) * 100).toFixed(1) + : "0"; + const doneSeg = track.createEl("div", { + cls: "paperforge-progress-seg done", + }); + doneSeg.style.cssText = `width:${pct}%; min-width:${current > 0 ? "2px" : "0"};`; + if (current < total) { + const pendingSeg = track.createEl("div", { + cls: "paperforge-progress-seg pending", + }); + pendingSeg.style.cssText = `width:${(100 - parseFloat(pct)).toFixed(1)}%;`; + } + embedStatusText.createEl("span", { + cls: "paperforge-embed-progress-text", + text: `${current}/${total} papers`, + }); + if (key) { + embedStatusText.createEl("span", { + cls: "paperforge-embed-progress-key", + text: ` (${key})`, + }); + } + // Warning button: Stop + const stopBtn = embedControls.createEl("button"); + stopBtn.setText(t("retrieval_stop")); + stopBtn.className = "mod-warning"; + stopBtn.addEventListener("click", () => { + this._callPython(["embed", "stop", "--json"], { + timeout: 8000, + }); + this.display(); + }); + break; } - if (hasChunks && !isCorrupted) { + case "stopping": { + const track = embedControls.createEl("div", { + cls: "paperforge-progress-track", + }); + track.style.cssText = "flex:1; opacity:0.5;"; + const pct = + total > 0 + ? ((current / total) * 100).toFixed(1) + : "0"; + const doneSeg = track.createEl("div", { + cls: "paperforge-progress-seg done", + }); + doneSeg.style.cssText = `width:${pct}%; min-width:${current > 0 ? "2px" : "0"};`; + if (current < total) { + const pendingSeg = track.createEl("div", { + cls: "paperforge-progress-seg pending", + }); + pendingSeg.style.cssText = `width:${(100 - parseFloat(pct)).toFixed(1)}%;`; + } + embedStatusText.createEl("span", { + text: t("retrieval_build_stopping"), + }); + const stopBtn = embedControls.createEl("button"); + stopBtn.setText(t("retrieval_stop")); + stopBtn.className = "mod-warning"; + stopBtn.setAttr("disabled", ""); + break; + } + + case "failed": { + embedStatusText.createEl("div", { + cls: "paperforge-desc-box", + text: + t("retrieval_build_failed") + + (buildMessage ? ": " + buildMessage : ""), + attr: { style: "color:var(--text-error);" }, + }); + // Primary CTA: Retry + const retryBtn = embedControls.createEl("button"); + retryBtn.setText(t("retrieval_retry")); + retryBtn.className = "mod-cta"; + retryBtn.addEventListener("click", () => + startBuild("--resume") + ); + // Secondary: Force Rebuild + const forceBtn = embedControls.createEl("button"); + forceBtn.setText(t("retrieval_force_rebuild")); + forceBtn.style.marginLeft = "6px"; + forceBtn.addEventListener("click", () => + startBuild("--force") + ); + break; + } + + case "stopped": { + embedStatusText.setText(t("retrieval_build_stopped")); + // Primary CTA: Resume + const resumeBtn = embedControls.createEl("button"); + resumeBtn.setText(t("retrieval_retry")); + resumeBtn.className = "mod-cta"; + resumeBtn.addEventListener("click", () => + startBuild("--resume") + ); + break; + } + + case "corrupted": { + embedStatusText.createEl("div", { + cls: "paperforge-desc-box", + text: t("feat_vector_corrupted"), + attr: { + style: + "background:var(--background-modifier-warning);", + }, + }); + // Primary CTA: Force Rebuild (no destructive warning on corrupted) + const forceBtn = embedControls.createEl("button"); + forceBtn.setText(t("retrieval_force_rebuild")); + forceBtn.className = "mod-cta"; + forceBtn.addEventListener("click", () => + startBuild("--force") + ); + break; + } + + case "stale": { + embedStatusText.createEl("div", { + cls: "paperforge-desc-box", + text: t("retrieval_build_stale"), + attr: { style: "color:var(--text-warning);" }, + }); + // Primary CTA: Rebuild + const rebuildBtn = embedControls.createEl("button"); + rebuildBtn.setText(t("retrieval_rebuild_vectors")); + rebuildBtn.className = "mod-cta"; + rebuildBtn.addEventListener("click", () => + startBuild("--resume") + ); + break; + } + + case "ready": { embedControls.createEl("span", { - text: embedChunks + " chunks embedded", + text: totalChunks + " chunks embedded", cls: "setting-item-description", }); + // Primary CTA: Rebuild Vectors + const rebuildBtn = embedControls.createEl("button"); + rebuildBtn.setText(t("retrieval_rebuild_vectors")); + rebuildBtn.className = "mod-cta"; + rebuildBtn.addEventListener("click", () => + startBuild("--resume") + ); + // Secondary: Force Rebuild + const forceBtn = embedControls.createEl("button"); + forceBtn.setText(t("retrieval_force_rebuild")); + forceBtn.style.marginLeft = "6px"; + forceBtn.addEventListener("click", () => + startBuild("--force") + ); + break; } - const buildBtn = embedControls.createEl("button"); - buildBtn.setText( - hasChunks ? t("feat_rebuild_btn") : t("feat_build_btn") - ); - buildBtn.addClass("mod-cta"); - buildBtn.addEventListener("click", () => startBuild("--resume")); - if (!isCorrupted && hasChunks) { - const forceBtn2 = embedControls.createEl("button"); - forceBtn2.setText(t("feat_vector_rebuild_force_btn")); - forceBtn2.style.marginLeft = "6px"; - forceBtn2.addEventListener("click", () => startBuild("--force")); + + case "deps-missing": { + embedStatusText.setText(t("retrieval_build_deps_missing")); + // Link-style: Install Dependencies redirects to full settings display + const installBtn = embedControls.createEl("a"); + installBtn.setText(t("feat_install_deps")); + installBtn.style.cssText = + "cursor:pointer; text-decoration:underline;"; + installBtn.addEventListener("click", () => { + this.display(); + }); + break; + } + + case "runtime-mismatch": { + embedStatusText.createEl("div", { + cls: "paperforge-desc-box", + text: t("retrieval_build_runtime_mismatch"), + attr: { style: "color:var(--text-warning);" }, + }); + // Link-style: Sync Runtime navigates to Runtime Health section + const syncLink = embedControls.createEl("a"); + syncLink.setText(t("runtime_health_sync")); + syncLink.style.cssText = + "cursor:pointer; text-decoration:underline;"; + syncLink.addEventListener("click", () => { + this.display(); + }); + break; + } + + case "idle": + default: { + embedStatusText.setText(t("retrieval_build_idle")); + // Primary CTA: Build + const buildBtn = embedControls.createEl("button"); + buildBtn.setText(t("feat_build_btn")); + buildBtn.className = "mod-cta"; + buildBtn.addEventListener("click", () => + startBuild("--resume") + ); + break; } } }; From 6b53de813501684f109d24fee2aad9b3d880adb8 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:56:20 +0800 Subject: [PATCH 07/21] feat: add 33 retrieval_* i18n keys for error distinction and recovery UI Adds all retrieval state labels, button text, warning messages, and descriptive copy in English and Chinese under the retrieval_* prefix. Prepares i18n foundation for search domain (8 states) and build domain (10 states) per PRD #57 and issue #62. --- paperforge/plugin/src/i18n.ts | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/paperforge/plugin/src/i18n.ts b/paperforge/plugin/src/i18n.ts index 1de673c9..697d88da 100644 --- a/paperforge/plugin/src/i18n.ts +++ b/paperforge/plugin/src/i18n.ts @@ -283,6 +283,40 @@ const LANG: Record> = { version_compare_title: "{vA} vs {vB}", version_compare_paragraphs: "{n} paragraphs changed", version_error_read: "Cannot read version data", + retrieval_search_placeholder: "Search papers... (@ for deep search)", + retrieval_search_placeholder_deep: "Search papers via deep retrieval...", + retrieval_search_idle_hint: "Type to search metadata, or start with @ for deep semantic search", + retrieval_searching_metadata: "Searching metadata...", + retrieval_searching_deep: "Running deep search...", + retrieval_search_cancel: "Cancel", + retrieval_results_count: "{n} result{s}", + retrieval_empty: "No matching papers found.", + retrieval_empty_tips: "Try broader terms or @ deep search.", + retrieval_vectors_not_built: "Vectors Not Built", + retrieval_vectors_not_built_desc: "Vector index has not been built. Search requires a built vector index.", + retrieval_open_vector_settings: "Open Vector Settings", + retrieval_backend_unavailable: "Backend Unavailable", + retrieval_backend_unavailable_desc: "The Python CLI search backend is not responding.", + retrieval_run_doctor: "Run Doctor", + retrieval_retry: "Retry", + retrieval_timeout_title: "Search Timed Out", + retrieval_timeout_desc: "The search took too long. You can retry or try a simpler query.", + retrieval_model_changed: "Model Changed", + retrieval_model_changed_desc: "The embedding model has changed since vectors were built. Rebuilding is required.", + retrieval_rebuild_vectors: "Rebuild Vectors", + retrieval_internal_error: "An internal error occurred. Check the console for details.", + retrieval_build_idle: "Vectors not yet built", + retrieval_build_ready: "Vectors ready", + retrieval_build_stopping: "Stopping...", + retrieval_build_stopped: "Build stopped. Resume to continue.", + retrieval_build_failed: "Build failed", + retrieval_build_stale: "Previous build was interrupted. Resume to continue.", + retrieval_build_deps_missing: "Dependencies not installed", + retrieval_build_runtime_mismatch: "Plugin and CLI versions differ", + retrieval_stop: "Stop", + retrieval_force_rebuild: "Force Rebuild", + retrieval_rebuild_warning: "Rebuild will replace {n} existing chunk(s). Continue?", + retrieval_no_python: "No Python found. Check Installation tab.", }, zh: { @@ -543,6 +577,40 @@ const LANG: Record> = { version_compare_title: "{vA} vs {vB}", version_compare_paragraphs: "{n} 段有变化", version_error_read: "无法读取版本数据", + retrieval_search_placeholder: "搜索论文... (@ 进行深度搜索)", + retrieval_search_placeholder_deep: "通过深度检索搜索论文...", + retrieval_search_idle_hint: "输入关键字搜索元数据,或以 @ 开头进行深度语义搜索", + retrieval_searching_metadata: "正在搜索元数据...", + retrieval_searching_deep: "正在运行深度搜索...", + retrieval_search_cancel: "取消", + retrieval_results_count: "找到 {n} 条结果", + retrieval_empty: "未找到匹配的论文。", + retrieval_empty_tips: "尝试更宽泛的关键词,或使用 @ 进行深度搜索。", + retrieval_vectors_not_built: "向量索引未构建", + retrieval_vectors_not_built_desc: "向量索引尚未构建,搜索需要先构建向量索引。", + retrieval_open_vector_settings: "打开向量设置", + retrieval_backend_unavailable: "后端不可用", + retrieval_backend_unavailable_desc: "Python CLI 搜索后端无响应。", + retrieval_run_doctor: "运行诊断", + retrieval_retry: "重试", + retrieval_timeout_title: "搜索超时", + retrieval_timeout_desc: "搜索耗时过长。你可以重试,或尝试简化查询。", + retrieval_model_changed: "模型已更换", + retrieval_model_changed_desc: "嵌入模型已更换,需要重建向量。", + retrieval_rebuild_vectors: "重建向量", + retrieval_internal_error: "发生内部错误。请查看控制台了解详情。", + retrieval_build_idle: "向量索引尚未构建", + retrieval_build_ready: "向量索引就绪", + retrieval_build_stopping: "正在停止…", + retrieval_build_stopped: "构建已停止。点击继续以恢复。", + retrieval_build_failed: "构建失败", + retrieval_build_stale: "上次构建被中断。点击继续以恢复。", + retrieval_build_deps_missing: "依赖未安装", + retrieval_build_runtime_mismatch: "插件与 CLI 版本不匹配", + retrieval_stop: "停止", + retrieval_force_rebuild: "强制重建", + retrieval_rebuild_warning: "重建将替换 {n} 个已有的 chunk。是否继续?", + retrieval_no_python: "未找到 Python。请查看安装标签页。", }, }; From 6e4b446ca224a5e0e5db8fb454674627f4b74112 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:56:25 +0800 Subject: [PATCH 08/21] feat: add retrieval error code routing in classifyError Maps 7 retrieval error codes (VECTOR_NOT_BUILT, VECTOR_CORRUPTED, MODEL_CHANGED, BACKEND_UNAVAILABLE, TIMEOUT, INTERNAL_ERROR, NO_PYTHON) to distinct UI states with type, message, recoverable flag, and action. Adds 7 new test cases for the error classification routing. --- .../plugin/src/services/python-bridge.ts | 7 +++ paperforge/plugin/tests/errors.test.ts | 49 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/paperforge/plugin/src/services/python-bridge.ts b/paperforge/plugin/src/services/python-bridge.ts index da72f152..e4cb6175 100644 --- a/paperforge/plugin/src/services/python-bridge.ts +++ b/paperforge/plugin/src/services/python-bridge.ts @@ -147,6 +147,13 @@ export function classifyError(errorCode: string): ErrorClassification { "pip-failed": { type: "pip_install_failure", message: "pip install command failed", recoverable: true }, ETIMEDOUT: { type: "timeout", message: "Subprocess timed out", recoverable: true, action: "retry" }, timeout: { type: "timeout", message: "Subprocess timed out", recoverable: true, action: "retry" }, + NO_PYTHON: { type: "no_python", message: "Python executable not found", recoverable: true, action: "open-setup" }, + VECTOR_NOT_BUILT: { type: "vectors_not_built", message: "Vector index has not been built yet", recoverable: true, action: "open-vector-settings" }, + VECTOR_CORRUPTED: { type: "vectors_corrupted", message: "Vector index is corrupted", recoverable: true, action: "force-rebuild" }, + MODEL_CHANGED: { type: "model_changed", message: "Embedding model has changed since vectors were built", recoverable: true, action: "rebuild-vectors" }, + BACKEND_UNAVAILABLE: { type: "backend_unavailable", message: "Python CLI search backend is not responding", recoverable: true, action: "run-doctor" }, + TIMEOUT: { type: "timeout", message: "Search timed out", recoverable: true, action: "retry" }, + INTERNAL_ERROR: { type: "internal_error", message: "An internal error occurred", recoverable: false }, }; const match = patterns[code]; if (match) return { ...match }; diff --git a/paperforge/plugin/tests/errors.test.ts b/paperforge/plugin/tests/errors.test.ts index 61b5435f..cb38ce9f 100644 --- a/paperforge/plugin/tests/errors.test.ts +++ b/paperforge/plugin/tests/errors.test.ts @@ -39,6 +39,55 @@ describe('classifyError', () => { expect(result.action).toBe('retry'); }); + + it('classifies NO_PYTHON as no_python with open-setup action', () => { + const result = classifyError('NO_PYTHON'); + expect(result.type).toBe('no_python'); + expect(result.recoverable).toBe(true); + expect(result.action).toBe('open-setup'); + }); + + it('classifies VECTOR_NOT_BUILT as vectors_not_built with open-vector-settings action', () => { + const result = classifyError('VECTOR_NOT_BUILT'); + expect(result.type).toBe('vectors_not_built'); + expect(result.recoverable).toBe(true); + expect(result.action).toBe('open-vector-settings'); + }); + + it('classifies VECTOR_CORRUPTED as vectors_corrupted with force-rebuild action', () => { + const result = classifyError('VECTOR_CORRUPTED'); + expect(result.type).toBe('vectors_corrupted'); + expect(result.recoverable).toBe(true); + expect(result.action).toBe('force-rebuild'); + }); + + it('classifies MODEL_CHANGED as model_changed with rebuild-vectors action', () => { + const result = classifyError('MODEL_CHANGED'); + expect(result.type).toBe('model_changed'); + expect(result.recoverable).toBe(true); + expect(result.action).toBe('rebuild-vectors'); + }); + + it('classifies BACKEND_UNAVAILABLE as backend_unavailable with run-doctor action', () => { + const result = classifyError('BACKEND_UNAVAILABLE'); + expect(result.type).toBe('backend_unavailable'); + expect(result.recoverable).toBe(true); + expect(result.action).toBe('run-doctor'); + }); + + it('classifies TIMEOUT as timeout with retry action', () => { + const result = classifyError('TIMEOUT'); + expect(result.type).toBe('timeout'); + expect(result.recoverable).toBe(true); + expect(result.action).toBe('retry'); + expect(result.message).toContain('Search'); + }); + + it('classifies INTERNAL_ERROR as internal_error not recoverable', () => { + const result = classifyError('INTERNAL_ERROR'); + expect(result.type).toBe('internal_error'); + expect(result.recoverable).toBe(false); + }); it('classifies unknown error strings as unknown', () => { const result = classifyError('SOME_RANDOM_ERROR'); expect(result.type).toBe('unknown'); From 51018943ad5de36cc05806de7fb5a173610d2efc Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:56:31 +0800 Subject: [PATCH 09/21] feat: implement 8 search domain states with keyboard shortcuts and a11y in dashboard Adds _renderSearchState() rendering 8 distinguishable states: idle, searching (M/@), results, empty, vectors-not-built, backend-unavailable, timeout, model-changed. Keyboard: / focuses search, Escape cancels, ArrowUp/Down navigates results, Enter opens note, Ctrl+Enter forces deep mode. Accessibility: role=alert on errors, aria-live=polite on results and progress, role=listbox with aria-selected/aria-posinset on cards, aria-setsize, tabindex=0 on result cards, focus management on state transitions. Focus management: Stop button on build start, first result on search complete, error banner on failure. --- paperforge/plugin/src/views/dashboard.ts | 416 +++++++++++++++++++++-- 1 file changed, 391 insertions(+), 25 deletions(-) diff --git a/paperforge/plugin/src/views/dashboard.ts b/paperforge/plugin/src/views/dashboard.ts index 2b2a9ea6..aa2d0820 100644 --- a/paperforge/plugin/src/views/dashboard.ts +++ b/paperforge/plugin/src/views/dashboard.ts @@ -96,6 +96,11 @@ export class PaperForgeStatusView extends ItemView { _searchInput: HTMLInputElement | null = null; _searchResultsEl: HTMLElement | null = null; _searchTimer: ReturnType | undefined = undefined; + _searchState: string = "idle"; + _searchMode: "M" | "@" = "M"; + _searchResults: unknown[] | null = null; + _searchActiveIndex: number = -1; + _onKeyDown: ((e: KeyboardEvent) => void) | null = null; constructor(leaf: WorkspaceLeaf) { super(leaf); @@ -127,8 +132,20 @@ export class PaperForgeStatusView extends ItemView { this._setupEventSubscriptions(); this._fetchVersion(); this._detectAndSwitch(); - } + // Global "/" keyboard shortcut to focus search input + this._onKeyDown = (e: KeyboardEvent) => { + if (e.key === "/" && !e.ctrlKey && !e.metaKey && !e.altKey) { + // Only focus search when not already in an input/textarea + const tag = (e.target as HTMLElement)?.tagName?.toLowerCase(); + if (tag !== "input" && tag !== "textarea") { + e.preventDefault(); + this._searchInput?.focus(); + } + } + }; + document.addEventListener("keydown", this._onKeyDown); + } async onClose() { if (this._modeSubscribers && this._modeSubscribers.length > 0) { for (const sub of this._modeSubscribers) { @@ -144,6 +161,16 @@ export class PaperForgeStatusView extends ItemView { clearTimeout(this._leafChangeTimer); this._leafChangeTimer = null; } + // Remove global keydown listener + if (this._onKeyDown) { + document.removeEventListener("keydown", this._onKeyDown); + this._onKeyDown = null; + } + // Reset search state + this._searchState = "idle"; + this._searchResults = null; + this._searchActiveIndex = -1; + this._searchTimer = undefined; this._cachedItems = null; this._cachedStats = null; } @@ -180,7 +207,10 @@ export class PaperForgeStatusView extends ItemView { this._invalidateIndex(); this._detectAndSwitch(); }); - this._messageEl = root.createEl("div", { cls: "paperforge-message" }); + this._messageEl = root.createEl("div", { + cls: "paperforge-message", + attr: { "aria-live": "polite" }, + }); this._contentEl = root.createEl("div", { cls: "paperforge-content-area" }); } @@ -2389,28 +2419,93 @@ export class PaperForgeStatusView extends ItemView { cls: "paperforge-search-results", }); + // Update placeholder from i18n on init + this._searchInput.placeholder = t("retrieval_search_placeholder"); + // Detect @ mode prefix + debounced metadata search this._searchInput.addEventListener("input", () => { const val = this._searchInput?.value || ""; if (val.startsWith("@") && !val.startsWith("@ ")) { + this._searchMode = "@"; modeBadge.setText("@"); modeBadge.addClass("deep"); + if (this._searchInput) this._searchInput.placeholder = t("retrieval_search_placeholder_deep"); } else { + this._searchMode = "M"; modeBadge.setText("M"); modeBadge.removeClass("deep"); + if (this._searchInput) this._searchInput.placeholder = t("retrieval_search_placeholder"); } // Cancel pending debounce clearTimeout(this._searchTimer); + // Reset results & show idle when input cleared + if (!val.trim()) { + this._searchState = "idle"; + this._searchResults = null; + this._searchActiveIndex = -1; + this._renderSearchState(); + return; + } // Debounced metadata search for non-@ queries - if (!val.startsWith("@") && val.trim()) { + if (!val.startsWith("@")) { this._searchTimer = setTimeout(() => { this.executeSearch(); }, 200); } }); - // Enter triggers CLI search (full search for @ or explicit) + // Keyboard: Enter triggers search, Escape clears, arrows navigate, Ctrl+Enter forces CLI this._searchInput.addEventListener("keydown", (e: KeyboardEvent) => { + if (e.key === "Escape") { + e.preventDefault(); + if (this._searchInput) { + this._searchInput.value = ""; + this._searchInput.blur(); + } + this._searchState = "idle"; + this._searchResults = null; + this._searchActiveIndex = -1; + this._renderSearchState(); + return; + } + if (e.key === "ArrowDown" || e.key === "ArrowUp") { + if (this._searchState !== "results" || !this._searchResults?.length) return; + e.preventDefault(); + const max = this._searchResults.length; + if (e.key === "ArrowDown") { + this._searchActiveIndex = Math.min(this._searchActiveIndex + 1, max - 1); + } else { + this._searchActiveIndex = Math.max(this._searchActiveIndex - 1, -1); + } + // Update aria-selected on result cards + const cards = this._searchResultsEl?.querySelectorAll(".paperforge-search-result-card"); + if (cards) { + cards.forEach((c, i) => { + if (i === this._searchActiveIndex) { + c.setAttribute("aria-selected", "true"); + c.classList.add("active"); + } else { + c.setAttribute("aria-selected", "false"); + c.classList.remove("active"); + } + }); + } + return; + } + if (e.key === "Enter" && e.ctrlKey) { + // Ctrl+Enter forces CLI deep search regardless of mode + e.preventDefault(); + if (this._searchTimer) { + clearTimeout(this._searchTimer); + this._searchTimer = undefined; + } + // Override mode to @ for this search + const originalMode = this._searchMode; + this._searchMode = "@"; + this.executeSearch(); + this._searchMode = originalMode; + return; + } if (e.key === "Enter") { e.preventDefault(); if (this._searchTimer) { @@ -2422,17 +2517,232 @@ export class PaperForgeStatusView extends ItemView { }); } + _renderSearchState() { + if (!this._searchResultsEl) return; + this._searchResultsEl.empty(); + this._searchResultsEl.removeAttribute("role"); + this._searchResultsEl.removeAttribute("aria-live"); + // Re-enable input on any state change + if (this._searchInput) this._searchInput.disabled = false; + const state = this._searchState; + + switch (state) { + case "idle": { + // Show placeholder hint in the input's placeholder — already set by input handler + // Keep results area empty + break; + } + case "searching": { + const isDeep = this._searchMode === "@"; + this._searchResultsEl.createEl("div", { + cls: "paperforge-search-loading", + text: isDeep ? t("retrieval_searching_deep") : t("retrieval_searching_metadata"), + }); + this._searchResultsEl.setAttr("aria-live", "polite"); + // Disable input during deep search + if (isDeep && this._searchInput) { + this._searchInput.disabled = true; + } + break; + } + case "results": { + this._searchResultsEl.setAttr("role", "listbox"); + this._searchResultsEl.setAttr("aria-live", "polite"); + if (this._searchResults) { + this._renderSearchResultsList(this._searchResults, this._searchMode === "@"); + } + // Focus management: focus first result after a short delay + setTimeout(() => { + const firstCard = this._searchResultsEl?.querySelector(".paperforge-search-result-card"); + if (firstCard && firstCard instanceof HTMLElement) { + firstCard.focus(); + } + }, 100); + break; + } + case "empty": { + const emptyEl = this._searchResultsEl.createEl("div", { + cls: "paperforge-search-empty", + }); + emptyEl.setAttr("role", "alert"); + emptyEl.createEl("div", { + text: t("retrieval_empty"), + }); + emptyEl.createEl("div", { + cls: "paperforge-search-empty-tips", + text: t("retrieval_empty_tips"), + }); + break; + } + case "vectors-not-built": { + const warn = this._searchResultsEl.createEl("div", { + cls: "paperforge-search-state-card", + attr: { role: "alert" }, + }); + warn.addClass("warning-soft"); + warn.createEl("div", { + cls: "paperforge-search-state-title", + text: t("retrieval_vectors_not_built"), + }); + warn.createEl("div", { + cls: "paperforge-search-state-desc", + text: t("retrieval_vectors_not_built_desc"), + }); + const btn = warn.createEl("button", { + cls: "pf-btn-link", + text: t("retrieval_open_vector_settings"), + }); + btn.addEventListener("click", () => { + const setting = (this.app as unknown as Record)["setting"]; + if (setting && typeof setting === "object") { + const openTab = (setting as Record)["openTab"]; + if (typeof openTab === "function") { + openTab.call(setting, "paperforge"); + } + } + }); + // Focus management: focus the action button + setTimeout(() => { + btn.focus(); + }, 100); + break; + } + case "backend-unavailable": { + const err = this._searchResultsEl.createEl("div", { + cls: "paperforge-search-state-card", + attr: { role: "alert" }, + }); + err.addClass("error-soft"); + err.createEl("div", { + cls: "paperforge-search-state-title", + text: t("retrieval_backend_unavailable"), + }); + err.createEl("div", { + cls: "paperforge-search-state-desc", + text: t("retrieval_backend_unavailable_desc"), + }); + const actions = err.createEl("div", { cls: "paperforge-search-state-actions" }); + const doctorBtn = actions.createEl("button", { + cls: "pf-btn-primary", + text: t("retrieval_run_doctor"), + }); + doctorBtn.addEventListener("click", () => { + const vp = (this.app.vault.adapter as unknown as Record)["basePath"]; + if (typeof vp === "string") { + const { path: pyExe, extraArgs = [] } = resolvePythonExecutable(vp, null, undefined, undefined); + spawn(pyExe, [...extraArgs, "-m", "paperforge", "doctor"], { + cwd: vp, + stdio: "inherit", + }); + } + }); + const retryBtn = actions.createEl("button", { + cls: "pf-btn-secondary", + text: t("retrieval_retry"), + }); + retryBtn.addEventListener("click", () => { + this.executeSearch(); + }); + // Focus: primary action + setTimeout(() => { + doctorBtn.focus(); + }, 100); + break; + } + case "timeout": { + const err = this._searchResultsEl.createEl("div", { + cls: "paperforge-search-state-card", + attr: { role: "alert" }, + }); + err.addClass("warning-soft"); + err.createEl("div", { + cls: "paperforge-search-state-title", + text: t("retrieval_timeout_title"), + }); + err.createEl("div", { + cls: "paperforge-search-state-desc", + text: t("retrieval_timeout_desc"), + }); + const retryBtn = err.createEl("button", { + cls: "pf-btn-primary", + text: t("retrieval_retry"), + }); + retryBtn.addEventListener("click", () => { + this.executeSearch(); + }); + // Focus: retry button + setTimeout(() => { + retryBtn.focus(); + }, 100); + break; + } + case "model-changed": { + const warn = this._searchResultsEl.createEl("div", { + cls: "paperforge-search-state-card", + attr: { role: "alert" }, + }); + warn.addClass("warning-soft"); + warn.createEl("div", { + cls: "paperforge-search-state-title", + text: t("retrieval_model_changed"), + }); + warn.createEl("div", { + cls: "paperforge-search-state-desc", + text: t("retrieval_model_changed_desc"), + }); + const rebuildBtn = warn.createEl("button", { + cls: "pf-btn-primary", + text: t("retrieval_rebuild_vectors"), + }); + rebuildBtn.addEventListener("click", () => { + // Trigger rebuild from settings + const setting = (this.app as unknown as Record)["setting"]; + if (setting && typeof setting === "object") { + const openTab = (setting as Record)["openTab"]; + if (typeof openTab === "function") { + openTab.call(setting, "paperforge"); + } + } + }); + // Focus: rebuild button + setTimeout(() => { + rebuildBtn.focus(); + }, 100); + break; + } + default: { + // Fallback: show internal error for unknown states + const err = this._searchResultsEl.createEl("div", { + cls: "paperforge-search-state-card", + text: t("retrieval_internal_error"), + attr: { role: "alert" }, + }); + err.addClass("error-soft"); + setTimeout(() => { + if (this._searchInput) this._searchInput.focus(); + }, 100); + break; + } + } + } + async executeSearch() { if (!this._searchInput || !this._searchResultsEl) return; const raw = this._searchInput.value.trim(); if (!raw) return; - const isDeep = raw.startsWith("@"); - const query = isDeep ? raw.slice(1).trim() : raw; + const isDeep = this._searchMode === "@" || raw.startsWith("@"); + const query = isDeep ? raw.replace(/^@\s*/, "").trim() : raw; if (!query) return; const mode = isDeep ? "retrieve" : "search"; + // Set searching state immediately + this._searchState = "searching"; + this._searchResults = null; + this._searchActiveIndex = -1; + this._renderSearchState(); + // Resolve vault path for CLI search const adapter = this.app.vault.adapter; let vaultPath = ""; @@ -2441,15 +2751,9 @@ export class PaperForgeStatusView extends ItemView { vaultPath = typeof bp === "string" ? bp : ""; } - this._searchResultsEl.empty(); - // ── CLI search path (deep search only) ── - this._searchResultsEl.createEl("div", { - cls: "paperforge-search-loading", - text: "Searching...", - }); - if (!vaultPath) { - this._renderSearchError("Could not determine vault path"); + this._searchState = "backend-unavailable"; + this._renderSearchState(); return; } @@ -2497,7 +2801,10 @@ export class PaperForgeStatusView extends ItemView { }); child.on("close", (code: number | null) => { if (code !== 0) { - this._renderSearchError(`Search failed (exit ${code})`); + // Map exit code to error state + const classification = classifyError(String(code)); + this._searchState = this._mapErrorToSearchState(classification.type); + this._renderSearchState(); return; } const rawOutput = chunks.join(""); @@ -2516,7 +2823,8 @@ export class PaperForgeStatusView extends ItemView { } } if (!jsonStr) { - this._renderSearchError("No JSON output from CLI"); + this._searchState = "internal-error"; + this._renderSearchState(); return; } try { @@ -2534,20 +2842,57 @@ export class PaperForgeStatusView extends ItemView { } } - this.renderSearchResults(results, isDeep); + this._searchResults = results; + this._searchState = results.length > 0 ? "results" : "empty"; + this._renderSearchState(); } catch (e) { const msg = e instanceof Error ? e.message : String(e); - this._renderSearchError("Failed to parse results: " + msg); + this._searchState = "internal-error"; + this._renderSearchState(); } }); child.on("error", (err: Error) => { - this._renderSearchError("Process error: " + err.message); + // Check for structured error in stderr + const errCode = (err as unknown as Record)["code"]; + if (typeof errCode === "string") { + const classification = classifyError(errCode); + this._searchState = this._mapErrorToSearchState(classification.type); + } else { + this._searchState = "backend-unavailable"; + } + this._renderSearchState(); }); } - renderSearchResults(results: unknown[], isDeep: boolean) { + /** Map classifyError types to _searchState values */ + _mapErrorToSearchState(errorType: string): string { + switch (errorType) { + case "vectors_not_built": + return "vectors-not-built"; + case "vectors_corrupted": + return "vectors-not-built"; + case "backend_unavailable": + return "backend-unavailable"; + case "model_changed": + return "model-changed"; + case "timeout": + return "timeout"; + case "no_python": + case "python_missing": + case "import_failed": + case "version_mismatch": + return "backend-unavailable"; + default: + return "backend-unavailable"; + } + } + + _renderSearchResultsList(results: unknown[], isDeep: boolean) { if (!this._searchResultsEl) return; - this._searchResultsEl.empty(); + + // Container already has role="listbox" set by _renderSearchState + // Add aria-live polite for live updates + this._searchResultsEl.setAttr("aria-live", "polite"); if (results.length === 0) { this._searchResultsEl.createEl("div", { @@ -2560,21 +2905,33 @@ export class PaperForgeStatusView extends ItemView { const header = this._searchResultsEl.createEl("div", { cls: "paperforge-search-results-header", }); - header.createEl("span", { - text: `${results.length} result${results.length !== 1 ? "s" : ""}`, + const countSpan = header.createEl("span", { + text: t("retrieval_results_count") + .replace("{n}", String(results.length)) + .replace("{s}", results.length !== 1 ? "s" : ""), }); + countSpan.setAttr("aria-live", "polite"); header.createEl("span", { cls: "paperforge-search-mode", text: isDeep ? "@" : "M", }); - for (const r of results) { + for (let i = 0; i < results.length; i++) { + const r = results[i]; if (!r || typeof r !== "object") continue; const rec = r as Record; + const isActive = i === this._searchActiveIndex; const card = this._searchResultsEl.createEl("div", { cls: "paperforge-search-result-card", - attr: { role: "button" }, + attr: { + role: "option", + tabindex: "0", + "aria-selected": isActive ? "true" : "false", + "aria-posinset": String(i + 1), + "aria-setsize": String(results.length), + }, }); + if (isActive) card.addClass("active"); // Title const titleText = @@ -2633,6 +2990,15 @@ export class PaperForgeStatusView extends ItemView { }); } + // Enter key on card opens the note + card.addEventListener("keydown", (e: KeyboardEvent) => { + if (e.key === "Enter" && resolvedPath) { + e.preventDefault(); + const newLeaf = e.ctrlKey || e.metaKey; + this.app.workspace.openLinkText(resolvedPath, "", newLeaf); + } + }); + // Meta row const meta = card.createEl("div", { cls: "paperforge-search-result-meta", From e7a030d057a8d7700c487463bcd23e883f50ba46 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:35:26 +0800 Subject: [PATCH 10/21] refactor: remove ChromaDB dependency gating from status and preflight MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embed status no longer checks for chromadb import — vec0 runs in paperforge.db and doesn't need the ChromaDB library. The preflight check also no longer requires chromadb since vec0 backends do not depend on it. The chroma_backend module remains for legacy test compatibility but no longer gates any production build/status path. --- paperforge/commands/embed.py | 4 ---- paperforge/embedding/preflight.py | 10 ---------- 2 files changed, 14 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index 6de40077..982f87b9 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -122,10 +122,6 @@ def run(args: argparse.Namespace) -> int: import openai # noqa: F401 except ImportError: _dep_missing.append("openai") - try: - import chromadb # noqa: F401 - except ImportError: - _dep_missing.append("chromadb") write_vector_runtime( vault, enabled=bool(status.get("mode", "")), diff --git a/paperforge/embedding/preflight.py b/paperforge/embedding/preflight.py index 2d11e13c..091889ff 100644 --- a/paperforge/embedding/preflight.py +++ b/paperforge/embedding/preflight.py @@ -17,16 +17,6 @@ def _preflight_check(vault: Path, settings: dict | None = None) -> dict: "fix": 'Run: pip install "paperforge[vector]"', } - # 2. chromadb package - try: - import chromadb # noqa: F401 - except ImportError: - return { - "ok": False, - "error": "chromadb is not installed", - "fix": 'Run: pip install "paperforge[vector]"', - } - # 3. API key api_key = None if settings: From 59581c72bf2e295c6830c282382619348bd242d5 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:36:14 +0800 Subject: [PATCH 11/21] fix: --resume checks vec0 meta tables, not ChromaDB path Replace get_vector_db_path() directory existence check with vec0 meta table row counts via SQLite. Resume now checks whether any rows exist in vec_fulltext_meta, vec_body_meta, or vec_objects_meta. If none exist, starts a fresh build. This removes the last ChromaDB path dependency from the resume control flow. --- paperforge/commands/embed.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index 982f87b9..c964c39a 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -287,20 +287,34 @@ def run(args: argparse.Namespace) -> int: print(msg) mark_vector_build_state(vault, status="idle", current=0, pid=0) resume = False + # 门二:no vec0 rows → fresh build(不是 error) + from paperforge.memory.db import ( + ensure_vec_extension, + get_connection, + get_memory_db_path, + ) + from paperforge.memory.schema import ensure_schema - # 门二:missing DB → fresh build(不是 error) - db_path = get_vector_db_path(vault) - if not db_path.exists(): + _db_path = get_memory_db_path(vault) + _any_rows = False + if _db_path.exists(): + _conn = get_connection(_db_path) + try: + ensure_vec_extension(_conn) + ensure_schema(_conn) + for _mt in ("vec_fulltext_meta", "vec_body_meta", "vec_objects_meta"): + _r = _conn.execute(f"SELECT COUNT(*) AS cnt FROM {_mt}").fetchone() + if _r and _r["cnt"] > 0: + _any_rows = True + break + except Exception: + pass + finally: + _conn.close() + if not _any_rows: resume = False else: - # 门三:corrupted DB - ok, err = _assert_collections_healthy(vault) - if not ok: - msg = f"Vector DB corrupted ({err}). Use --force to rebuild." - print(msg) - return 1 - - # 过三道门后,正常 model check + # 门三:过三道门后,正常 model check stored_model = build_state.get("model", "") if stored_model and _current_model and stored_model != _current_model: msg = f"Model changed: {stored_model} -> {_current_model}. Re-embedding all papers." From 11eb2946d957bcfce9f6c13d0eb4a3b4c2a5357d Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:36:55 +0800 Subject: [PATCH 12/21] fix: --force drops vec0 tables instead of ChromaDB directory Replace shutil.rmtree on the ChromaDB path with DROP TABLE IF EXISTS on vec0 virtual tables and their companion meta tables. Force rebuild now opens paperforge.db and drops vec_fulltext, vec_body, vec_objects, vec_fulltext_meta, vec_body_meta, and vec_objects_meta. Also replaced the remaining get_vector_db_path reference in the error handler with get_memory_db_path. Removed get_vector_db_path import from embed.py since it is no longer used in active control flow. --- paperforge/commands/embed.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index c964c39a..fa37aaba 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -12,7 +12,6 @@ from paperforge.core.result import PFError, PFResult from paperforge.embedding import ( delete_paper_vectors, get_embed_status, - get_vector_db_path, mark_vector_build_state, read_vector_build_state, ) @@ -325,16 +324,22 @@ def run(args: argparse.Namespace) -> int: _force_rebuild = args.force or (resume is False and getattr(args, "resume", False)) if _force_rebuild: _gc.collect() - db_path = get_vector_db_path(vault) - if db_path.exists(): - import shutil - - shutil.rmtree(str(db_path), ignore_errors=True) - if db_path.exists(): - import time - - time.sleep(0.5) - shutil.rmtree(str(db_path), ignore_errors=True) + _db_path = get_memory_db_path(vault) + if _db_path.exists(): + _conn = get_connection(_db_path) + try: + from paperforge.memory.db import ensure_vec_extension + from paperforge.memory.schema import ensure_schema + ensure_vec_extension(_conn) + ensure_schema(_conn) + for _t in ("vec_fulltext", "vec_body", "vec_objects", + "vec_fulltext_meta", "vec_body_meta", "vec_objects_meta"): + _conn.execute(f'DROP TABLE IF EXISTS "{_t}"') + _conn.commit() + except Exception: + pass + finally: + _conn.close() mark_vector_build_state( vault, @@ -579,7 +584,7 @@ def run(args: argparse.Namespace) -> int: deps_installed=True, deps_missing=None, py_version=sys.version.split()[0], - db_exists=get_vector_db_path(vault).exists(), + db_exists=get_memory_db_path(vault).exists(), chunk_count=_actual, body_chunk_count=0, object_chunk_count=0, From 4c5d981fff69a72118b4b329a958fe3d9b7841cc Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Fri, 10 Jul 2026 23:34:50 +0800 Subject: [PATCH 13/21] fix: delete old vectors before writing new ones in build loop The previous ordering wrote encoded payloads first, then deleted ALL vectors for that paper (including the just-written ones). Swap the ordering so old vectors are deleted first and new ones survive. --- paperforge/commands/embed.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index fa37aaba..68f8dd74 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -386,12 +386,9 @@ def run(args: argparse.Namespace) -> int: paper_id=job.paper_id, pid=0, ) - return False - + delete_paper_vectors(vault, bundle.paper_id) for payload in bundle.payloads: write_encoded_payload(vault, payload) - # Delete old vectors only after all new payloads are written safely - delete_paper_vectors(vault, bundle.paper_id) processed_count += 1 papers_embedded += 1 From 0fd52273556fc8551f4b30dd71d8589fc19576c1 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:10:32 +0800 Subject: [PATCH 14/21] =?UTF-8?q?chore:=20fix=20ruff=20violations=20?= =?UTF-8?q?=E2=80=94=20unused=20imports,=20Path,=20dead=20code,=20formatti?= =?UTF-8?q?ng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- paperforge/commands/embed.py | 34 ++++--------------------- paperforge/plugin/main.js | 48 ++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 53 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index 68f8dd74..c1eb97d1 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -1,10 +1,12 @@ from __future__ import annotations import argparse +import contextlib import logging import os import sys from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait +from pathlib import Path from paperforge import __version__ as PF_VERSION from paperforge.core.errors import ErrorCode @@ -17,8 +19,6 @@ from paperforge.embedding import ( ) from paperforge.embedding.builder import ( PaperEmbeddingJob, - embed_body_units, - embed_object_units, encode_paper_job, get_body_units_for_embedding, get_object_units_for_embedding, @@ -26,7 +26,6 @@ from paperforge.embedding.builder import ( write_encoded_payload, ) from paperforge.embedding.preflight import _preflight_check -from paperforge.memory.chunker import chunk_fulltext from paperforge.memory.db import get_connection, get_memory_db_path from paperforge.memory.state_snapshot import write_vector_runtime from paperforge.retrieval.manifest import RETRIEVAL_POLICY_VERSION, compute_body_units_hash, compute_object_units_hash @@ -81,25 +80,6 @@ def _pid_alive(pid: int) -> bool: except Exception: return False -def _assert_collections_healthy(vault: Path) -> tuple[bool, str]: - """Probe sqlite-vec companion tables: connectivity + metadata accessibility.""" - from paperforge.memory.db import ensure_vec_extension, get_connection, get_memory_db_path - from paperforge.memory.schema import ensure_schema - - db_path = get_memory_db_path(vault) - if not db_path.exists(): - return False, "paperforge.db not found" - conn = get_connection(db_path) - try: - ensure_vec_extension(conn) - ensure_schema(conn) - for meta_table in ["vec_fulltext_meta", "vec_body_meta", "vec_objects_meta"]: - conn.execute(f"SELECT COUNT(*) FROM {meta_table}").fetchone() - except Exception as exc: - return False, f"{meta_table}: {exc}" - finally: - conn.close() - return True, "" logger = logging.getLogger(__name__) @@ -167,10 +147,8 @@ def run(args: argparse.Namespace) -> int: # Force-kill if still alive after timeout if _pid_alive(pid): import signal - try: + with contextlib.suppress(Exception): os.kill(pid, signal.SIGTERM) - except Exception: - pass # Settle to idle, preserving progress _current = read_vector_build_state(vault).get("current", state.get("current", 0)) mark_vector_build_state(vault, status="idle", current=_current, pid=0, message="") @@ -266,9 +244,7 @@ def run(args: argparse.Namespace) -> int: if build_state.get("status") == "running": stale = False pid = build_state.get("pid", 0) - if not pid: - stale = True - elif not _pid_alive(pid): + if not pid or not _pid_alive(pid): stale = True else: started = build_state.get("started_at", "") @@ -496,7 +472,7 @@ def run(args: argparse.Namespace) -> int: fulltext_rel = entry.get("fulltext_path", "") if not fulltext_rel: continue - fulltext_path = vault / fulltext_rel + vault / fulltext_rel ocr_root = vault / "System" / "PaperForge" / "ocr" / key has_files = (ocr_root / "structure" / "blocks.structured.jsonl").exists() and ( diff --git a/paperforge/plugin/main.js b/paperforge/plugin/main.js index d95235db..b963af93 100644 --- a/paperforge/plugin/main.js +++ b/paperforge/plugin/main.js @@ -1,11 +1,11 @@ -"use strict";var Rt=Object.create;var Le=Object.defineProperty;var Tt=Object.getOwnPropertyDescriptor;var Dt=Object.getOwnPropertyNames;var Bt=Object.getPrototypeOf,At=Object.prototype.hasOwnProperty;var Ot=(h,u)=>()=>(u||h((u={exports:{}}).exports,u),u.exports),Lt=(h,u)=>{for(var e in u)Le(h,e,{get:u[e],enumerable:!0})},rt=(h,u,e,t)=>{if(u&&typeof u=="object"||typeof u=="function")for(let r of Dt(u))!At.call(h,r)&&r!==e&&Le(h,r,{get:()=>u[r],enumerable:!(t=Tt(u,r))||t.enumerable});return h};var $=(h,u,e)=>(e=h!=null?Rt(Bt(h)):{},rt(u||!h||!h.__esModule?Le(e,"default",{value:h,enumerable:!0}):e,h)),Mt=h=>rt(Le({},"__esModule",{value:!0}),h);var qe=Ot((qt,Nt)=>{Nt.exports={versions:[{version:"1.5.15",date:"2026-06-01",title:"\u5168\u6587\u5B58\u50A8\u91CD\u6784 + OCR \u9605\u8BFB\u987A\u5E8F\u4FEE\u590D + Redo \u4E00\u952E\u91CD\u505A",breaking_or_migration:["\u5168\u6587\u6587\u4EF6\u73B0\u5728\u7EDF\u4E00\u5B58\u653E\u4E8E System/PaperForge/ocr/ \u4E0B\uFF0C\u4E0D\u518D\u5728\u5DE5\u4F5C\u533A\u4FDD\u7559\u526F\u672C","Redo OCR \u73B0\u5728\u4F1A\u7ACB\u5373\u6267\u884C\uFF08\u4E00\u952E\u5B8C\u6210\uFF09\uFF0C\u4E0D\u518D\u9700\u8981\u624B\u52A8\u518D\u8DD1\u4E00\u6B21"],new_features:["Redo OCR \u4E00\u952E\u95ED\u73AF\uFF1A\u52FE\u9009 \u2192 \u70B9\u6309\u94AE \u2192 \u81EA\u52A8\u5B8C\u6210\u5168\u90E8\u6D41\u7A0B","\u8BBE\u7F6E\u9875\u65B0\u589E\u300C\u66F4\u65B0\u4E0E\u624B\u518C\u300D\u6807\u7B7E\u9875\uFF0C\u53EF\u968F\u65F6\u67E5\u770B\u7248\u672C\u66F4\u65B0\u8BB0\u5F55\u548C\u4F7F\u7528\u624B\u518C","\u63D2\u4EF6\u66F4\u65B0\u540E\u81EA\u52A8\u5F39\u51FA\u66F4\u65B0\u8BF4\u660E"],fixes:["\u4FEE\u590D\u5168\u6587\u9605\u8BFB\u987A\u5E8F\u6DF7\u4E71\uFF0C\u4F18\u5316\u6574\u4F53\u6392\u7248\u4F53\u9A8C","\u4FEE\u590D\u7AE0\u8282\u6807\u9898\u548C\u6B63\u6587\u6BB5\u843D\u9519\u4F4D\u65AD\u5F00\u7684\u95EE\u9898","\u4FEE\u590D\u56FE\u8868\u548C\u5BF9\u5E94\u56FE\u6CE8\u88AB\u5206\u5F00\u7684\u95EE\u9898","\u4FEE\u590D\u9996\u9875\u6458\u8981\u533A\u5757\u6392\u5E8F\u5F02\u5E38","\u4FEE\u590D\u5E76\u6392\u56FE\u7247\u672A\u80FD\u81EA\u52A8\u5408\u5E76\u7684\u95EE\u9898","Dashboard \u73B0\u5728\u80FD\u6B63\u786E\u8BC6\u522B\u65B0\u7684\u5168\u6587\u6587\u4EF6\u4F4D\u7F6E"],recommended_actions:["\u65E7\u7248 OCR \u5168\u6587\u53EF\u80FD\u5B58\u5728\u9605\u8BFB\u987A\u5E8F\u95EE\u9898\uFF0C\u5EFA\u8BAE\u5BF9\u91CD\u8981\u8BBA\u6587\u6267\u884C\u4E00\u6B21 Redo OCR","\u6253\u5F00\u5168\u6587\u8BF7\u76F4\u63A5\u4F7F\u7528 Dashboard \u7684\u300C\u6253\u5F00\u5168\u6587\u300D\u6309\u94AE"]}]}});var Vt={};Lt(Vt,{default:()=>He});module.exports=Mt(Vt);var K=require("obsidian"),H=$(require("fs")),ke=$(require("path")),ie=require("child_process");var _e="paperforge-status",Ce="paperforge",st='',Y=[{id:"paperforge-sync",title:"Sync Library",desc:"Pull new references from Zotero and generate literature notes",icon:"\u21BB",cmd:"sync",okMsg:"Sync complete"},{id:"paperforge-ocr",title:"Run OCR",desc:"Extract full text and figures from PDFs via PaddleOCR",icon:"\u229E",cmd:"ocr",okMsg:"OCR started"},{id:"paperforge-doctor",title:"Run Doctor",desc:"Verify PaperForge setup \u2014 check configs, Zotero, paths, and index health",icon:"\u2695",cmd:"doctor",okMsg:"Doctor complete"},{id:"paperforge-repair",title:"Repair Issues",desc:"Fix three-way state divergence, path errors, and rebuild index",icon:"\u21BA",cmd:"repair",args:["--fix","--fix-paths"],okMsg:"Repair complete"},{id:"paperforge-ocr-redo",title:"Redo OCR",desc:"Re-run OCR for papers marked ocr_redo: true",icon:"\u21BA",cmd:"ocr",args:["redo"],okMsg:"OCR redo started"}],Fe={vault_path:"",setup_complete:!1,auto_update:!0,auto_update_on_startup:!0,agent_platform:"opencode",language:"",paddleocr_api_key:"",zotero_data_dir:"",python_path:"",features:{memory_layer:!0,vector_db:!1},selected_skill_platform:"opencode",vector_db_api_key:"",vector_db_api_base:"",vector_db_api_model:"text-embedding-3-small",frozen_skills:{},system_dir:"",resources_dir:"",literature_dir:"",base_dir:"",last_seen_version:""};function nt(h,u){if(!u||!u.note_path)return u;let e=h.vault.getAbstractFileByPath(u.note_path);if(!e)return u;let t=h.metadataCache.getFileCache(e),r=t&&t.frontmatter;if(!r)return u;let n={...u};for(let a of["do_ocr","analyze","ocr_status","ocr_redo","deep_reading_status"])Object.prototype.hasOwnProperty.call(r,a)&&(n[a]=r[a]);return n}function Ke(h,u){return h&&{...h,...u}}var We={en:{action_running:"Running ",api_key_missing:"Missing",api_key_set:"Entered",btn_install:"Open Setup Wizard",btn_install_desc:"Check whether the environment is ready, then open the step-by-step setup wizard",btn_reconfig:"Reconfigure",btn_reconfig_desc:"Open the setup wizard again to change directories, platform, or API keys",btn_validate:"Validate",check_bbt_fail:"Not detected",check_bbt_ok:"Installed",check_python_fail:"Not found",check_python_ok:"Ready",check_zotero_fail:"Not detected",check_zotero_ok:"Found",complete_export_path:"Save Better BibTeX JSON exports into:",complete_next:"Recommended next steps",complete_step1:"Open Dashboard",complete_step1_desc:'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.',complete_step2:"Sync Literature",complete_step2_desc:"In the main panel, click Sync Library to bring papers from Zotero into Obsidian and generate notes.",complete_step3:"Run OCR",complete_step3_desc:"In the Obsidian Base view, mark do_ocr:true on papers, then run OCR in the main panel.",complete_step4:"Configure Better BibTeX Auto-export",complete_step4_desc:'In Zotero, right-click the library or collection you want to sync -> Export -> Better BibTeX JSON -> enable "Keep updated".',complete_summary:"Saved Configuration",complete_title:"Setup Complete",copied:"Copied!",copy_pf_deep_cmd:"Copy /pf-deep Command",dashboard_drift_warning:"PaperForge CLI (v{0}) differs from plugin (v{1}). Open Settings \u2192 Runtime Health to sync.",deep_reading_not_found:"Deep reading file not found",desc:"Obsidian + Zotero literature pipeline. Sync papers, generate notes, run OCR, and read deeply in one place.",dir_base:"Base Dir",dir_index:"Index Dir",dir_notes:"Notes Dir",dir_resources:"Resource Dir",dir_system:"System Dir",dir_vault:"Vault Path",error_copied:"Copied!",error_copy_diagnostic:"Copy diagnostic",feat_agent_platform:"Agent Platform",feat_agent_platform_desc:"Select which agent platform to manage skills for.",feat_api_base_url:"API Base URL",feat_api_base_url_desc:"Custom OpenAI-compatible API endpoint. Leave empty for default.",feat_api_model:"API Model",feat_api_model_desc:"Embedding model name for this endpoint.",feat_build_btn:"Build",feat_build_complete:"Vector build complete.",feat_build_failed:"Build failed. See terminal output.",feat_building:"Building...",feat_cache_remove_failed:"Failed: {0}",feat_cache_removed:"Model cache removed.",feat_checking:"Checking...",feat_checking_btn:"Checking...",feat_deps_checking:"Checking dependencies...",feat_deps_missing:"Dependencies not installed. Required: chromadb, openai.",feat_enter_key:"Enter a valid OpenAI API key.",feat_install_btn:"Install",feat_install_deps:"Install Dependencies",feat_install_deps_desc:"pip install chromadb openai (~35MB).",feat_install_done:"Dependencies installed. Building vectors...",feat_install_failed:"Install failed: ",feat_installing:"Installing...",feat_installing_pkgs:"Installing {pkgs}...",feat_key_rejected:"API key rejected.",feat_memory_desc:"The Memory Layer is the core data engine of PaperForge, powered by SQLite. It integrates literature metadata (papers, assets, aliases, reading events), provides FTS5 metadata search across titles, abstracts, authors, domains, and collections, and powers agent-context and paper-status. Always active \u2014 no toggle needed.",feat_memory_rebuild_btn:"Rebuild",feat_memory_rebuild_done:"Memory DB rebuilt.",feat_memory_rebuild_failed:"Rebuild failed.",feat_memory_rebuilding:"Rebuilding...",feat_model_changed_warn:"Model changed ({0} -> {1}). Existing vectors are incompatible \u2014 rebuild required.",feat_network_error:"Network error: ",feat_no_python:"No Python found. Check Installation tab.",feat_not_cached:"Not cached",feat_openai_key:"OpenAI API Key",feat_openai_key_desc:"Used for API embedding calls. Model is defined below.",feat_output_copied:"Output copied to clipboard.",feat_rebuild_btn:"Rebuild",feat_rebuild_vectors:"Rebuild Vectors",feat_rebuild_vectors_changed:"Model changed \u2014 rebuild to update all vectors.",feat_rebuild_vectors_desc:"Rebuild all OCR fulltext vectors. Required after model or mode change.",feat_removing:"Removing...",feat_retry_btn:"Retry",feat_skills_desc:"Manage and enable/disable agent skills installed in your vault. Each row corresponds to a SKILL.md file \u2014 toggle off to prevent the agent from auto-invoking that skill.",feat_skills_system:"System Skills ship with PaperForge and are updated alongside PaperForge.",feat_skills_user:"User Skills are custom skills you install from community or create yourself.",feat_uninstall_btn:"Uninstall",feat_valid_key:"API key valid.",feat_vector_config_label:"Vector Settings",feat_vector_corrupted:"Vector index corrupted \u2014 needs force rebuild.",feat_vector_desc:"Vector Database enables semantic search across OCR-extracted fulltext via API embedding. Documents are split into chunks, embedded via OpenAI-compatible API, and stored in ChromaDB.",feat_vector_enable:"Enable Vector Retrieval",feat_vector_enable_desc:"Semantic search across OCR fulltext. Requires: pip install openai chromadb (~35MB).",feat_vector_rebuild_force_btn:"Force Rebuild",feat_verify:"Verify",feat_verify_btn:"Verify",field_paddleocr:"PaddleOCR API Key",field_python_custom:"Custom Path",field_python_interp:"Python Interpreter",field_zotero_data:"Zotero Data Dir",field_zotero_placeholder:"Required. Path to Zotero data directory for PDF attachment resolution.",guide_ocr:"Run OCR",guide_ocr_desc:"In the main panel, click Run OCR to extract full text and figures from PDFs for later reading and analysis.",guide_open:"Open Main Panel",guide_open_desc:'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.',guide_sync:"Sync Literature",guide_sync_desc:"After Better BibTeX JSON export is configured, click Sync Library to import papers from Zotero into Obsidian and generate notes automatically.",header_title:"PaperForge",install_bootstrapping:"PaperForge Python package not found. Installing automatically...",install_btn:"Start Install",install_btn_retry:"Retry",install_btn_running:"Installing...",install_complete:"Installation complete!",install_failed:"Installation failed: ",install_validating:"Validating setup...",jump_to_deep_reading:"Open Deep Reading",label_agent:"Agent Platform",nav_close:"Close",nav_next:"Next",nav_prev:"Back",not_set:"Not entered",notice_check_fail:"Missing: ",notice_python_missing:"Python was not detected. Install Python 3.10+ and add it to PATH.",ocr_privacy_title:"OCR Privacy Notice",ocr_privacy_warning:"OCR will upload PDFs to the PaddleOCR API. Do not upload sensitive or confidential documents.",ocr_queue_add:"Add to OCR Queue",ocr_queue_added:"Added to OCR queue",ocr_queue_remove:"Remove from OCR Queue",ocr_queue_removed:"Removed from OCR queue",ocr_understand:"I understand, continue",optional_later:"(can be set later in Settings)",orphan_delete_failed:"Prune failed",orphan_delete_selected:"Delete {count} selected",orphan_deleted:"Deleted {count} orphan workspace(s)",orphan_desc:"These papers are no longer in your Zotero library.",orphan_deselect_all:"Deselect all",orphan_explain:"Removed from Zotero. Workspace files remain on disk.",orphan_keep_all:"Keep all",orphan_none_selected:"No papers selected for deletion",orphan_select_all:"Select all",orphan_title:"Found {count} orphan paper(s)",panel_actions:"Quick Actions",prep_bbt:"Better BibTeX",prep_bbt_desc:"In Zotero: Tools -> Add-ons -> install Better BibTeX.",prep_export:"Better BibTeX Auto-export",prep_export_desc:'In Zotero, right-click the collection you want to sync -> Export Collection -> BetterBibTeX JSON -> enable "Keep updated" -> save the JSON file into the exports folder shown below. Obsidian Base views will use the JSON filename as the Base name:',prep_export_path_label:"Save the exported JSON file into this folder:",prep_key:"PaddleOCR Key",prep_key_desc:"Get your API key from https://aistudio.baidu.com/paddleocr",prep_python:"Python 3.10+",prep_python_desc:"Python must be available from the command line. If you are not sure, click below to auto-detect.",prep_zotero:"Zotero Desktop",prep_zotero_desc:"Install Zotero from https://www.zotero.org",run_in_agent:"Run in {0}",runtime_health:"Runtime Health",runtime_health_checking:"Checking...",runtime_health_desc:"Check whether the installed paperforge Python package matches the plugin version and whether the deployed skill contract is current.",runtime_health_match:"Match",runtime_health_mismatch:"Mismatch",runtime_health_package_ver:"Python package v{0}",runtime_health_plugin_ver:"Plugin v{0}",runtime_health_sync:"Sync Runtime",runtime_health_sync_done:"Runtime synced to v{0}",runtime_health_sync_fail:"Sync failed: {0}",runtime_health_syncing:"Syncing...",section_config:"Current Configuration",section_guide:"How To Use",section_prep:"Preparation",section_prep_desc:"Before first use, finish these 4 preparation items. Better BibTeX auto-export is configured after setup:",setup_done:"PaperForge environment is ready",setup_pending:"Not installed yet. Finish the preparation items below, then open the wizard.",tab_features:"Features",tab_setup:"Installation",tab_maintenance:"Maintenance",validate_base:"Base directory is required",validate_fail:"Please complete the required fields below",validate_index:"Index directory is required",validate_key:"PaddleOCR API key (optional, needed for OCR)",validate_notes:"Notes directory is required",validate_resources:"Resources directory is required",validate_system:"System directory is required",validate_vault:"Vault path is required",validate_zotero:"Zotero data directory (optional, needed for PDF linking)",wizard_agent_hint:"Choose the AI agent platform you use most often. PaperForge will place the matching command and skill files in the correct location.",wizard_dir_hint:"PaperForge stores user-facing literature data under the resources directory. These folders will live there:",wizard_dir_sub_hint:"Resolved folder preview based on the names below:",wizard_intro:"This wizard walks you through the full setup. In most cases, the default values are fine to keep.",wizard_keys_hint:"Enter your PaddleOCR API key below. If you want PaperForge to auto-locate Zotero PDFs, you can also fill in the Zotero data directory.",wizard_preview:"After installation, system files stay at the vault root while literature data stays under the resources directory.",wizard_safety:"Safety: if the selected folders already contain files, setup preserves existing files and only creates missing PaperForge folders and files.",wizard_step1:"Overview",wizard_step2:"Directory Setup",wizard_step3:"Platform & Keys",wizard_step4:"Install",wizard_step5:"Done",wizard_skip_ocr_desc:"OCR will not be available until you configure a valid PaddleOCR API key. You can continue setup now and configure it later in Settings.",wizard_skip_ocr_continue:"Continue without OCR key",wizard_skip_ocr_back:"Back to configure",wizard_api_hint_skip:"OCR key is optional \u2014 you may skip it and configure later.",wizard_sys_hint:"These folders live at the vault root, outside the resources directory:",wizard_title:"PaperForge Setup Wizard",ocr_maint_no_action:"No Action Needed",ocr_maint_rebuild:"Rebuild Recommended",ocr_maint_failed:"OCR Failed",ocr_maint_limited:"Result Limited",ocr_maint_needs_attention:"Needs Attention",ocr_maint_limitations:"Result Limitations",ocr_maint_hero_ok:"OCR looks usable overall.",ocr_maint_hero_warn:"OCR needs attention: {rebuild} rebuild recommended, {failed} failed.",ocr_maint_hero_note:"This page only promotes issues where maintenance is likely to help. Some papers may have limitations that maintenance will not improve.",ocr_maint_limitations_intro:"These papers look less certain, but PaperForge does not currently have a high-confidence maintenance action to recommend.",ocr_maint_all_papers:"All Papers",ocr_maint_rebuild_btn:"Rebuild results",ocr_maint_redo_btn:"Rerun OCR",maintenance_group_retry:"Needs Retry",maintenance_group_rebuild:"Can Rebuild",maintenance_group_legacy:"Upgrade Available (Optional)",maintenance_btn_retry:"Retry",maintenance_btn_rebuild:"Rebuild",maintenance_btn_upgrade:"Upgrade",maintenance_refresh_spinning:"Updating\u2026",maintenance_all_good:"\u2705 All good \u2014 no action needed",maintenance_n_pending:"{n} need attention",version_panel_title:"Version History",version_panel_back:"Back",version_filter_placeholder:"Filter papers...",version_papers_count:"{n} papers",version_current:"current",version_restore_btn:"Restore",version_compare_btn:"Compare",version_restore_selected:"Restore selected",version_clear_old:"Clear old versions (free {size})",version_no_backups:"No version history available",version_restore_confirm:"Restore {label} for {paper}?",version_restore_done:"Restored {label}",version_compare_title:"{vA} vs {vB}",version_compare_paragraphs:"{n} paragraphs changed",version_error_read:"Cannot read version data"},zh:{action_running:"\u6B63\u5728\u6267\u884C ",api_key_missing:"\u672A\u914D\u7F6E \u2717",api_key_set:"\u5DF2\u914D\u7F6E \u2713",btn_install:"\u6253\u5F00\u5B89\u88C5\u5411\u5BFC",btn_install_desc:"\u81EA\u52A8\u68C0\u6D4B Python + \u524D\u7F6E\u73AF\u5883\uFF0C\u901A\u8FC7\u540E\u6253\u5F00\u5206\u6B65\u5B89\u88C5\u5411\u5BFC",btn_reconfig:"\u91CD\u65B0\u914D\u7F6E",btn_reconfig_desc:"\u91CD\u65B0\u8FD0\u884C\u5B89\u88C5\u5411\u5BFC\uFF0C\u4FEE\u6539\u76EE\u5F55\u6216\u5BC6\u94A5\u914D\u7F6E",btn_validate:"\u9A8C\u8BC1",check_bbt_fail:"\u672A\u68C0\u6D4B\u5230",check_bbt_ok:"\u5DF2\u5B89\u88C5",check_python_fail:"\u672A\u5B89\u88C5",check_python_ok:"\u5DF2\u5C31\u7EEA",check_zotero_fail:"\u672A\u68C0\u6D4B\u5230",check_zotero_ok:"\u5DF2\u5B89\u88C5",complete_next:"\u4E0B\u4E00\u6B65\u64CD\u4F5C",complete_step1:"\u6253\u5F00 PaperForge Dashboard",complete_step1_desc:"Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807",complete_step2:"\u540C\u6B65\u6587\u732E",complete_step2_desc:"Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0",complete_step3:"\u8FD0\u884C OCR",complete_step3_desc:"Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868",complete_step4:"\u914D\u7F6E BBT \u81EA\u52A8\u5BFC\u51FA",complete_summary:"\u5F53\u524D\u5B8C\u6574\u914D\u7F6E",complete_title:"\u2713 PaperForge \u5B89\u88C5\u5B8C\u6210",copied:"\u5DF2\u590D\u5236\uFF01",copy_pf_deep_cmd:"\u590D\u5236 /pf-deep \u547D\u4EE4",dashboard_drift_warning:'\u63D2\u4EF6\u7248\u672C\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u4E0D\u5339\u914D\u3002\u8BF7\u5728\u8BBE\u7F6E\u4E2D\u70B9\u51FB"\u540C\u6B65\u8FD0\u884C\u65F6"\u3002',deep_reading_not_found:"\u7CBE\u8BFB\u6587\u4EF6\u672A\u627E\u5230",desc:"Obsidian + Zotero \u6587\u732E\u7BA1\u7406\u6D41\u6C34\u7EBF\u3002\u81EA\u52A8\u540C\u6B65\u6587\u732E\u3001\u751F\u6210\u7B14\u8BB0\u3001OCR \u63D0\u53D6\u5168\u6587\uFF0C\u4E00\u7AD9\u5F0F\u6587\u732E\u7CBE\u8BFB\u5DE5\u4F5C\u6D41\u3002",dir_base:"Base \u76EE\u5F55",dir_index:"\u7D22\u5F15\u76EE\u5F55",dir_notes:"\u6B63\u6587\u76EE\u5F55",dir_resources:"\u8D44\u6E90\u76EE\u5F55",dir_system:"\u7CFB\u7EDF\u76EE\u5F55",dir_vault:"Vault \u8DEF\u5F84",error_copied:"\u5DF2\u590D\u5236\uFF01",error_copy_diagnostic:"\u590D\u5236\u8BCA\u65AD\u4FE1\u606F",feat_agent_platform:"Agent \u5E73\u53F0",feat_agent_platform_desc:"\u9009\u62E9\u8981\u7BA1\u7406\u7684 Agent \u5E73\u53F0\u3002",feat_api_base_url:"API \u5730\u5740",feat_api_base_url_desc:"\u81EA\u5B9A\u4E49 OpenAI \u517C\u5BB9 API \u7AEF\u70B9\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u5730\u5740\u3002",feat_api_model:"API \u6A21\u578B",feat_api_model_desc:"\u8BE5\u7AEF\u70B9\u4F7F\u7528\u7684\u5D4C\u5165\u6A21\u578B\u540D\u79F0\u3002",feat_build_btn:"\u6784\u5EFA",feat_build_complete:"\u5411\u91CF\u6784\u5EFA\u5B8C\u6210\u3002",feat_build_failed:"\u6784\u5EFA\u5931\u8D25\u3002\u8BF7\u67E5\u770B\u7EC8\u7AEF\u8F93\u51FA\u3002",feat_building:"\u6784\u5EFA\u4E2D\u2026",feat_cache_remove_failed:"\u5931\u8D25\uFF1A{0}",feat_cache_removed:"\u6A21\u578B\u7F13\u5B58\u5DF2\u6E05\u9664\u3002",feat_checking:"\u68C0\u6D4B\u4E2D\u2026",feat_checking_btn:"\u68C0\u6D4B\u4E2D\u2026",feat_deps_checking:"\u6B63\u5728\u68C0\u6D4B\u4F9D\u8D56\u2026",feat_deps_missing:"\u4F9D\u8D56\u672A\u5B89\u88C5\u3002\u9700\u8981\uFF1Achromadb, openai\u3002",feat_enter_key:"\u8BF7\u8F93\u5165\u6709\u6548\u7684 OpenAI API Key\u3002",feat_install_btn:"\u5B89\u88C5",feat_install_deps:"\u5B89\u88C5\u4F9D\u8D56",feat_install_done:"\u4F9D\u8D56\u5DF2\u5B89\u88C5\u3002\u6B63\u5728\u6784\u5EFA\u5411\u91CF\u2026",feat_install_failed:"\u5B89\u88C5\u5931\u8D25\uFF1A",feat_installing:"\u5B89\u88C5\u4E2D\u2026",feat_installing_pkgs:"\u6B63\u5728\u5B89\u88C5 {pkgs}...",feat_key_rejected:"API Key \u88AB\u62D2\u7EDD\u3002",feat_memory_desc:"\u8BB0\u5FC6\u5C42\u662F PaperForge \u7684\u6838\u5FC3\u6570\u636E\u5F15\u64CE\uFF0C\u57FA\u4E8E SQLite \u6784\u5EFA\u3002\u5B83\u6574\u5408\u4E86\u6587\u732E\u5143\u6570\u636E\uFF08\u8BBA\u6587\u3001\u8D44\u6E90\u6587\u4EF6\u3001\u522B\u540D\u3001\u9605\u8BFB\u4E8B\u4EF6\uFF09\uFF0C\u652F\u6301 FTS5 \u5143\u6570\u636E\u68C0\u7D22\uFF08\u6807\u9898\u3001\u6458\u8981\u3001\u4F5C\u8005\u3001domain\u3001collection\uFF09\uFF0C\u5E76\u4E3A agent-context \u548C paper-status \u547D\u4EE4\u63D0\u4F9B\u6570\u636E\u652F\u6491\u3002\u59CB\u7EC8\u8FD0\u884C\uFF0C\u65E0\u9700\u624B\u52A8\u5F00\u542F\u3002",feat_memory_rebuild_btn:"\u91CD\u5EFA\u6570\u636E\u5E93",feat_memory_rebuild_done:"\u8BB0\u5FC6\u6570\u636E\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002",feat_memory_rebuild_failed:"\u91CD\u5EFA\u5931\u8D25\u3002",feat_memory_rebuilding:"\u91CD\u5EFA\u4E2D\u2026",feat_model:"\u6A21\u578B",feat_model_changed_warn:"\u6A21\u578B\u5DF2\u66F4\u6362\uFF08{0} -> {1}\uFF09\u3002\u5DF2\u6709\u5411\u91CF\u4E0D\u517C\u5BB9\u2014\u2014\u9700\u8981\u91CD\u5EFA\u3002",feat_network_error:"\u7F51\u7EDC\u9519\u8BEF\uFF1A",feat_no_python:"\u672A\u627E\u5230 Python\u3002\u8BF7\u67E5\u770B\u5B89\u88C5\u6807\u7B7E\u9875\u3002",feat_not_cached:"\u672A\u7F13\u5B58",feat_openai_key:"OpenAI API Key",feat_openai_key_desc:"\u7528\u4E8E API \u5D4C\u5165\u8C03\u7528\uFF0C\u6A21\u578B\u5728\u4E0B\u65B9\u5B9A\u4E49\u3002",feat_output_copied:"\u8F93\u51FA\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\u3002",feat_rebuild_btn:"\u91CD\u5EFA",feat_rebuild_vectors:"\u91CD\u5EFA\u5411\u91CF",feat_rebuild_vectors_changed:"\u6A21\u578B\u5DF2\u66F4\u6362 \u2014 \u9700\u8981\u91CD\u5EFA\u5411\u91CF\u3002",feat_rebuild_vectors_desc:"\u91CD\u5EFA\u6240\u6709 OCR \u5168\u6587\u5411\u91CF\u3002\u66F4\u6362\u6A21\u578B\u6216\u6A21\u5F0F\u540E\u9700\u8981\u91CD\u5EFA\u3002",feat_removing:"\u5220\u9664\u4E2D\u2026",feat_retry_btn:"\u91CD\u8BD5",feat_skills_desc:"\u7BA1\u7406 Vault \u4E2D\u5DF2\u5B89\u88C5\u7684 Agent \u6280\u80FD\u3002\u6BCF\u884C\u5BF9\u5E94\u4E00\u4E2A SKILL.md \u6587\u4EF6\uFF0C\u5173\u95ED\u5F00\u5173\u53EF\u963B\u6B62 Agent \u81EA\u52A8\u8C03\u7528\u8BE5\u6280\u80FD\u3002",feat_skills_system:"\u7CFB\u7EDF\u6280\u80FD\u968F PaperForge \u4E00\u540C\u53D1\u5E03\uFF0C\u4F1A\u8DDF\u968F PaperForge \u7248\u672C\u66F4\u65B0\u3002",feat_skills_user:"\u7528\u6237\u6280\u80FD\u662F\u4F60\u81EA\u884C\u5B89\u88C5\u6216\u521B\u5EFA\u7684\u81EA\u5B9A\u4E49\u6280\u80FD\u3002",feat_uninstall_btn:"\u5378\u8F7D",feat_valid_key:"API Key \u6709\u6548\u3002",feat_vector_config_label:"\u5411\u91CF\u5E93\u914D\u7F6E",feat_vector_corrupted:"\u5411\u91CF\u7D22\u5F15\u5DF2\u635F\u574F \u2014 \u9700\u8981\u5F3A\u5236\u91CD\u5EFA\u3002",feat_vector_desc:"\u5411\u91CF\u6570\u636E\u5E93\u901A\u8FC7\u5D4C\u5165\u6A21\u578B\u5B9E\u73B0 OCR \u5168\u6587\u7684\u8BED\u4E49\u641C\u7D22\u3002\u6587\u6863\u88AB\u5207\u5206\u4E3A\u6587\u672C\u5757\uFF08chunk\uFF09\uFF0C\u7F16\u7801\u4E3A\u5411\u91CF\u5B58\u5165 ChromaDB\u3002\u652F\u6301\u672C\u5730\u6A21\u578B\uFF08\u514D\u8D39\uFF0CCPU \u8FD0\u884C\uFF09\u6216 OpenAI API\uFF08\u4ED8\u8D39\uFF0C\u66F4\u5FEB\u901F\uFF09\u3002",feat_vector_enable:"\u542F\u7528\u5411\u91CF\u68C0\u7D22",feat_vector_enable_desc:"\u5BF9 OCR \u5168\u6587\u8FDB\u884C\u8BED\u4E49\u641C\u7D22\u3002\u9700\u5B89\u88C5: pip install chromadb sentence-transformers openai (~500MB)\u3002",feat_vector_rebuild_force_btn:"\u5F3A\u5236\u91CD\u5EFA",feat_verify:"\u9A8C\u8BC1",feat_verify_btn:"\u9A8C\u8BC1",field_paddleocr:"PaddleOCR API \u5BC6\u94A5",field_python_custom:"\u81EA\u5B9A\u4E49 Python \u8DEF\u5F84",field_python_interp:"\u5F53\u524D Python \u89E3\u91CA\u5668",field_zotero_data:"Zotero \u6570\u636E\u76EE\u5F55",field_zotero_placeholder:"\u53EF\u9009\uFF0C\u7528\u4E8E\u81EA\u52A8\u68C0\u6D4B PDF",guide_ocr:"\u8FD0\u884C OCR",guide_ocr_desc:"Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868",guide_open:"\u6253\u5F00 Dashboard",guide_open_desc:"Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807",guide_sync:"\u540C\u6B65\u6587\u732E",guide_sync_desc:"Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0",header_title:"PaperForge",install_bootstrapping:"\u672A\u68C0\u6D4B\u5230 PaperForge Python \u5305\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5\u2026",install_btn:"\u5F00\u59CB\u5B89\u88C5",install_btn_retry:"\u91CD\u8BD5",install_btn_running:"\u6B63\u5728\u5B89\u88C5...",install_complete:"\u2713 \u5B89\u88C5\u5B8C\u6210\uFF01",install_failed:"\u2717 \u5B89\u88C5\u5931\u8D25\uFF1A",install_validating:"\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u73AF\u5883\u2026",jump_to_deep_reading:"\u8DF3\u8F6C\u5230\u7CBE\u8BFB",label_agent:"Agent \u5E73\u53F0",nav_close:"\u5173\u95ED",nav_next:"\u4E0B\u4E00\u6B65 \u2192",nav_prev:"\u2190 \u4E0A\u4E00\u6B65",no_pending_ocr:"\u6240\u6709 OCR \u4EFB\u52A1\u5DF2\u5B8C\u6210",not_set:"\u672A\u8BBE\u7F6E",notice_check_fail:"\u672A\u901A\u8FC7: ",notice_python_missing:"Python \u672A\u68C0\u6D4B\u5230\uFF0C\u8BF7\u5148\u5B89\u88C5 Python 3.10+ \u5E76\u52A0\u5165 PATH",ocr_privacy_title:"OCR \u9690\u79C1\u63D0\u793A",ocr_privacy_warning:"OCR \u4F1A\u5C06 PDF \u4E0A\u4F20\u5230 PaddleOCR API \u8FDB\u884C\u5904\u7406\u3002\u8BF7\u4E0D\u8981\u4E0A\u4F20\u5305\u542B\u654F\u611F\u4FE1\u606F\u6216\u65E0\u6CD5\u5916\u4F20\u7684\u6587\u732E\u3002",ocr_queue_add:"\u52A0\u5165 OCR \u961F\u5217",ocr_queue_added:"\u5DF2\u52A0\u5165 OCR \u961F\u5217",ocr_queue_remove:"\u79FB\u51FA OCR \u961F\u5217",ocr_queue_removed:"\u5DF2\u79FB\u51FA OCR \u961F\u5217",ocr_understand:"\u6211\u4E86\u89E3\uFF0C\u7EE7\u7EED",optional_later:"\uFF08\u7A0D\u540E\u53EF\u5728\u8BBE\u7F6E\u4E2D\u8865\u5145\uFF09",orphan_delete_failed:"\u6E05\u7406\u5931\u8D25",orphan_delete_selected:"\u5220\u9664 {count} \u7BC7",orphan_deleted:"\u5DF2\u5220\u9664 {count} \u7BC7\u6B8B\u7559\u6587\u732E",orphan_desc:"\u8FD9\u4E9B\u6587\u732E\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002",orphan_deselect_all:"\u53D6\u6D88\u5168\u9009",orphan_explain:"\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002\u5DE5\u4F5C\u533A\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u78C1\u76D8\u4E0A\u3002",orphan_keep_all:"\u4FDD\u7559\u5168\u90E8",orphan_none_selected:"\u672A\u9009\u62E9\u4EFB\u4F55\u6587\u732E",orphan_select_all:"\u5168\u9009",orphan_title:"\u53D1\u73B0 {count} \u7BC7\u6B8B\u7559\u6587\u732E",panel_actions:"\u5FEB\u6377\u64CD\u4F5C",prep_bbt:"Better BibTeX",prep_bbt_desc:"Zotero \u2192 \u5DE5\u5177 \u2192 \u63D2\u4EF6 \u2192 \u5B89\u88C5 Better BibTeX",prep_export:"BBT \u81EA\u52A8\u5BFC\u51FA",prep_export_desc:"\u53F3\u952E\u6587\u732E\u5B50\u5206\u7C7B \u2192 \u5BFC\u51FA\u5206\u7C7B \u2192 BetterBibTeX JSON \u2192 \u52FE\u9009\u4FDD\u6301\u66F4\u65B0 \u2192 \u5BFC\u51FA\u5230\uFF08JSON \u6587\u4EF6\u540D\u5373\u4E3A Base \u540D\uFF09\uFF1A",prep_key:"PaddleOCR Key",prep_key_desc:"\u5728 https://aistudio.baidu.com/paddleocr \u83B7\u53D6 API Key",prep_python:"Python 3.10+",prep_python_desc:"\u786E\u4FDD Python \u53EF\u547D\u4EE4\u884C\u8C03\u7528\u3002\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u81EA\u52A8\u68C0\u6D4B\u3002",prep_zotero:"Zotero \u684C\u9762\u7248",prep_zotero_desc:"\u5B89\u88C5 Zotero (https://www.zotero.org)",run_in_agent:"\u5728 {0} \u4E2D\u8FD0\u884C",runtime_health:"\u8FD0\u884C\u65F6\u72B6\u6001",runtime_health_checking:"\u6B63\u5728\u68C0\u6D4B\u2026",runtime_health_desc:"\u68C0\u67E5\u63D2\u4EF6\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u7684\u5339\u914D\u60C5\u51B5\uFF0C\u5E76\u786E\u8BA4\u5DF2\u90E8\u7F72\u7684 skill contract \u662F\u5426\u4E3A\u5F53\u524D\u7248\u672C\u3002",runtime_health_match:"\u5339\u914D",runtime_health_mismatch:"\u4E0D\u5339\u914D",runtime_health_package_ver:"Python \u5305 v{0}",runtime_health_plugin_ver:"\u63D2\u4EF6 v{0}",runtime_health_sync:"\u540C\u6B65\u8FD0\u884C\u65F6",runtime_health_sync_done:"\u8FD0\u884C\u65F6\u5DF2\u540C\u6B65\u81F3 v{0}",runtime_health_sync_fail:"\u8FD0\u884C\u65F6\u540C\u6B65\u5931\u8D25\uFF1A{0}",runtime_health_syncing:"\u6B63\u5728\u540C\u6B65\u2026",section_config:"\u5F53\u524D\u914D\u7F6E",section_guide:"\u64CD\u4F5C\u65B9\u5F0F",section_prep:"\u5B89\u88C5\u51C6\u5907",section_prep_desc:"\u9996\u6B21\u4F7F\u7528\u524D\uFF0C\u8BF7\u4F9D\u6B21\u5B8C\u6210\u4EE5\u4E0B\u51C6\u5907\uFF1A",setup_done:"\u2713 PaperForge \u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u6210",setup_pending:"\u5C1A\u672A\u5B89\u88C5\uFF0C\u5B8C\u6210\u5B89\u88C5\u51C6\u5907\u540E\u70B9\u51FB\u5B89\u88C5\u5411\u5BFC",tab_features:"\u529F\u80FD",tab_setup:"\u5B89\u88C5",tab_maintenance:"\u7EF4\u62A4",validate_base:"Base \u76EE\u5F55\u672A\u586B\u5199",validate_fail:"\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25",validate_index:"\u7D22\u5F15\u76EE\u5F55\u672A\u586B\u5199",validate_key:"PaddleOCR API \u5BC6\u94A5\u672A\u586B\u5199",validate_notes:"\u6B63\u6587\u76EE\u5F55\u672A\u586B\u5199",validate_resources:"\u8D44\u6E90\u76EE\u5F55\u672A\u586B\u5199",validate_system:"\u7CFB\u7EDF\u76EE\u5F55\u672A\u586B\u5199",validate_vault:"Vault \u8DEF\u5F84\u672A\u586B\u5199",validate_zotero:"Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879",wizard_agent_hint:"\u9009\u62E9\u4F60\u4F7F\u7528\u7684 AI Agent \u5E73\u53F0\uFF0C\u5B89\u88C5\u65F6\u5C06\u6309\u5BF9\u5E94\u683C\u5F0F\u90E8\u7F72\u6280\u80FD\u6587\u4EF6\uFF1A",wizard_dir_hint:"\u8D44\u6E90\u76EE\u5F55\u662F\u6587\u732E\u6570\u636E\u7684\u7EDF\u4E00\u6839\u76EE\u5F55\uFF0C\u4EE5\u4E0B\u5B50\u76EE\u5F55\u5C06\u521B\u5EFA\u5728\u5176\u5185\u90E8\uFF1A",wizard_dir_sub_hint:"\u8D44\u6E90\u76EE\u5F55\u5185\u7684\u4E24\u4E2A\u5B50\u76EE\u5F55\uFF1A",wizard_intro:"\u672C\u5411\u5BFC\u5C06\u5F15\u5BFC\u60A8\u5B8C\u6210 PaperForge \u73AF\u5883\u7684\u5B8C\u6574\u914D\u7F6E\u3002\u5B89\u88C5\u8FC7\u7A0B\u4F1A\u81EA\u52A8\u521B\u5EFA\u6240\u6709\u76EE\u5F55\u7ED3\u6784\uFF0C\u65E0\u9700\u624B\u52A8\u64CD\u4F5C\u3002",wizard_keys_hint:"\u4EE5\u4E0B\u4E3A API \u5BC6\u94A5\u4E0E Zotero \u914D\u7F6E\uFF1A",wizard_preview:"\u7CFB\u7EDF\u6587\u4EF6\u548C Agent \u914D\u7F6E\u4F4D\u4E8E Vault \u6839\u76EE\u5F55\u4E0B\u3002\u6587\u732E\u6570\u636E\uFF08\u6B63\u6587\u3001\u7D22\u5F15\uFF09\u7EDF\u4E00\u5B58\u653E\u5728\u8D44\u6E90\u76EE\u5F55\u5185\u3002\u5B89\u88C5\u540E\u4ECD\u53EF\u5728\u8BBE\u7F6E\u4E2D\u4FEE\u6539\u3002",wizard_safety:"\u5B89\u5168\u8BF4\u660E\uFF1A\u5982\u679C\u4F60\u9009\u62E9\u7684\u76EE\u5F55\u91CC\u5DF2\u7ECF\u6709\u6587\u4EF6\uFF0C\u5B89\u88C5\u5411\u5BFC\u4F1A\u4FDD\u7559\u5DF2\u6709\u5185\u5BB9\uFF0C\u53EA\u8865\u5145\u7F3A\u5931\u7684 PaperForge \u6587\u4EF6\u548C\u76EE\u5F55\u3002",wizard_step1:"\u6982\u89C8",wizard_step2:"\u76EE\u5F55",wizard_step3:"Agent",wizard_step4:"\u5B89\u88C5",wizard_step5:"\u5B8C\u6210",wizard_skip_ocr_desc:"OCR \u529F\u80FD\u5728\u914D\u7F6E\u6709\u6548\u7684 PaddleOCR API \u5BC6\u94A5\u4E4B\u524D\u4E0D\u53EF\u7528\u3002\u60A8\u53EF\u4EE5\u7EE7\u7EED\u5B8C\u6210\u8BBE\u7F6E\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002",wizard_skip_ocr_continue:"\u7EE7\u7EED\uFF0C\u7A0D\u540E\u914D\u7F6E\u5BC6\u94A5",wizard_skip_ocr_back:"\u8FD4\u56DE\u914D\u7F6E",wizard_api_hint_skip:"OCR \u5BC6\u94A5\u4E3A\u9009\u586B\u9879 \u2014 \u53EF\u8DF3\u8FC7\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002",wizard_sys_hint:"\u72EC\u7ACB\u4E8E\u8D44\u6E90\u76EE\u5F55\u7684\u7CFB\u7EDF\u6587\u4EF6\uFF1A",wizard_title:"PaperForge \u5B89\u88C5\u5411\u5BFC",ocr_maint_no_action:"\u65E0\u9700\u5904\u7406",ocr_maint_rebuild:"\u5EFA\u8BAE\u91CD\u5EFA",ocr_maint_failed:"OCR \u5931\u8D25",ocr_maint_limited:"\u7ED3\u679C\u4E00\u822C",ocr_maint_needs_attention:"\u9700\u8981\u5904\u7406",ocr_maint_limitations:"\u7ED3\u679C\u8BF4\u660E",ocr_maint_hero_ok:"OCR \u6574\u4F53\u6B63\u5E38\u3002",ocr_maint_hero_warn:"OCR \u9700\u8981\u5173\u6CE8\uFF1A{rebuild} \u7BC7\u5EFA\u8BAE\u91CD\u5EFA\uFF0C{failed} \u7BC7\u5904\u7406\u5931\u8D25\u3002",ocr_maint_hero_note:"\u672C\u9875\u53EA\u63D0\u793A\u7EF4\u62A4\u540E\u5927\u6982\u7387\u4F1A\u6539\u5584\u7684\u95EE\u9898\u3002\u90E8\u5206\u8BBA\u6587\u6548\u679C\u4E00\u822C\uFF0C\u7EF4\u62A4\u672A\u5FC5\u80FD\u6539\u5584\u3002",ocr_maint_limitations_intro:"\u8FD9\u7C7B\u8BBA\u6587\u901A\u5E38\u8868\u793A\u7248\u5F0F\u590D\u6742\u6216\u4FE1\u53F7\u504F\u5F31\uFF0CPaperForge \u76EE\u524D\u6CA1\u6709\u9AD8\u7F6E\u4FE1\u5EA6\u7684\u7EF4\u62A4\u5EFA\u8BAE\u3002",ocr_maint_all_papers:"\u5168\u90E8\u8BBA\u6587",ocr_maint_rebuild_btn:"\u91CD\u5EFA\u7ED3\u679C",maintenance_group_retry:"\u9700\u8981\u91CD\u8BD5",maintenance_group_rebuild:"\u53EF\u91CD\u5EFA\u7ED3\u679C",maintenance_group_legacy:"\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09",maintenance_btn_retry:"\u91CD\u8BD5",maintenance_btn_rebuild:"\u91CD\u5EFA",maintenance_btn_upgrade:"\u5347\u7EA7",maintenance_refresh_spinning:"\u6B63\u5728\u66F4\u65B0\u2026",maintenance_all_good:"\u2705 \u5168\u90E8\u6B63\u5E38",maintenance_n_pending:"{n} \u7BC7\u9700\u8981\u5904\u7406",version_panel_title:"\u7248\u672C\u5386\u53F2",version_panel_back:"\u8FD4\u56DE",version_filter_placeholder:"\u641C\u7D22\u8BBA\u6587...",version_papers_count:"{n} \u7BC7\u8BBA\u6587",version_current:"\u5F53\u524D",version_restore_btn:"\u6062\u590D",version_compare_btn:"\u5BF9\u6BD4",version_restore_selected:"\u6062\u590D\u9009\u4E2D\u7248\u672C",version_clear_old:"\u6E05\u9664\u65E7\u7248\u672C (\u91CA\u653E {size})",version_no_backups:"\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5386\u53F2\u7248\u672C",version_restore_confirm:"\u786E\u8BA4\u5C06 {paper} \u6062\u590D\u5230 {label}\uFF1F",version_restore_done:"\u5DF2\u6062\u590D\u5230 {label}",version_compare_title:"{vA} vs {vB}",version_compare_paragraphs:"{n} \u6BB5\u6709\u53D8\u5316",version_error_read:"\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C\u6570\u636E"}},Ze=null;function It(h){try{let u=h.vault;if(typeof u.getConfig=="function"){let e=u.getConfig("language");if(e&&String(e).startsWith("zh"))return"zh"}}catch(u){}try{if(typeof localStorage!="undefined"){let u=localStorage.getItem("language");if(u&&String(u).startsWith("zh"))return"zh"}}catch(u){}return"en"}function at(h){Ze=It(h)==="zh"?We.zh:We.en}function o(h){return Ze&&Ze[h]||We.en[h]||h}var C=require("obsidian"),N=$(require("fs")),Z=$(require("path")),kt=$(require("os")),j=require("child_process");var wt=$(qe());var ne=$(require("fs")),se=$(require("path")),ot=$(require("os")),le=require("child_process"),Je=null,it=!1;function L(h,u,e,t){let r=e||ne,n=t||le.execFileSync;if(u&&u.python_path&&u.python_path.trim()){let l=u.python_path.trim();if(r.existsSync(l))return{path:l,source:"manual",extraArgs:[]}}let a=[se.join(h,".paperforge-test-venv","Scripts","python.exe"),se.join(h,".venv","Scripts","python.exe"),se.join(h,"venv","Scripts","python.exe")];for(let l of a)try{if(r.existsSync(l))return{path:l,source:"auto-detected",extraArgs:[]}}catch(i){}let s=[{path:"py",extraArgs:["-3"]},{path:"python",extraArgs:[]},{path:"python3",extraArgs:[]}];for(let l of s)try{let i=n(l.path,[...l.extraArgs,"--version"],{encoding:"utf-8",timeout:5e3,windowsHide:!0});if(i&&i.toLowerCase().includes("python"))return{path:l.path,source:"auto-detected",extraArgs:l.extraArgs}}catch(i){}return{path:"python",source:"auto-detected",extraArgs:[]}}function lt(h,u,e,t,r){t===void 0&&(t=1e4);let n=r||le.execFile;return new Promise(a=>{n(h,["-c","import paperforge; print(paperforge.__version__)"],{cwd:e,timeout:t},(s,l)=>{if(s){a({status:"not-installed",pyVersion:null,pluginVersion:u,error:s.message});return}let i=l&&l.trim()||null;a(i===u?{status:"match",pyVersion:i,pluginVersion:u,error:null}:{status:"mismatch",pyVersion:i,pluginVersion:u,error:null})})})}function ct(h,u,e){e===void 0&&(e=[]);let t=`paperforge==${u}`,r=`git+https://github.com/LLLin000/PaperForge.git@${u}`,n=[...e,"-m","pip","install","--upgrade",t],a=[...e,"-m","pip","install","--upgrade",r];return{cmd:h,url:r,args:a,pypiArgs:n,gitArgs:a,timeout:12e4}}function pt(h,u,e,t,r,n){let a=r||le.spawn;return new Promise(s=>{let l=Date.now(),i={cwd:e,timeout:t,windowsHide:!0};n&&(i.env=n);let c=a(h,u,i),d=[],g=[];c.stdout.on("data",p=>{d.push(p.toString("utf-8"))}),c.stderr.on("data",p=>{g.push(p.toString("utf-8"))}),c.on("close",p=>{s({stdout:d.join(""),stderr:g.join(""),exitCode:p,elapsed:Date.now()-l})}),c.on("error",p=>{s({stdout:d.join(""),stderr:g.join("")+` -`+p.message,exitCode:-1,elapsed:Date.now()-l})})})}function Ue(){if(it)return Je;it=!0;try{let h;if(process.platform==="win32"){let u=process.env.ComSpec||"C:\\Windows\\System32\\cmd.exe";h=(0,le.execFileSync)(u,["/c","where","git"],{timeout:5e3,windowsHide:!0,encoding:"utf-8"})}else h=(0,le.execFileSync)("which",["git"],{timeout:5e3,encoding:"utf-8"});if(h){let u=h.split(` -`)[0].trim();u&&(Je=se.dirname(u))}}catch(h){}return Je}function me(){let h={...process.env},u=process.platform,e=ot.homedir(),t=[],r=Ue();r&&t.push(r),u==="darwin"?t.push("/opt/homebrew/bin","/usr/local/bin","/usr/bin",`${e}/.local/bin`):u==="linux"&&t.push("/usr/local/bin","/usr/bin",`${e}/.local/bin`);let n=h.PATH||"";return h.PATH=[...t,n].filter(Boolean).join(se.delimiter),h}function dt(h){return String(h).toLowerCase().replace(/[^a-z0-9]/g,"").includes("betterbibtex")}function Ge(h){if(!h)return!1;try{if(!ne.existsSync(h))return!1;for(let u of ne.readdirSync(h))if(dt(u))return!0}catch(u){}return!1}function Me(h){if(!h)return!1;try{if(!ne.existsSync(h))return!1;for(let u of ne.readdirSync(h)){let e=se.join(h,u,"extensions");try{if(!ne.existsSync(e))continue;for(let t of ne.readdirSync(e))if(dt(t))return!0}catch(t){}}}catch(u){}return!1}var ye=$(require("fs")),W=$(require("path")),ut=require("child_process"),ae=null;function zt(h,u){let e=u||ye,t=W.join(h,"paperforge.json"),r={system_dir:"System",resources_dir:"Resources",literature_dir:"Literature",base_dir:"Bases"};try{if(!e.existsSync(t))return{...r,_warning:"paperforge.json not found; using defaults"};let n=e.readFileSync(t,"utf-8"),a=JSON.parse(n),s=a.vault_config||{};return{system_dir:s.system_dir||a.system_dir||r.system_dir,resources_dir:s.resources_dir||a.resources_dir||r.resources_dir,literature_dir:s.literature_dir||a.literature_dir||r.literature_dir,base_dir:s.base_dir||a.base_dir||r.base_dir,_warning:null}}catch(n){return console.warn("PaperForge: Failed to read paperforge.json, using defaults",n),{...r,_warning:"paperforge.json invalid; using defaults"}}}function Q(h,u){let e=zt(h,u),t=W.join(h,e.system_dir,"PaperForge");return{vault:h,systemDir:t,indexesDir:W.join(t,"indexes"),logsDir:W.join(t,"logs"),dbPath:W.join(t,"indexes","paperforge.db"),memoryStatePath:W.join(t,"indexes","memory-runtime-state.json"),vectorStatePath:W.join(t,"indexes","vector-runtime-state.json"),healthStatePath:W.join(t,"indexes","runtime-health.json"),buildStatePath:W.join(t,"indexes","vector-build-state.json"),orphanStatePath:W.join(t,"indexes","sync-orphan-state.json"),exportsDir:W.join(t,"exports"),ocrDir:W.join(t,"ocr"),pluginDataPath:W.join(h,".obsidian","plugins","paperforge","data.json"),pfJsonPath:W.join(h,"paperforge.json"),configWarning:e._warning}}function Xe(h){try{return ye.existsSync(h)?JSON.parse(ye.readFileSync(h,"utf-8")):null}catch(u){return null}}function $t(h){let u=Q(h);return Xe(u.memoryStatePath)}function Re(h){let u=Q(h);return Xe(u.vectorStatePath)}function Ye(h){let u=Q(h);return Xe(u.healthStatePath)}function ht(h){var e;let u=Ye(h);return!!(u&&((e=u.summary)==null?void 0:e.status)==="ok")}function Ie(h){let u=$t(h);return!u||u.paper_count_db===0?"DB not found. Run paperforge memory build.":"Papers: "+u.paper_count_db+" | "+(u.fresh?"fresh":"stale")}function be(h){var t,r,n;let u=Re(h);return u?u.healthy===!1?"Vector index unreadable - rebuild required":"Chunks: "+(((t=u.chunk_count)!=null?t:0)+((r=u.body_chunk_count)!=null?r:0)+((n=u.object_chunk_count)!=null?n:0))+" | "+u.model+" | "+u.mode:"Status unavailable"}function ce(h,u){if(ae)return ae;if(u&&u.python_path&&u.python_path.trim()){let r=u.python_path.trim();if(ye.existsSync(r))return ae={path:r,source:"manual",extraArgs:[]},ae}let e=[W.join(h,".paperforge-test-venv","Scripts","python.exe"),W.join(h,".venv","Scripts","python.exe"),W.join(h,"venv","Scripts","python.exe")];for(let r=0;r({...a,_selected:!0,_idx:s})),this.vaultPath=r,this.py=n}_updateUI(){let e=this.orphans.filter(t=>t._selected);this._countEl.setText(o("orphan_delete_selected").replace("{count}",String(e.length))),this._selectAllBtn.setText(e.length===this.orphans.length?o("orphan_deselect_all"):o("orphan_select_all"));for(let t of this.orphans){let r=this._rowEls[t._idx];r&&r.toggleClass("paperforge-orphan-dimmed",!t._selected)}}onOpen(){let{contentEl:e}=this;e.addClass("paperforge-modal"),e.createEl("h2",{text:o("orphan_title").replace("{count}",String(this.orphans.length))}),e.createEl("p",{cls:"paperforge-modal-desc",text:o("orphan_desc")}),this._rowEls=[];let t=e.createEl("div",{cls:"paperforge-orphan-list"});for(let n of this.orphans){let a=t.createEl("div",{cls:"paperforge-orphan-row"+(n._selected?"":" paperforge-orphan-dimmed")});this._rowEls.push(a);let s=a.createEl("div",{cls:"paperforge-orphan-info"}),l=s.createEl("div",{cls:"paperforge-orphan-header"});l.createEl("span",{cls:"paperforge-orphan-key",text:n.citation_key||n.key});let i=l.createEl("span",{cls:"paperforge-orphan-tags"});i.createEl("span",{cls:"paperforge-tag "+(n.has_pdf?"tag-pdf":"tag-nopdf"),text:n.has_pdf?"PDF":"no PDF"}),n.collection_path&&i.createEl("span",{cls:"paperforge-tag tag-collection",text:n.collection_path}),n.title&&s.createEl("div",{cls:"paperforge-orphan-title",text:n.title});let c=[];n.authors&&c.push(n.authors),n.year&&c.push(n.year),c.length>0&&s.createEl("div",{cls:"paperforge-orphan-meta",text:c.join(" \xB7 ")}),s.createEl("div",{cls:"paperforge-orphan-explain",text:o("orphan_explain")}),a.addEventListener("click",()=>{n._selected=!n._selected,this._updateUI()})}let r=e.createEl("div",{cls:"paperforge-modal-actions"});this._selectAllBtn=r.createEl("button",{cls:"paperforge-step-btn",text:"Deselect all"}),this._selectAllBtn.addEventListener("click",()=>{let n=this.orphans.every(a=>a._selected);for(let a of this.orphans)a._selected=!n;this._updateUI()}),this._countEl=r.createEl("button",{cls:"paperforge-step-btn mod-cta",text:"Delete "+this.orphans.length+" selected"}),r.createEl("button",{cls:"paperforge-step-btn",text:"Keep all"}).addEventListener("click",()=>this.close()),this._countEl.addEventListener("click",()=>{let n=this.orphans.filter(s=>s._selected);if(n.length===0){new G.Notice(o("orphan_none_selected"));return}if(this._countEl.setText("Deleting..."),this._countEl.setAttr("disabled",""),this._selectAllBtn.setAttr("disabled",""),!this.py||!this.py.path){new G.Notice("PaperForge: Python not found"),this.close();return}let a=n.map(s=>s.key);(0,De.execFile)(this.py.path,[...this.py.extraArgs,"-m","paperforge","--vault",this.vaultPath,"prune","--force","--json",...a],{cwd:this.vaultPath,timeout:6e4},(s,l)=>{if(s){new G.Notice("PaperForge: prune failed"),this.close();return}try{let i=JSON.parse(l),c=i.data&&i.data.deleted||[];new G.Notice("Deleted "+c.length+" orphan workspace(s)")}catch(i){new G.Notice("PaperForge: prune done")}this.close()})})}onClose(){this.contentEl.empty()}};function Ne(h,u,e){console.log("[PF] checkOrphanState called");try{let r=Q(e).orphanStatePath;if(!te.existsSync(r)){console.log("[PF] orphan file NOT FOUND");return}console.log("[PF] orphan file FOUND");let n=te.readFileSync(r,"utf-8"),s=JSON.parse(n).orphans||[];if(console.log("[PF] orphans count:",s.length),s.length===0)return;let l=ce(e,u.settings);console.log("[PF] py.path:",l?l.path:"null"),new et(h,s,e,l).open(),te.unlinkSync(r),console.log("[PF] orphan file cleaned")}catch(t){console.log("[PF] checkOrphanState exception:",t.message||t)}}var Te=class extends G.Modal{constructor(e,t){super(e);this._pendingSave=null;this._showSkipConfirm=!1;this.plugin=t,this._step=1}onOpen(){this._render()}onClose(){this.contentEl.empty()}_render(){let{contentEl:e}=this;e.empty(),e.addClass("paperforge-modal"),this._renderStepIndicator(),this._renderStepContent(),this._renderNavigation()}_renderStepIndicator(){let e=[o("wizard_step1"),o("wizard_step2"),o("wizard_step3"),o("wizard_step4"),o("wizard_step5")],t=this.contentEl.createEl("div",{cls:"paperforge-step-bar"});e.forEach((r,n)=>{let a=n+1,s=t.createEl("div",{cls:`paperforge-step-dot ${a===this._step?"active":""} ${a1&&e.createEl("button",{cls:"paperforge-step-btn",text:o("nav_prev")}).addEventListener("click",()=>{this._step--,this._showSkipConfirm=!1,this._render()}),this._step<5?e.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("nav_next")}).addEventListener("click",()=>{if(this._step===3){let r=this._validateStep3();if(r.blocked){if(r.reason==="zotero")return;if(r.reason==="ocr"){this._showSkipConfirm=!0,this._render();return}}}this._step++,this._showSkipConfirm=!1,this._render()}):e.createEl("button",{cls:"paperforge-step-btn",text:o("nav_close")}).addEventListener("click",()=>this.close())}_validateStep3(){let e=this.plugin.settings,t=gt(this._apiKeyValidated,e.zotero_data_dir);if(t.reason==="ocr")return t;let r=(e.zotero_data_dir||"").trim();if(!r)return new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879\uFF0C\u8BF7\u586B\u5199\u8DEF\u5F84"),{blocked:!0,reason:"zotero"};if(!te.existsSync(r))return new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u5B58\u5728"),{blocked:!0,reason:"zotero"};if(!te.statSync(r).isDirectory())return new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u662F\u4E00\u4E2A\u76EE\u5F55"),{blocked:!0,reason:"zotero"};let n=_t.join(r,"storage");return!te.existsSync(n)||!te.statSync(n).isDirectory()?(new G.Notice("Zotero \u6570\u636E\u76EE\u5F55\u4E2D\u672A\u627E\u5230 storage/ \u5B50\u76EE\u5F55"),{blocked:!0,reason:"zotero"}):{blocked:!1}}_stepOverview(e){e.createEl("h2",{text:o("wizard_title")}),e.createEl("p",{text:o("wizard_intro")});let t=this.plugin.settings,r=this.app.vault.adapter.basePath,n=e.createEl("div",{cls:"paperforge-dir-tree"}),a=n.createEl("div",{cls:"paperforge-dir-node root"});a.textContent=`\u{1F4C1} Vault (${r})`;let s=n.createEl("div",{cls:"paperforge-dir-children"}),l=s.createEl("div",{cls:"paperforge-dir-node folder"});l.textContent=`\u{1F4C1} ${t.resources_dir||"Resources"}/ \u2014 \u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08Base \u6570\u636E\u6765\u6E90\uFF09`,l.createEl("div",{cls:"paperforge-dir-children"}).createEl("div",{cls:"paperforge-dir-node file",text:`\u{1F4C1} ${t.literature_dir||"Literature"}/ \u2014 \u6587\u732E\u5361\u7247`}),s.createEl("div",{cls:"paperforge-dir-node folder",text:`\u{1F4C1} ${t.base_dir||"Bases"}/ \u2014 \u6570\u636E\u7BA1\u7406\u9762\u677F`}),s.createEl("div",{cls:"paperforge-dir-node folder",text:`\u{1F4C1} ${t.system_dir||"System"}/ \u2014 Zotero \u8F6F\u94FE\u63A5 + PaperForge \u7CFB\u7EDF\u6587\u4EF6\u5939`}),e.createEl("p",{text:o("wizard_preview"),cls:"paperforge-modal-hint"}),e.createEl("p",{text:o("wizard_safety"),cls:"paperforge-modal-hint"});let c=e.createEl("div",{cls:"paperforge-summary"}),d=[{label:o("dir_resources"),val:`${r}/${t.resources_dir||"Resources"}`},{label:o("dir_notes"),val:`${r}/${t.resources_dir||"Resources"}/${t.literature_dir||"Literature"}`},{label:o("dir_base"),val:`${r}/${t.base_dir||"Bases"}`},{label:o("dir_system"),val:`${r}/${t.system_dir||"System"}`}];for(let g of d){let p=c.createEl("div",{cls:"paperforge-summary-row"});p.createEl("span",{cls:"paperforge-summary-label",text:g.label}),p.createEl("span",{cls:"paperforge-summary-value",text:g.val})}}_stepDirectories(e){e.createEl("h2",{text:o("wizard_step2")}),e.createEl("p",{text:o("wizard_intro")});let t=this.plugin.settings,r=this.app.vault.adapter.basePath;this._modalField(e,o("dir_vault"),r,!0),e.createEl("p",{text:o("wizard_dir_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u8D44\u6E90\u76EE\u5F55\uFF08\u521B\u5EFA\u6587\u732E\u5361\u7247\u76EE\u5F55\u7684\u5730\u65B9\uFF09","resources_dir",t.resources_dir,"Resources"),e.createEl("p",{text:o("wizard_dir_sub_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08\u5B58\u653E\u6587\u732E\u5361\u7247\u7684\u5730\u65B9\uFF0CBase \u6570\u636E\u6765\u6E90\uFF09","literature_dir",t.literature_dir,"Literature"),e.createEl("p",{text:o("wizard_sys_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u7CFB\u7EDF\u76EE\u5F55\uFF08\u5B58\u653E Zotero \u8F6F\u94FE\u63A5\u548C PaperForge \u7CFB\u7EDF\u6587\u4EF6\uFF09","system_dir",t.system_dir,"System"),this._modalInput(e,"Base \u76EE\u5F55\uFF08\u5B58\u653E\u6570\u636E\u7BA1\u7406\u9762\u677F\u7684\u5730\u65B9\uFF09","base_dir",t.base_dir,"Bases"),e.createEl("p",{text:o("wizard_safety"),cls:"paperforge-modal-hint"});let n=e.createEl("div",{cls:"paperforge-summary"}),a=[{label:o("dir_resources"),val:`${r}/${t.resources_dir||""}`},{label:o("dir_notes"),val:`${r}/${t.resources_dir||""}/${t.literature_dir||""}`},{label:o("dir_system"),val:`${r}/${t.system_dir||""}`},{label:o("dir_base"),val:`${r}/${t.base_dir||""}`}];for(let s of a){let l=n.createEl("div",{cls:"paperforge-summary-row"});l.createEl("span",{cls:"paperforge-summary-label",text:s.label}),l.createEl("span",{cls:"paperforge-summary-value",text:s.val})}}_stepKeys(e){if(e.createEl("h2",{text:o("wizard_step3")}),this._showSkipConfirm){this._renderSkipConfirm(e);return}let t=this.plugin.settings;e.createEl("p",{text:o("wizard_agent_hint"),cls:"paperforge-modal-hint"});let r=[{key:"opencode",name:"OpenCode"},{key:"claude",name:"Claude Code"},{key:"cursor",name:"Cursor"},{key:"github_copilot",name:"GitHub Copilot"},{key:"windsurf",name:"Windsurf"},{key:"codex",name:"Codex"},{key:"gemini",name:"Gemini CLI"},{key:"cline",name:"Cline"}],n=e.createEl("div",{cls:"paperforge-modal-field"});n.createEl("label",{cls:"paperforge-modal-label",text:o("label_agent")});let a=n.createEl("select",{cls:"paperforge-modal-select"});for(let g of r){let p=a.createEl("option",{text:g.name,attr:{value:g.key}});g.key===(t.agent_platform||"opencode")&&(p.selected=!0)}a.addEventListener("change",()=>{t.agent_platform=a.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)}),e.createEl("p",{text:o("wizard_keys_hint"),cls:"paperforge-modal-hint"});let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:o("field_paddleocr")});let l=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"password",placeholder:"API Key"}});l.value=t.paddleocr_api_key||"",this._apiKeyValidated=!1,this._apiKeyStatus=s.createEl("span",{cls:"paperforge-apikey-status",text:""});let i=s.createEl("button",{cls:"paperforge-step-btn",text:"\u9A8C\u8BC1"});i.addEventListener("click",()=>this._validateApiKey(l.value,i)),l.addEventListener("input",()=>{t.paddleocr_api_key=l.value,this._apiKeyValidated=!1,this._apiKeyStatus.textContent="",this._apiKeyStatus.className="paperforge-apikey-status"}),this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500),e.createEl("p",{text:o("wizard_api_hint_skip"),cls:"paperforge-modal-hint"});let c=e.createEl("div",{cls:"paperforge-modal-field"});c.createEl("label",{cls:"paperforge-modal-label",text:o("field_zotero_data")});let d=c.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text",placeholder:o("field_zotero_placeholder")}});d.value=t.zotero_data_dir||"",d.addEventListener("input",()=>{t.zotero_data_dir=d.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_validateApiKey(e,t){if(!e||e.length<10){this._apiKeyStatus.textContent="\u5BC6\u94A5\u683C\u5F0F\u4E0D\u6B63\u786E\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error";return}t.disabled=!0,t.textContent="\u9A8C\u8BC1\u4E2D\u2026",this._apiKeyStatus.textContent="\u6B63\u5728\u9A8C\u8BC1\u2026",this._apiKeyStatus.className="paperforge-apikey-status";let r=JSON.stringify({model:"PaddleOCR-VL-1.5"}),n={hostname:"paddleocr.aistudio-app.com",path:"/api/v2/ocr/jobs",method:"POST",headers:{Authorization:"bearer "+e,"Content-Type":"application/json","Content-Length":Buffer.byteLength(r)},timeout:1e4},a=mt.request(n,s=>{t.disabled=!1,t.textContent="\u9A8C\u8BC1";let l="";s.on("data",i=>l+=i),s.on("end",()=>{try{let i=JSON.parse(l);s.statusCode===400&&i.code===10001?(this._apiKeyStatus.textContent="\u2713 \u5BC6\u94A5\u6709\u6548",this._apiKeyStatus.className="paperforge-apikey-status ok",this._apiKeyValidated=!0):s.statusCode===401?(this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5BC6\u94A5\u65E0\u6548\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1):(this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1AAPI \u8FD4\u56DE "+s.statusCode+"\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1)}catch(i){this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u89E3\u6790\u54CD\u5E94\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1}})});a.on("error",s=>{t.disabled=!1,t.textContent="\u9A8C\u8BC1",this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u8FDE\u63A5 ("+s.message+")\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1}),a.write(r),a.end()}_renderSkipConfirm(e){e.createEl("p",{text:o("wizard_skip_ocr_desc"),cls:"paperforge-modal-desc"});let t=e.createEl("div",{cls:"paperforge-modal-actions"});t.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("wizard_skip_ocr_continue")}).addEventListener("click",()=>{this._showSkipConfirm=!1,this._step++,this._render()}),t.createEl("button",{cls:"paperforge-step-btn",text:o("wizard_skip_ocr_back")}).addEventListener("click",()=>{this._showSkipConfirm=!1,this._render()})}_modalField(e,t,r,n){let a=e.createEl("div",{cls:"paperforge-modal-field"});a.createEl("label",{cls:"paperforge-modal-label",text:t});let s=a.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text"}});s.value=r,s.disabled=!!n}_modalInput(e,t,r,n,a){let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:t});let l=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text",placeholder:a||""}});l.value=n;let i=this.plugin.settings;l.addEventListener("input",()=>{i[r]=l.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_modalSecret(e,t,r,n,a){let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:t});let l=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"password",placeholder:a||""}});l.value=n;let i=this.plugin.settings;l.addEventListener("input",()=>{i[r]=l.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_stepInstall(e){e.createEl("h2",{text:o("wizard_step4")}),this._installLog=e.createEl("div",{cls:"paperforge-install-log"});let t=e.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("install_btn")});t.addEventListener("click",()=>this._runInstall(t))}async _runInstall(e){var s,l,i,c,d,g;e.disabled=!0,e.textContent=o("install_btn_running"),this._installLog.setText(o("install_validating")+` -`),this._log(o("install_validating"));let t=this.plugin.settings,r=this._validate();if(r.length>0){this._log(o("validate_fail")+":"),r.forEach(p=>this._log(" \u2717 "+p)),e.disabled=!1,e.textContent=o("install_btn_retry");return}let n=(p,f={})=>new Promise((y,b)=>{let{path:m,extraArgs:x=[]}=L(t.vault_path.trim(),this.plugin.settings,void 0,void 0),w=(0,De.spawn)(m,[...x,...p],{cwd:t.vault_path.trim(),env:me(),timeout:12e4,...f}),E="",_="";w.stdout.on("data",v=>{let k=v.toString("utf-8");E+=k,f.logStdout&&this._processSetupOutput(k)}),w.stderr.on("data",v=>{let k=v.toString("utf-8");_+=k,this._log("[stderr] "+k.trim())}),w.on("close",v=>{v===0?y({stdout:E,stderr:_}):b(new Error(_.trim()||E.trim()||`exit code ${v}`))}),w.on("error",v=>b(v))}),a=["-m","paperforge","--vault",t.vault_path.trim(),"setup","--headless","--system-dir",t.system_dir.trim(),"--resources-dir",t.resources_dir.trim(),"--literature-dir",t.literature_dir.trim(),"--base-dir",t.base_dir.trim(),"--agent",t.agent_platform||"opencode"];t.zotero_data_dir&&t.zotero_data_dir.trim()&&a.push("--zotero-data",t.zotero_data_dir.trim()),t.paddleocr_api_key&&t.paddleocr_api_key.trim()&&a.push("--paddleocr-key",t.paddleocr_api_key.trim());try{let p=!0;try{await n(["-c","import paperforge"])}catch(f){p=!1}if(!p){this._log(o("install_bootstrapping"));let f=this.plugin.manifest.version;this._log(`[install] Trying PyPI: pip install paperforge==${f}`);let y=["-m","pip","install","--upgrade"];process.platform!=="win32"&&y.push("--user"),y.push(`paperforge==${f}`);try{await n(y,{logStdout:!0})}catch(b){this._log(`[install] PyPI failed, falling back to git: git+https://...@v${f}`),console.warn("[PaperForge] PyPI install failed, falling back to git:",(s=b.message)==null?void 0:s.slice(0,200));let m=["-m","pip","install","--upgrade"];process.platform!=="win32"&&m.push("--user"),m.push(`git+https://github.com/LLLin000/PaperForge.git@v${f}`),await n(m,{logStdout:!0})}}await n(a,{logStdout:!0,env:me()}),this._log(o("install_complete")),t.setup_complete=!0,await this.plugin.saveSettings(),setTimeout(()=>{this._step=5,this._render()},800)}catch(p){console.error("PaperForge setup failed:",p.message);let f=this._formatSetupError(p.message);this._log(o("install_failed")+f);let y=(l=this._installLog.parentElement)==null?void 0:l.createEl("button",{cls:"paperforge-copy-diag-btn",text:o("error_copy_diagnostic")||"Copy diagnostic"});if(y){let b=p.message,m=((c=(i=this.plugin)==null?void 0:i.settings)==null?void 0:c.python_path)||"auto",x=((g=(d=this.plugin)==null?void 0:d.manifest)==null?void 0:g.version)||"?",w=process.platform+" "+process.arch,E,_;try{E=Ue()||"(not found)"}catch(P){E="(error)"}try{_=L(t.vault_path.trim(),this.plugin.settings,void 0,void 0)}catch(P){_=null}let v=(process.env.PATH||"").length,k=(process.env.PATH||"").toLowerCase().includes("git"),S=["[PaperForge Diagnostic]","Category: "+f,"Plugin version: "+x,"Python: "+m,"Resolved Python: "+((_==null?void 0:_.path)||"?"),"OS: "+w,"Vault path: "+(t.vault_path||"?"),"--- Git ---","Git dir (resolved): "+E,"PATH length: "+v+" chars","PATH contains git: "+k,"--- Raw error ---",b.slice(0,2e3)].join(` -`);y.addEventListener("click",()=>{navigator.clipboard.writeText(S).then(()=>{y.setText(o("error_copied")||"Copied!"),setTimeout(()=>{y.setText(o("error_copy_diagnostic")||"Copy diagnostic")},3e3)}).catch(()=>{new G.Notice("[!!] Clipboard write failed",6e3)})})}e.disabled=!1,e.textContent=o("install_btn_retry")}}_log(e){this._installLog&&this._installLog.setText(this._installLog.textContent+e+` +"use strict";var Dt=Object.create;var Ie=Object.defineProperty;var Bt=Object.getOwnPropertyDescriptor;var At=Object.getOwnPropertyNames;var Ot=Object.getPrototypeOf,Lt=Object.prototype.hasOwnProperty;var It=(u,h)=>()=>(h||u((h={exports:{}}).exports,h),h.exports),Mt=(u,h)=>{for(var e in h)Ie(u,e,{get:h[e],enumerable:!0})},at=(u,h,e,t)=>{if(h&&typeof h=="object"||typeof h=="function")for(let r of At(h))!Lt.call(u,r)&&r!==e&&Ie(u,r,{get:()=>h[r],enumerable:!(t=Bt(h,r))||t.enumerable});return u};var V=(u,h,e)=>(e=u!=null?Dt(Ot(u)):{},at(h||!u||!u.__esModule?Ie(e,"default",{value:u,enumerable:!0}):e,u)),Nt=u=>at(Ie({},"__esModule",{value:!0}),u);var Je=It((Jt,zt)=>{zt.exports={versions:[{version:"1.5.15",date:"2026-06-01",title:"\u5168\u6587\u5B58\u50A8\u91CD\u6784 + OCR \u9605\u8BFB\u987A\u5E8F\u4FEE\u590D + Redo \u4E00\u952E\u91CD\u505A",breaking_or_migration:["\u5168\u6587\u6587\u4EF6\u73B0\u5728\u7EDF\u4E00\u5B58\u653E\u4E8E System/PaperForge/ocr/ \u4E0B\uFF0C\u4E0D\u518D\u5728\u5DE5\u4F5C\u533A\u4FDD\u7559\u526F\u672C","Redo OCR \u73B0\u5728\u4F1A\u7ACB\u5373\u6267\u884C\uFF08\u4E00\u952E\u5B8C\u6210\uFF09\uFF0C\u4E0D\u518D\u9700\u8981\u624B\u52A8\u518D\u8DD1\u4E00\u6B21"],new_features:["Redo OCR \u4E00\u952E\u95ED\u73AF\uFF1A\u52FE\u9009 \u2192 \u70B9\u6309\u94AE \u2192 \u81EA\u52A8\u5B8C\u6210\u5168\u90E8\u6D41\u7A0B","\u8BBE\u7F6E\u9875\u65B0\u589E\u300C\u66F4\u65B0\u4E0E\u624B\u518C\u300D\u6807\u7B7E\u9875\uFF0C\u53EF\u968F\u65F6\u67E5\u770B\u7248\u672C\u66F4\u65B0\u8BB0\u5F55\u548C\u4F7F\u7528\u624B\u518C","\u63D2\u4EF6\u66F4\u65B0\u540E\u81EA\u52A8\u5F39\u51FA\u66F4\u65B0\u8BF4\u660E"],fixes:["\u4FEE\u590D\u5168\u6587\u9605\u8BFB\u987A\u5E8F\u6DF7\u4E71\uFF0C\u4F18\u5316\u6574\u4F53\u6392\u7248\u4F53\u9A8C","\u4FEE\u590D\u7AE0\u8282\u6807\u9898\u548C\u6B63\u6587\u6BB5\u843D\u9519\u4F4D\u65AD\u5F00\u7684\u95EE\u9898","\u4FEE\u590D\u56FE\u8868\u548C\u5BF9\u5E94\u56FE\u6CE8\u88AB\u5206\u5F00\u7684\u95EE\u9898","\u4FEE\u590D\u9996\u9875\u6458\u8981\u533A\u5757\u6392\u5E8F\u5F02\u5E38","\u4FEE\u590D\u5E76\u6392\u56FE\u7247\u672A\u80FD\u81EA\u52A8\u5408\u5E76\u7684\u95EE\u9898","Dashboard \u73B0\u5728\u80FD\u6B63\u786E\u8BC6\u522B\u65B0\u7684\u5168\u6587\u6587\u4EF6\u4F4D\u7F6E"],recommended_actions:["\u65E7\u7248 OCR \u5168\u6587\u53EF\u80FD\u5B58\u5728\u9605\u8BFB\u987A\u5E8F\u95EE\u9898\uFF0C\u5EFA\u8BAE\u5BF9\u91CD\u8981\u8BBA\u6587\u6267\u884C\u4E00\u6B21 Redo OCR","\u6253\u5F00\u5168\u6587\u8BF7\u76F4\u63A5\u4F7F\u7528 Dashboard \u7684\u300C\u6253\u5F00\u5168\u6587\u300D\u6309\u94AE"]}]}});var Wt={};Mt(Wt,{default:()=>Ke});module.exports=Nt(Wt);var U=require("obsidian"),W=V(require("fs")),Se=V(require("path")),pe=require("child_process");var ve="paperforge-status",Fe="paperforge",it='',se=[{id:"paperforge-sync",title:"Sync Library",desc:"Pull new references from Zotero and generate literature notes",icon:"\u21BB",cmd:"sync",okMsg:"Sync complete"},{id:"paperforge-ocr",title:"Run OCR",desc:"Extract full text and figures from PDFs via PaddleOCR",icon:"\u229E",cmd:"ocr",okMsg:"OCR started"},{id:"paperforge-doctor",title:"Run Doctor",desc:"Verify PaperForge setup \u2014 check configs, Zotero, paths, and index health",icon:"\u2695",cmd:"doctor",okMsg:"Doctor complete"},{id:"paperforge-repair",title:"Repair Issues",desc:"Fix three-way state divergence, path errors, and rebuild index",icon:"\u21BA",cmd:"repair",args:["--fix","--fix-paths"],okMsg:"Repair complete"},{id:"paperforge-ocr-redo",title:"Redo OCR",desc:"Re-run OCR for papers marked ocr_redo: true",icon:"\u21BA",cmd:"ocr",args:["redo"],okMsg:"OCR redo started"}],Re={vault_path:"",setup_complete:!1,auto_update:!0,auto_update_on_startup:!0,agent_platform:"opencode",language:"",paddleocr_api_key:"",zotero_data_dir:"",python_path:"",features:{memory_layer:!0,vector_db:!1},selected_skill_platform:"opencode",vector_db_api_key:"",vector_db_api_base:"",vector_db_api_model:"text-embedding-3-small",frozen_skills:{},system_dir:"",resources_dir:"",literature_dir:"",base_dir:"",last_seen_version:""};function ot(u,h){if(!h||!h.note_path)return h;let e=u.vault.getAbstractFileByPath(h.note_path);if(!e)return h;let t=u.metadataCache.getFileCache(e),r=t&&t.frontmatter;if(!r)return h;let n={...h};for(let a of["do_ocr","analyze","ocr_status","ocr_redo","deep_reading_status"])Object.prototype.hasOwnProperty.call(r,a)&&(n[a]=r[a]);return n}function Ze(u,h){return u&&{...u,...h}}var qe={en:{action_running:"Running ",api_key_missing:"Missing",api_key_set:"Entered",btn_install:"Open Setup Wizard",btn_install_desc:"Check whether the environment is ready, then open the step-by-step setup wizard",btn_reconfig:"Reconfigure",btn_reconfig_desc:"Open the setup wizard again to change directories, platform, or API keys",btn_validate:"Validate",check_bbt_fail:"Not detected",check_bbt_ok:"Installed",check_python_fail:"Not found",check_python_ok:"Ready",check_zotero_fail:"Not detected",check_zotero_ok:"Found",complete_export_path:"Save Better BibTeX JSON exports into:",complete_next:"Recommended next steps",complete_step1:"Open Dashboard",complete_step1_desc:'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.',complete_step2:"Sync Literature",complete_step2_desc:"In the main panel, click Sync Library to bring papers from Zotero into Obsidian and generate notes.",complete_step3:"Run OCR",complete_step3_desc:"In the Obsidian Base view, mark do_ocr:true on papers, then run OCR in the main panel.",complete_step4:"Configure Better BibTeX Auto-export",complete_step4_desc:'In Zotero, right-click the library or collection you want to sync -> Export -> Better BibTeX JSON -> enable "Keep updated".',complete_summary:"Saved Configuration",complete_title:"Setup Complete",copied:"Copied!",copy_pf_deep_cmd:"Copy /pf-deep Command",dashboard_drift_warning:"PaperForge CLI (v{0}) differs from plugin (v{1}). Open Settings \u2192 Runtime Health to sync.",deep_reading_not_found:"Deep reading file not found",desc:"Obsidian + Zotero literature pipeline. Sync papers, generate notes, run OCR, and read deeply in one place.",dir_base:"Base Dir",dir_index:"Index Dir",dir_notes:"Notes Dir",dir_resources:"Resource Dir",dir_system:"System Dir",dir_vault:"Vault Path",error_copied:"Copied!",error_copy_diagnostic:"Copy diagnostic",feat_agent_platform:"Agent Platform",feat_agent_platform_desc:"Select which agent platform to manage skills for.",feat_api_base_url:"API Base URL",feat_api_base_url_desc:"Custom OpenAI-compatible API endpoint. Leave empty for default.",feat_api_model:"API Model",feat_api_model_desc:"Embedding model name for this endpoint.",feat_build_btn:"Build",feat_build_complete:"Vector build complete.",feat_build_failed:"Build failed. See terminal output.",feat_building:"Building...",feat_cache_remove_failed:"Failed: {0}",feat_cache_removed:"Model cache removed.",feat_checking:"Checking...",feat_checking_btn:"Checking...",feat_deps_checking:"Checking dependencies...",feat_deps_missing:"Dependencies not installed. Required: chromadb, openai.",feat_enter_key:"Enter a valid OpenAI API key.",feat_install_btn:"Install",feat_install_deps:"Install Dependencies",feat_install_deps_desc:"pip install chromadb openai (~35MB).",feat_install_done:"Dependencies installed. Building vectors...",feat_install_failed:"Install failed: ",feat_installing:"Installing...",feat_installing_pkgs:"Installing {pkgs}...",feat_key_rejected:"API key rejected.",feat_memory_desc:"The Memory Layer is the core data engine of PaperForge, powered by SQLite. It integrates literature metadata (papers, assets, aliases, reading events), provides FTS5 metadata search across titles, abstracts, authors, domains, and collections, and powers agent-context and paper-status. Always active \u2014 no toggle needed.",feat_memory_rebuild_btn:"Rebuild",feat_memory_rebuild_done:"Memory DB rebuilt.",feat_memory_rebuild_failed:"Rebuild failed.",feat_memory_rebuilding:"Rebuilding...",feat_model_changed_warn:"Model changed ({0} -> {1}). Existing vectors are incompatible \u2014 rebuild required.",feat_network_error:"Network error: ",feat_no_python:"No Python found. Check Installation tab.",feat_not_cached:"Not cached",feat_openai_key:"OpenAI API Key",feat_openai_key_desc:"Used for API embedding calls. Model is defined below.",feat_output_copied:"Output copied to clipboard.",feat_rebuild_btn:"Rebuild",feat_rebuild_vectors:"Rebuild Vectors",feat_rebuild_vectors_changed:"Model changed \u2014 rebuild to update all vectors.",feat_rebuild_vectors_desc:"Rebuild all OCR fulltext vectors. Required after model or mode change.",feat_removing:"Removing...",feat_retry_btn:"Retry",feat_skills_desc:"Manage and enable/disable agent skills installed in your vault. Each row corresponds to a SKILL.md file \u2014 toggle off to prevent the agent from auto-invoking that skill.",feat_skills_system:"System Skills ship with PaperForge and are updated alongside PaperForge.",feat_skills_user:"User Skills are custom skills you install from community or create yourself.",feat_uninstall_btn:"Uninstall",feat_valid_key:"API key valid.",feat_vector_config_label:"Vector Settings",feat_vector_corrupted:"Vector index corrupted \u2014 needs force rebuild.",feat_vector_desc:"Vector Database enables semantic search across OCR-extracted fulltext via API embedding. Documents are split into chunks, embedded via OpenAI-compatible API, and stored in ChromaDB.",feat_vector_enable:"Enable Vector Retrieval",feat_vector_enable_desc:"Semantic search across OCR fulltext. Requires: pip install openai chromadb (~35MB).",feat_vector_rebuild_force_btn:"Force Rebuild",feat_verify:"Verify",feat_verify_btn:"Verify",field_paddleocr:"PaddleOCR API Key",field_python_custom:"Custom Path",field_python_interp:"Python Interpreter",field_zotero_data:"Zotero Data Dir",field_zotero_placeholder:"Required. Path to Zotero data directory for PDF attachment resolution.",guide_ocr:"Run OCR",guide_ocr_desc:"In the main panel, click Run OCR to extract full text and figures from PDFs for later reading and analysis.",guide_open:"Open Main Panel",guide_open_desc:'Press Ctrl+P and run "PaperForge: Open Main Panel", or click the PaperForge icon in the left sidebar.',guide_sync:"Sync Literature",guide_sync_desc:"After Better BibTeX JSON export is configured, click Sync Library to import papers from Zotero into Obsidian and generate notes automatically.",header_title:"PaperForge",install_bootstrapping:"PaperForge Python package not found. Installing automatically...",install_btn:"Start Install",install_btn_retry:"Retry",install_btn_running:"Installing...",install_complete:"Installation complete!",install_failed:"Installation failed: ",install_validating:"Validating setup...",jump_to_deep_reading:"Open Deep Reading",label_agent:"Agent Platform",nav_close:"Close",nav_next:"Next",nav_prev:"Back",not_set:"Not entered",notice_check_fail:"Missing: ",notice_python_missing:"Python was not detected. Install Python 3.10+ and add it to PATH.",ocr_privacy_title:"OCR Privacy Notice",ocr_privacy_warning:"OCR will upload PDFs to the PaddleOCR API. Do not upload sensitive or confidential documents.",ocr_queue_add:"Add to OCR Queue",ocr_queue_added:"Added to OCR queue",ocr_queue_remove:"Remove from OCR Queue",ocr_queue_removed:"Removed from OCR queue",ocr_understand:"I understand, continue",optional_later:"(can be set later in Settings)",orphan_delete_failed:"Prune failed",orphan_delete_selected:"Delete {count} selected",orphan_deleted:"Deleted {count} orphan workspace(s)",orphan_desc:"These papers are no longer in your Zotero library.",orphan_deselect_all:"Deselect all",orphan_explain:"Removed from Zotero. Workspace files remain on disk.",orphan_keep_all:"Keep all",orphan_none_selected:"No papers selected for deletion",orphan_select_all:"Select all",orphan_title:"Found {count} orphan paper(s)",panel_actions:"Quick Actions",prep_bbt:"Better BibTeX",prep_bbt_desc:"In Zotero: Tools -> Add-ons -> install Better BibTeX.",prep_export:"Better BibTeX Auto-export",prep_export_desc:'In Zotero, right-click the collection you want to sync -> Export Collection -> BetterBibTeX JSON -> enable "Keep updated" -> save the JSON file into the exports folder shown below. Obsidian Base views will use the JSON filename as the Base name:',prep_export_path_label:"Save the exported JSON file into this folder:",prep_key:"PaddleOCR Key",prep_key_desc:"Get your API key from https://aistudio.baidu.com/paddleocr",prep_python:"Python 3.10+",prep_python_desc:"Python must be available from the command line. If you are not sure, click below to auto-detect.",prep_zotero:"Zotero Desktop",prep_zotero_desc:"Install Zotero from https://www.zotero.org",run_in_agent:"Run in {0}",runtime_health:"Runtime Health",runtime_health_checking:"Checking...",runtime_health_desc:"Check whether the installed paperforge Python package matches the plugin version and whether the deployed skill contract is current.",runtime_health_match:"Match",runtime_health_mismatch:"Mismatch",runtime_health_package_ver:"Python package v{0}",runtime_health_plugin_ver:"Plugin v{0}",runtime_health_sync:"Sync Runtime",runtime_health_sync_done:"Runtime synced to v{0}",runtime_health_sync_fail:"Sync failed: {0}",runtime_health_syncing:"Syncing...",section_config:"Current Configuration",section_guide:"How To Use",section_prep:"Preparation",section_prep_desc:"Before first use, finish these 4 preparation items. Better BibTeX auto-export is configured after setup:",setup_done:"PaperForge environment is ready",setup_pending:"Not installed yet. Finish the preparation items below, then open the wizard.",tab_features:"Features",tab_setup:"Installation",tab_maintenance:"Maintenance",validate_base:"Base directory is required",validate_fail:"Please complete the required fields below",validate_index:"Index directory is required",validate_key:"PaddleOCR API key (optional, needed for OCR)",validate_notes:"Notes directory is required",validate_resources:"Resources directory is required",validate_system:"System directory is required",validate_vault:"Vault path is required",validate_zotero:"Zotero data directory (optional, needed for PDF linking)",wizard_agent_hint:"Choose the AI agent platform you use most often. PaperForge will place the matching command and skill files in the correct location.",wizard_dir_hint:"PaperForge stores user-facing literature data under the resources directory. These folders will live there:",wizard_dir_sub_hint:"Resolved folder preview based on the names below:",wizard_intro:"This wizard walks you through the full setup. In most cases, the default values are fine to keep.",wizard_keys_hint:"Enter your PaddleOCR API key below. If you want PaperForge to auto-locate Zotero PDFs, you can also fill in the Zotero data directory.",wizard_preview:"After installation, system files stay at the vault root while literature data stays under the resources directory.",wizard_safety:"Safety: if the selected folders already contain files, setup preserves existing files and only creates missing PaperForge folders and files.",wizard_step1:"Overview",wizard_step2:"Directory Setup",wizard_step3:"Platform & Keys",wizard_step4:"Install",wizard_step5:"Done",wizard_skip_ocr_desc:"OCR will not be available until you configure a valid PaddleOCR API key. You can continue setup now and configure it later in Settings.",wizard_skip_ocr_continue:"Continue without OCR key",wizard_skip_ocr_back:"Back to configure",wizard_api_hint_skip:"OCR key is optional \u2014 you may skip it and configure later.",wizard_sys_hint:"These folders live at the vault root, outside the resources directory:",wizard_title:"PaperForge Setup Wizard",ocr_maint_no_action:"No Action Needed",ocr_maint_rebuild:"Rebuild Recommended",ocr_maint_failed:"OCR Failed",ocr_maint_limited:"Result Limited",ocr_maint_needs_attention:"Needs Attention",ocr_maint_limitations:"Result Limitations",ocr_maint_hero_ok:"OCR looks usable overall.",ocr_maint_hero_warn:"OCR needs attention: {rebuild} rebuild recommended, {failed} failed.",ocr_maint_hero_note:"This page only promotes issues where maintenance is likely to help. Some papers may have limitations that maintenance will not improve.",ocr_maint_limitations_intro:"These papers look less certain, but PaperForge does not currently have a high-confidence maintenance action to recommend.",ocr_maint_all_papers:"All Papers",ocr_maint_rebuild_btn:"Rebuild results",ocr_maint_redo_btn:"Rerun OCR",maintenance_group_retry:"Needs Retry",maintenance_group_rebuild:"Can Rebuild",maintenance_group_legacy:"Upgrade Available (Optional)",maintenance_btn_retry:"Retry",maintenance_btn_rebuild:"Rebuild",maintenance_btn_upgrade:"Upgrade",maintenance_refresh_spinning:"Updating\u2026",maintenance_all_good:"\u2705 All good \u2014 no action needed",maintenance_n_pending:"{n} need attention",version_panel_title:"Version History",version_panel_back:"Back",version_filter_placeholder:"Filter papers...",version_papers_count:"{n} papers",version_current:"current",version_restore_btn:"Restore",version_compare_btn:"Compare",version_restore_selected:"Restore selected",version_clear_old:"Clear old versions (free {size})",version_no_backups:"No version history available",version_restore_confirm:"Restore {label} for {paper}?",version_restore_done:"Restored {label}",version_compare_title:"{vA} vs {vB}",version_compare_paragraphs:"{n} paragraphs changed",version_error_read:"Cannot read version data",retrieval_search_placeholder:"Search papers... (@ for deep search)",retrieval_search_placeholder_deep:"Search papers via deep retrieval...",retrieval_search_idle_hint:"Type to search metadata, or start with @ for deep semantic search",retrieval_searching_metadata:"Searching metadata...",retrieval_searching_deep:"Running deep search...",retrieval_search_cancel:"Cancel",retrieval_results_count:"{n} result{s}",retrieval_empty:"No matching papers found.",retrieval_empty_tips:"Try broader terms or @ deep search.",retrieval_vectors_not_built:"Vectors Not Built",retrieval_vectors_not_built_desc:"Vector index has not been built. Search requires a built vector index.",retrieval_open_vector_settings:"Open Vector Settings",retrieval_backend_unavailable:"Backend Unavailable",retrieval_backend_unavailable_desc:"The Python CLI search backend is not responding.",retrieval_run_doctor:"Run Doctor",retrieval_retry:"Retry",retrieval_timeout_title:"Search Timed Out",retrieval_timeout_desc:"The search took too long. You can retry or try a simpler query.",retrieval_model_changed:"Model Changed",retrieval_model_changed_desc:"The embedding model has changed since vectors were built. Rebuilding is required.",retrieval_rebuild_vectors:"Rebuild Vectors",retrieval_internal_error:"An internal error occurred. Check the console for details.",retrieval_build_idle:"Vectors not yet built",retrieval_build_ready:"Vectors ready",retrieval_build_stopping:"Stopping...",retrieval_build_stopped:"Build stopped. Resume to continue.",retrieval_build_failed:"Build failed",retrieval_build_stale:"Previous build was interrupted. Resume to continue.",retrieval_build_deps_missing:"Dependencies not installed",retrieval_build_runtime_mismatch:"Plugin and CLI versions differ",retrieval_stop:"Stop",retrieval_force_rebuild:"Force Rebuild",retrieval_rebuild_warning:"Rebuild will replace {n} existing chunk(s). Continue?",retrieval_no_python:"No Python found. Check Installation tab."},zh:{action_running:"\u6B63\u5728\u6267\u884C ",api_key_missing:"\u672A\u914D\u7F6E \u2717",api_key_set:"\u5DF2\u914D\u7F6E \u2713",btn_install:"\u6253\u5F00\u5B89\u88C5\u5411\u5BFC",btn_install_desc:"\u81EA\u52A8\u68C0\u6D4B Python + \u524D\u7F6E\u73AF\u5883\uFF0C\u901A\u8FC7\u540E\u6253\u5F00\u5206\u6B65\u5B89\u88C5\u5411\u5BFC",btn_reconfig:"\u91CD\u65B0\u914D\u7F6E",btn_reconfig_desc:"\u91CD\u65B0\u8FD0\u884C\u5B89\u88C5\u5411\u5BFC\uFF0C\u4FEE\u6539\u76EE\u5F55\u6216\u5BC6\u94A5\u914D\u7F6E",btn_validate:"\u9A8C\u8BC1",check_bbt_fail:"\u672A\u68C0\u6D4B\u5230",check_bbt_ok:"\u5DF2\u5B89\u88C5",check_python_fail:"\u672A\u5B89\u88C5",check_python_ok:"\u5DF2\u5C31\u7EEA",check_zotero_fail:"\u672A\u68C0\u6D4B\u5230",check_zotero_ok:"\u5DF2\u5B89\u88C5",complete_next:"\u4E0B\u4E00\u6B65\u64CD\u4F5C",complete_step1:"\u6253\u5F00 PaperForge Dashboard",complete_step1_desc:"Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807",complete_step2:"\u540C\u6B65\u6587\u732E",complete_step2_desc:"Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0",complete_step3:"\u8FD0\u884C OCR",complete_step3_desc:"Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868",complete_step4:"\u914D\u7F6E BBT \u81EA\u52A8\u5BFC\u51FA",complete_summary:"\u5F53\u524D\u5B8C\u6574\u914D\u7F6E",complete_title:"\u2713 PaperForge \u5B89\u88C5\u5B8C\u6210",copied:"\u5DF2\u590D\u5236\uFF01",copy_pf_deep_cmd:"\u590D\u5236 /pf-deep \u547D\u4EE4",dashboard_drift_warning:'\u63D2\u4EF6\u7248\u672C\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u4E0D\u5339\u914D\u3002\u8BF7\u5728\u8BBE\u7F6E\u4E2D\u70B9\u51FB"\u540C\u6B65\u8FD0\u884C\u65F6"\u3002',deep_reading_not_found:"\u7CBE\u8BFB\u6587\u4EF6\u672A\u627E\u5230",desc:"Obsidian + Zotero \u6587\u732E\u7BA1\u7406\u6D41\u6C34\u7EBF\u3002\u81EA\u52A8\u540C\u6B65\u6587\u732E\u3001\u751F\u6210\u7B14\u8BB0\u3001OCR \u63D0\u53D6\u5168\u6587\uFF0C\u4E00\u7AD9\u5F0F\u6587\u732E\u7CBE\u8BFB\u5DE5\u4F5C\u6D41\u3002",dir_base:"Base \u76EE\u5F55",dir_index:"\u7D22\u5F15\u76EE\u5F55",dir_notes:"\u6B63\u6587\u76EE\u5F55",dir_resources:"\u8D44\u6E90\u76EE\u5F55",dir_system:"\u7CFB\u7EDF\u76EE\u5F55",dir_vault:"Vault \u8DEF\u5F84",error_copied:"\u5DF2\u590D\u5236\uFF01",error_copy_diagnostic:"\u590D\u5236\u8BCA\u65AD\u4FE1\u606F",feat_agent_platform:"Agent \u5E73\u53F0",feat_agent_platform_desc:"\u9009\u62E9\u8981\u7BA1\u7406\u7684 Agent \u5E73\u53F0\u3002",feat_api_base_url:"API \u5730\u5740",feat_api_base_url_desc:"\u81EA\u5B9A\u4E49 OpenAI \u517C\u5BB9 API \u7AEF\u70B9\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u5730\u5740\u3002",feat_api_model:"API \u6A21\u578B",feat_api_model_desc:"\u8BE5\u7AEF\u70B9\u4F7F\u7528\u7684\u5D4C\u5165\u6A21\u578B\u540D\u79F0\u3002",feat_build_btn:"\u6784\u5EFA",feat_build_complete:"\u5411\u91CF\u6784\u5EFA\u5B8C\u6210\u3002",feat_build_failed:"\u6784\u5EFA\u5931\u8D25\u3002\u8BF7\u67E5\u770B\u7EC8\u7AEF\u8F93\u51FA\u3002",feat_building:"\u6784\u5EFA\u4E2D\u2026",feat_cache_remove_failed:"\u5931\u8D25\uFF1A{0}",feat_cache_removed:"\u6A21\u578B\u7F13\u5B58\u5DF2\u6E05\u9664\u3002",feat_checking:"\u68C0\u6D4B\u4E2D\u2026",feat_checking_btn:"\u68C0\u6D4B\u4E2D\u2026",feat_deps_checking:"\u6B63\u5728\u68C0\u6D4B\u4F9D\u8D56\u2026",feat_deps_missing:"\u4F9D\u8D56\u672A\u5B89\u88C5\u3002\u9700\u8981\uFF1Achromadb, openai\u3002",feat_enter_key:"\u8BF7\u8F93\u5165\u6709\u6548\u7684 OpenAI API Key\u3002",feat_install_btn:"\u5B89\u88C5",feat_install_deps:"\u5B89\u88C5\u4F9D\u8D56",feat_install_done:"\u4F9D\u8D56\u5DF2\u5B89\u88C5\u3002\u6B63\u5728\u6784\u5EFA\u5411\u91CF\u2026",feat_install_failed:"\u5B89\u88C5\u5931\u8D25\uFF1A",feat_installing:"\u5B89\u88C5\u4E2D\u2026",feat_installing_pkgs:"\u6B63\u5728\u5B89\u88C5 {pkgs}...",feat_key_rejected:"API Key \u88AB\u62D2\u7EDD\u3002",feat_memory_desc:"\u8BB0\u5FC6\u5C42\u662F PaperForge \u7684\u6838\u5FC3\u6570\u636E\u5F15\u64CE\uFF0C\u57FA\u4E8E SQLite \u6784\u5EFA\u3002\u5B83\u6574\u5408\u4E86\u6587\u732E\u5143\u6570\u636E\uFF08\u8BBA\u6587\u3001\u8D44\u6E90\u6587\u4EF6\u3001\u522B\u540D\u3001\u9605\u8BFB\u4E8B\u4EF6\uFF09\uFF0C\u652F\u6301 FTS5 \u5143\u6570\u636E\u68C0\u7D22\uFF08\u6807\u9898\u3001\u6458\u8981\u3001\u4F5C\u8005\u3001domain\u3001collection\uFF09\uFF0C\u5E76\u4E3A agent-context \u548C paper-status \u547D\u4EE4\u63D0\u4F9B\u6570\u636E\u652F\u6491\u3002\u59CB\u7EC8\u8FD0\u884C\uFF0C\u65E0\u9700\u624B\u52A8\u5F00\u542F\u3002",feat_memory_rebuild_btn:"\u91CD\u5EFA\u6570\u636E\u5E93",feat_memory_rebuild_done:"\u8BB0\u5FC6\u6570\u636E\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002",feat_memory_rebuild_failed:"\u91CD\u5EFA\u5931\u8D25\u3002",feat_memory_rebuilding:"\u91CD\u5EFA\u4E2D\u2026",feat_model:"\u6A21\u578B",feat_model_changed_warn:"\u6A21\u578B\u5DF2\u66F4\u6362\uFF08{0} -> {1}\uFF09\u3002\u5DF2\u6709\u5411\u91CF\u4E0D\u517C\u5BB9\u2014\u2014\u9700\u8981\u91CD\u5EFA\u3002",feat_network_error:"\u7F51\u7EDC\u9519\u8BEF\uFF1A",feat_no_python:"\u672A\u627E\u5230 Python\u3002\u8BF7\u67E5\u770B\u5B89\u88C5\u6807\u7B7E\u9875\u3002",feat_not_cached:"\u672A\u7F13\u5B58",feat_openai_key:"OpenAI API Key",feat_openai_key_desc:"\u7528\u4E8E API \u5D4C\u5165\u8C03\u7528\uFF0C\u6A21\u578B\u5728\u4E0B\u65B9\u5B9A\u4E49\u3002",feat_output_copied:"\u8F93\u51FA\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F\u3002",feat_rebuild_btn:"\u91CD\u5EFA",feat_rebuild_vectors:"\u91CD\u5EFA\u5411\u91CF",feat_rebuild_vectors_changed:"\u6A21\u578B\u5DF2\u66F4\u6362 \u2014 \u9700\u8981\u91CD\u5EFA\u5411\u91CF\u3002",feat_rebuild_vectors_desc:"\u91CD\u5EFA\u6240\u6709 OCR \u5168\u6587\u5411\u91CF\u3002\u66F4\u6362\u6A21\u578B\u6216\u6A21\u5F0F\u540E\u9700\u8981\u91CD\u5EFA\u3002",feat_removing:"\u5220\u9664\u4E2D\u2026",feat_retry_btn:"\u91CD\u8BD5",feat_skills_desc:"\u7BA1\u7406 Vault \u4E2D\u5DF2\u5B89\u88C5\u7684 Agent \u6280\u80FD\u3002\u6BCF\u884C\u5BF9\u5E94\u4E00\u4E2A SKILL.md \u6587\u4EF6\uFF0C\u5173\u95ED\u5F00\u5173\u53EF\u963B\u6B62 Agent \u81EA\u52A8\u8C03\u7528\u8BE5\u6280\u80FD\u3002",feat_skills_system:"\u7CFB\u7EDF\u6280\u80FD\u968F PaperForge \u4E00\u540C\u53D1\u5E03\uFF0C\u4F1A\u8DDF\u968F PaperForge \u7248\u672C\u66F4\u65B0\u3002",feat_skills_user:"\u7528\u6237\u6280\u80FD\u662F\u4F60\u81EA\u884C\u5B89\u88C5\u6216\u521B\u5EFA\u7684\u81EA\u5B9A\u4E49\u6280\u80FD\u3002",feat_uninstall_btn:"\u5378\u8F7D",feat_valid_key:"API Key \u6709\u6548\u3002",feat_vector_config_label:"\u5411\u91CF\u5E93\u914D\u7F6E",feat_vector_corrupted:"\u5411\u91CF\u7D22\u5F15\u5DF2\u635F\u574F \u2014 \u9700\u8981\u5F3A\u5236\u91CD\u5EFA\u3002",feat_vector_desc:"\u5411\u91CF\u6570\u636E\u5E93\u901A\u8FC7\u5D4C\u5165\u6A21\u578B\u5B9E\u73B0 OCR \u5168\u6587\u7684\u8BED\u4E49\u641C\u7D22\u3002\u6587\u6863\u88AB\u5207\u5206\u4E3A\u6587\u672C\u5757\uFF08chunk\uFF09\uFF0C\u7F16\u7801\u4E3A\u5411\u91CF\u5B58\u5165 ChromaDB\u3002\u652F\u6301\u672C\u5730\u6A21\u578B\uFF08\u514D\u8D39\uFF0CCPU \u8FD0\u884C\uFF09\u6216 OpenAI API\uFF08\u4ED8\u8D39\uFF0C\u66F4\u5FEB\u901F\uFF09\u3002",feat_vector_enable:"\u542F\u7528\u5411\u91CF\u68C0\u7D22",feat_vector_enable_desc:"\u5BF9 OCR \u5168\u6587\u8FDB\u884C\u8BED\u4E49\u641C\u7D22\u3002\u9700\u5B89\u88C5: pip install chromadb sentence-transformers openai (~500MB)\u3002",feat_vector_rebuild_force_btn:"\u5F3A\u5236\u91CD\u5EFA",feat_verify:"\u9A8C\u8BC1",feat_verify_btn:"\u9A8C\u8BC1",field_paddleocr:"PaddleOCR API \u5BC6\u94A5",field_python_custom:"\u81EA\u5B9A\u4E49 Python \u8DEF\u5F84",field_python_interp:"\u5F53\u524D Python \u89E3\u91CA\u5668",field_zotero_data:"Zotero \u6570\u636E\u76EE\u5F55",field_zotero_placeholder:"\u53EF\u9009\uFF0C\u7528\u4E8E\u81EA\u52A8\u68C0\u6D4B PDF",guide_ocr:"\u8FD0\u884C OCR",guide_ocr_desc:"Dashboard \u4E2D\u70B9 Run OCR\uFF0C\u63D0\u53D6 PDF \u5168\u6587\u4E0E\u56FE\u8868",guide_open:"\u6253\u5F00 Dashboard",guide_open_desc:"Ctrl+P \u2192 \u8F93\u5165 PaperForge: Open Dashboard\uFF0C\u6216\u70B9\u5DE6\u4FA7\u4E66\u672C\u56FE\u6807",guide_sync:"\u540C\u6B65\u6587\u732E",guide_sync_desc:"Dashboard \u4E2D\u70B9 Sync Library\uFF0C\u4ECE Zotero \u62C9\u53D6\u6587\u732E\u751F\u6210\u7B14\u8BB0",header_title:"PaperForge",install_bootstrapping:"\u672A\u68C0\u6D4B\u5230 PaperForge Python \u5305\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5\u2026",install_btn:"\u5F00\u59CB\u5B89\u88C5",install_btn_retry:"\u91CD\u8BD5",install_btn_running:"\u6B63\u5728\u5B89\u88C5...",install_complete:"\u2713 \u5B89\u88C5\u5B8C\u6210\uFF01",install_failed:"\u2717 \u5B89\u88C5\u5931\u8D25\uFF1A",install_validating:"\u6B63\u5728\u6821\u9A8C\u5B89\u88C5\u73AF\u5883\u2026",jump_to_deep_reading:"\u8DF3\u8F6C\u5230\u7CBE\u8BFB",label_agent:"Agent \u5E73\u53F0",nav_close:"\u5173\u95ED",nav_next:"\u4E0B\u4E00\u6B65 \u2192",nav_prev:"\u2190 \u4E0A\u4E00\u6B65",no_pending_ocr:"\u6240\u6709 OCR \u4EFB\u52A1\u5DF2\u5B8C\u6210",not_set:"\u672A\u8BBE\u7F6E",notice_check_fail:"\u672A\u901A\u8FC7: ",notice_python_missing:"Python \u672A\u68C0\u6D4B\u5230\uFF0C\u8BF7\u5148\u5B89\u88C5 Python 3.10+ \u5E76\u52A0\u5165 PATH",ocr_privacy_title:"OCR \u9690\u79C1\u63D0\u793A",ocr_privacy_warning:"OCR \u4F1A\u5C06 PDF \u4E0A\u4F20\u5230 PaddleOCR API \u8FDB\u884C\u5904\u7406\u3002\u8BF7\u4E0D\u8981\u4E0A\u4F20\u5305\u542B\u654F\u611F\u4FE1\u606F\u6216\u65E0\u6CD5\u5916\u4F20\u7684\u6587\u732E\u3002",ocr_queue_add:"\u52A0\u5165 OCR \u961F\u5217",ocr_queue_added:"\u5DF2\u52A0\u5165 OCR \u961F\u5217",ocr_queue_remove:"\u79FB\u51FA OCR \u961F\u5217",ocr_queue_removed:"\u5DF2\u79FB\u51FA OCR \u961F\u5217",ocr_understand:"\u6211\u4E86\u89E3\uFF0C\u7EE7\u7EED",optional_later:"\uFF08\u7A0D\u540E\u53EF\u5728\u8BBE\u7F6E\u4E2D\u8865\u5145\uFF09",orphan_delete_failed:"\u6E05\u7406\u5931\u8D25",orphan_delete_selected:"\u5220\u9664 {count} \u7BC7",orphan_deleted:"\u5DF2\u5220\u9664 {count} \u7BC7\u6B8B\u7559\u6587\u732E",orphan_desc:"\u8FD9\u4E9B\u6587\u732E\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002",orphan_deselect_all:"\u53D6\u6D88\u5168\u9009",orphan_explain:"\u5DF2\u4ECE Zotero \u4E2D\u79FB\u9664\u3002\u5DE5\u4F5C\u533A\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u78C1\u76D8\u4E0A\u3002",orphan_keep_all:"\u4FDD\u7559\u5168\u90E8",orphan_none_selected:"\u672A\u9009\u62E9\u4EFB\u4F55\u6587\u732E",orphan_select_all:"\u5168\u9009",orphan_title:"\u53D1\u73B0 {count} \u7BC7\u6B8B\u7559\u6587\u732E",panel_actions:"\u5FEB\u6377\u64CD\u4F5C",prep_bbt:"Better BibTeX",prep_bbt_desc:"Zotero \u2192 \u5DE5\u5177 \u2192 \u63D2\u4EF6 \u2192 \u5B89\u88C5 Better BibTeX",prep_export:"BBT \u81EA\u52A8\u5BFC\u51FA",prep_export_desc:"\u53F3\u952E\u6587\u732E\u5B50\u5206\u7C7B \u2192 \u5BFC\u51FA\u5206\u7C7B \u2192 BetterBibTeX JSON \u2192 \u52FE\u9009\u4FDD\u6301\u66F4\u65B0 \u2192 \u5BFC\u51FA\u5230\uFF08JSON \u6587\u4EF6\u540D\u5373\u4E3A Base \u540D\uFF09\uFF1A",prep_key:"PaddleOCR Key",prep_key_desc:"\u5728 https://aistudio.baidu.com/paddleocr \u83B7\u53D6 API Key",prep_python:"Python 3.10+",prep_python_desc:"\u786E\u4FDD Python \u53EF\u547D\u4EE4\u884C\u8C03\u7528\u3002\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u81EA\u52A8\u68C0\u6D4B\u3002",prep_zotero:"Zotero \u684C\u9762\u7248",prep_zotero_desc:"\u5B89\u88C5 Zotero (https://www.zotero.org)",run_in_agent:"\u5728 {0} \u4E2D\u8FD0\u884C",runtime_health:"\u8FD0\u884C\u65F6\u72B6\u6001",runtime_health_checking:"\u6B63\u5728\u68C0\u6D4B\u2026",runtime_health_desc:"\u68C0\u67E5\u63D2\u4EF6\u4E0E Python \u8FD0\u884C\u65F6\u7248\u672C\u7684\u5339\u914D\u60C5\u51B5\uFF0C\u5E76\u786E\u8BA4\u5DF2\u90E8\u7F72\u7684 skill contract \u662F\u5426\u4E3A\u5F53\u524D\u7248\u672C\u3002",runtime_health_match:"\u5339\u914D",runtime_health_mismatch:"\u4E0D\u5339\u914D",runtime_health_package_ver:"Python \u5305 v{0}",runtime_health_plugin_ver:"\u63D2\u4EF6 v{0}",runtime_health_sync:"\u540C\u6B65\u8FD0\u884C\u65F6",runtime_health_sync_done:"\u8FD0\u884C\u65F6\u5DF2\u540C\u6B65\u81F3 v{0}",runtime_health_sync_fail:"\u8FD0\u884C\u65F6\u540C\u6B65\u5931\u8D25\uFF1A{0}",runtime_health_syncing:"\u6B63\u5728\u540C\u6B65\u2026",section_config:"\u5F53\u524D\u914D\u7F6E",section_guide:"\u64CD\u4F5C\u65B9\u5F0F",section_prep:"\u5B89\u88C5\u51C6\u5907",section_prep_desc:"\u9996\u6B21\u4F7F\u7528\u524D\uFF0C\u8BF7\u4F9D\u6B21\u5B8C\u6210\u4EE5\u4E0B\u51C6\u5907\uFF1A",setup_done:"\u2713 PaperForge \u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u6210",setup_pending:"\u5C1A\u672A\u5B89\u88C5\uFF0C\u5B8C\u6210\u5B89\u88C5\u51C6\u5907\u540E\u70B9\u51FB\u5B89\u88C5\u5411\u5BFC",tab_features:"\u529F\u80FD",tab_setup:"\u5B89\u88C5",tab_maintenance:"\u7EF4\u62A4",validate_base:"Base \u76EE\u5F55\u672A\u586B\u5199",validate_fail:"\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25",validate_index:"\u7D22\u5F15\u76EE\u5F55\u672A\u586B\u5199",validate_key:"PaddleOCR API \u5BC6\u94A5\u672A\u586B\u5199",validate_notes:"\u6B63\u6587\u76EE\u5F55\u672A\u586B\u5199",validate_resources:"\u8D44\u6E90\u76EE\u5F55\u672A\u586B\u5199",validate_system:"\u7CFB\u7EDF\u76EE\u5F55\u672A\u586B\u5199",validate_vault:"Vault \u8DEF\u5F84\u672A\u586B\u5199",validate_zotero:"Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879",wizard_agent_hint:"\u9009\u62E9\u4F60\u4F7F\u7528\u7684 AI Agent \u5E73\u53F0\uFF0C\u5B89\u88C5\u65F6\u5C06\u6309\u5BF9\u5E94\u683C\u5F0F\u90E8\u7F72\u6280\u80FD\u6587\u4EF6\uFF1A",wizard_dir_hint:"\u8D44\u6E90\u76EE\u5F55\u662F\u6587\u732E\u6570\u636E\u7684\u7EDF\u4E00\u6839\u76EE\u5F55\uFF0C\u4EE5\u4E0B\u5B50\u76EE\u5F55\u5C06\u521B\u5EFA\u5728\u5176\u5185\u90E8\uFF1A",wizard_dir_sub_hint:"\u8D44\u6E90\u76EE\u5F55\u5185\u7684\u4E24\u4E2A\u5B50\u76EE\u5F55\uFF1A",wizard_intro:"\u672C\u5411\u5BFC\u5C06\u5F15\u5BFC\u60A8\u5B8C\u6210 PaperForge \u73AF\u5883\u7684\u5B8C\u6574\u914D\u7F6E\u3002\u5B89\u88C5\u8FC7\u7A0B\u4F1A\u81EA\u52A8\u521B\u5EFA\u6240\u6709\u76EE\u5F55\u7ED3\u6784\uFF0C\u65E0\u9700\u624B\u52A8\u64CD\u4F5C\u3002",wizard_keys_hint:"\u4EE5\u4E0B\u4E3A API \u5BC6\u94A5\u4E0E Zotero \u914D\u7F6E\uFF1A",wizard_preview:"\u7CFB\u7EDF\u6587\u4EF6\u548C Agent \u914D\u7F6E\u4F4D\u4E8E Vault \u6839\u76EE\u5F55\u4E0B\u3002\u6587\u732E\u6570\u636E\uFF08\u6B63\u6587\u3001\u7D22\u5F15\uFF09\u7EDF\u4E00\u5B58\u653E\u5728\u8D44\u6E90\u76EE\u5F55\u5185\u3002\u5B89\u88C5\u540E\u4ECD\u53EF\u5728\u8BBE\u7F6E\u4E2D\u4FEE\u6539\u3002",wizard_safety:"\u5B89\u5168\u8BF4\u660E\uFF1A\u5982\u679C\u4F60\u9009\u62E9\u7684\u76EE\u5F55\u91CC\u5DF2\u7ECF\u6709\u6587\u4EF6\uFF0C\u5B89\u88C5\u5411\u5BFC\u4F1A\u4FDD\u7559\u5DF2\u6709\u5185\u5BB9\uFF0C\u53EA\u8865\u5145\u7F3A\u5931\u7684 PaperForge \u6587\u4EF6\u548C\u76EE\u5F55\u3002",wizard_step1:"\u6982\u89C8",wizard_step2:"\u76EE\u5F55",wizard_step3:"Agent",wizard_step4:"\u5B89\u88C5",wizard_step5:"\u5B8C\u6210",wizard_skip_ocr_desc:"OCR \u529F\u80FD\u5728\u914D\u7F6E\u6709\u6548\u7684 PaddleOCR API \u5BC6\u94A5\u4E4B\u524D\u4E0D\u53EF\u7528\u3002\u60A8\u53EF\u4EE5\u7EE7\u7EED\u5B8C\u6210\u8BBE\u7F6E\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002",wizard_skip_ocr_continue:"\u7EE7\u7EED\uFF0C\u7A0D\u540E\u914D\u7F6E\u5BC6\u94A5",wizard_skip_ocr_back:"\u8FD4\u56DE\u914D\u7F6E",wizard_api_hint_skip:"OCR \u5BC6\u94A5\u4E3A\u9009\u586B\u9879 \u2014 \u53EF\u8DF3\u8FC7\uFF0C\u7A0D\u540E\u5728\u8BBE\u7F6E\u4E2D\u914D\u7F6E\u3002",wizard_sys_hint:"\u72EC\u7ACB\u4E8E\u8D44\u6E90\u76EE\u5F55\u7684\u7CFB\u7EDF\u6587\u4EF6\uFF1A",wizard_title:"PaperForge \u5B89\u88C5\u5411\u5BFC",ocr_maint_no_action:"\u65E0\u9700\u5904\u7406",ocr_maint_rebuild:"\u5EFA\u8BAE\u91CD\u5EFA",ocr_maint_failed:"OCR \u5931\u8D25",ocr_maint_limited:"\u7ED3\u679C\u4E00\u822C",ocr_maint_needs_attention:"\u9700\u8981\u5904\u7406",ocr_maint_limitations:"\u7ED3\u679C\u8BF4\u660E",ocr_maint_hero_ok:"OCR \u6574\u4F53\u6B63\u5E38\u3002",ocr_maint_hero_warn:"OCR \u9700\u8981\u5173\u6CE8\uFF1A{rebuild} \u7BC7\u5EFA\u8BAE\u91CD\u5EFA\uFF0C{failed} \u7BC7\u5904\u7406\u5931\u8D25\u3002",ocr_maint_hero_note:"\u672C\u9875\u53EA\u63D0\u793A\u7EF4\u62A4\u540E\u5927\u6982\u7387\u4F1A\u6539\u5584\u7684\u95EE\u9898\u3002\u90E8\u5206\u8BBA\u6587\u6548\u679C\u4E00\u822C\uFF0C\u7EF4\u62A4\u672A\u5FC5\u80FD\u6539\u5584\u3002",ocr_maint_limitations_intro:"\u8FD9\u7C7B\u8BBA\u6587\u901A\u5E38\u8868\u793A\u7248\u5F0F\u590D\u6742\u6216\u4FE1\u53F7\u504F\u5F31\uFF0CPaperForge \u76EE\u524D\u6CA1\u6709\u9AD8\u7F6E\u4FE1\u5EA6\u7684\u7EF4\u62A4\u5EFA\u8BAE\u3002",ocr_maint_all_papers:"\u5168\u90E8\u8BBA\u6587",ocr_maint_rebuild_btn:"\u91CD\u5EFA\u7ED3\u679C",maintenance_group_retry:"\u9700\u8981\u91CD\u8BD5",maintenance_group_rebuild:"\u53EF\u91CD\u5EFA\u7ED3\u679C",maintenance_group_legacy:"\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09",maintenance_btn_retry:"\u91CD\u8BD5",maintenance_btn_rebuild:"\u91CD\u5EFA",maintenance_btn_upgrade:"\u5347\u7EA7",maintenance_refresh_spinning:"\u6B63\u5728\u66F4\u65B0\u2026",maintenance_all_good:"\u2705 \u5168\u90E8\u6B63\u5E38",maintenance_n_pending:"{n} \u7BC7\u9700\u8981\u5904\u7406",version_panel_title:"\u7248\u672C\u5386\u53F2",version_panel_back:"\u8FD4\u56DE",version_filter_placeholder:"\u641C\u7D22\u8BBA\u6587...",version_papers_count:"{n} \u7BC7\u8BBA\u6587",version_current:"\u5F53\u524D",version_restore_btn:"\u6062\u590D",version_compare_btn:"\u5BF9\u6BD4",version_restore_selected:"\u6062\u590D\u9009\u4E2D\u7248\u672C",version_clear_old:"\u6E05\u9664\u65E7\u7248\u672C (\u91CA\u653E {size})",version_no_backups:"\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5386\u53F2\u7248\u672C",version_restore_confirm:"\u786E\u8BA4\u5C06 {paper} \u6062\u590D\u5230 {label}\uFF1F",version_restore_done:"\u5DF2\u6062\u590D\u5230 {label}",version_compare_title:"{vA} vs {vB}",version_compare_paragraphs:"{n} \u6BB5\u6709\u53D8\u5316",version_error_read:"\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C\u6570\u636E",retrieval_search_placeholder:"\u641C\u7D22\u8BBA\u6587... (@ \u8FDB\u884C\u6DF1\u5EA6\u641C\u7D22)",retrieval_search_placeholder_deep:"\u901A\u8FC7\u6DF1\u5EA6\u68C0\u7D22\u641C\u7D22\u8BBA\u6587...",retrieval_search_idle_hint:"\u8F93\u5165\u5173\u952E\u5B57\u641C\u7D22\u5143\u6570\u636E\uFF0C\u6216\u4EE5 @ \u5F00\u5934\u8FDB\u884C\u6DF1\u5EA6\u8BED\u4E49\u641C\u7D22",retrieval_searching_metadata:"\u6B63\u5728\u641C\u7D22\u5143\u6570\u636E...",retrieval_searching_deep:"\u6B63\u5728\u8FD0\u884C\u6DF1\u5EA6\u641C\u7D22...",retrieval_search_cancel:"\u53D6\u6D88",retrieval_results_count:"\u627E\u5230 {n} \u6761\u7ED3\u679C",retrieval_empty:"\u672A\u627E\u5230\u5339\u914D\u7684\u8BBA\u6587\u3002",retrieval_empty_tips:"\u5C1D\u8BD5\u66F4\u5BBD\u6CDB\u7684\u5173\u952E\u8BCD\uFF0C\u6216\u4F7F\u7528 @ \u8FDB\u884C\u6DF1\u5EA6\u641C\u7D22\u3002",retrieval_vectors_not_built:"\u5411\u91CF\u7D22\u5F15\u672A\u6784\u5EFA",retrieval_vectors_not_built_desc:"\u5411\u91CF\u7D22\u5F15\u5C1A\u672A\u6784\u5EFA\uFF0C\u641C\u7D22\u9700\u8981\u5148\u6784\u5EFA\u5411\u91CF\u7D22\u5F15\u3002",retrieval_open_vector_settings:"\u6253\u5F00\u5411\u91CF\u8BBE\u7F6E",retrieval_backend_unavailable:"\u540E\u7AEF\u4E0D\u53EF\u7528",retrieval_backend_unavailable_desc:"Python CLI \u641C\u7D22\u540E\u7AEF\u65E0\u54CD\u5E94\u3002",retrieval_run_doctor:"\u8FD0\u884C\u8BCA\u65AD",retrieval_retry:"\u91CD\u8BD5",retrieval_timeout_title:"\u641C\u7D22\u8D85\u65F6",retrieval_timeout_desc:"\u641C\u7D22\u8017\u65F6\u8FC7\u957F\u3002\u4F60\u53EF\u4EE5\u91CD\u8BD5\uFF0C\u6216\u5C1D\u8BD5\u7B80\u5316\u67E5\u8BE2\u3002",retrieval_model_changed:"\u6A21\u578B\u5DF2\u66F4\u6362",retrieval_model_changed_desc:"\u5D4C\u5165\u6A21\u578B\u5DF2\u66F4\u6362\uFF0C\u9700\u8981\u91CD\u5EFA\u5411\u91CF\u3002",retrieval_rebuild_vectors:"\u91CD\u5EFA\u5411\u91CF",retrieval_internal_error:"\u53D1\u751F\u5185\u90E8\u9519\u8BEF\u3002\u8BF7\u67E5\u770B\u63A7\u5236\u53F0\u4E86\u89E3\u8BE6\u60C5\u3002",retrieval_build_idle:"\u5411\u91CF\u7D22\u5F15\u5C1A\u672A\u6784\u5EFA",retrieval_build_ready:"\u5411\u91CF\u7D22\u5F15\u5C31\u7EEA",retrieval_build_stopping:"\u6B63\u5728\u505C\u6B62\u2026",retrieval_build_stopped:"\u6784\u5EFA\u5DF2\u505C\u6B62\u3002\u70B9\u51FB\u7EE7\u7EED\u4EE5\u6062\u590D\u3002",retrieval_build_failed:"\u6784\u5EFA\u5931\u8D25",retrieval_build_stale:"\u4E0A\u6B21\u6784\u5EFA\u88AB\u4E2D\u65AD\u3002\u70B9\u51FB\u7EE7\u7EED\u4EE5\u6062\u590D\u3002",retrieval_build_deps_missing:"\u4F9D\u8D56\u672A\u5B89\u88C5",retrieval_build_runtime_mismatch:"\u63D2\u4EF6\u4E0E CLI \u7248\u672C\u4E0D\u5339\u914D",retrieval_stop:"\u505C\u6B62",retrieval_force_rebuild:"\u5F3A\u5236\u91CD\u5EFA",retrieval_rebuild_warning:"\u91CD\u5EFA\u5C06\u66FF\u6362 {n} \u4E2A\u5DF2\u6709\u7684 chunk\u3002\u662F\u5426\u7EE7\u7EED\uFF1F",retrieval_no_python:"\u672A\u627E\u5230 Python\u3002\u8BF7\u67E5\u770B\u5B89\u88C5\u6807\u7B7E\u9875\u3002"}},Ue=null;function jt(u){try{let h=u.vault;if(typeof h.getConfig=="function"){let e=h.getConfig("language");if(e&&String(e).startsWith("zh"))return"zh"}}catch(h){}try{if(typeof localStorage!="undefined"){let h=localStorage.getItem("language");if(h&&String(h).startsWith("zh"))return"zh"}}catch(h){}return"en"}function lt(u){Ue=jt(u)==="zh"?qe.zh:qe.en}function o(u){return Ue&&Ue[u]||qe.en[u]||u}var R=require("obsidian"),$=V(require("fs")),X=V(require("path")),St=V(require("os")),K=require("child_process");var Pt=V(Je());var le=V(require("fs")),oe=V(require("path")),pt=V(require("os")),de=require("child_process"),Ge=null,ct=!1;function N(u,h,e,t){let r=e||le,n=t||de.execFileSync;if(h&&h.python_path&&h.python_path.trim()){let i=h.python_path.trim();if(r.existsSync(i))return{path:i,source:"manual",extraArgs:[]}}let a=[oe.join(u,".paperforge-test-venv","Scripts","python.exe"),oe.join(u,".venv","Scripts","python.exe"),oe.join(u,"venv","Scripts","python.exe")];for(let i of a)try{if(r.existsSync(i))return{path:i,source:"auto-detected",extraArgs:[]}}catch(l){}let s=[{path:"py",extraArgs:["-3"]},{path:"python",extraArgs:[]},{path:"python3",extraArgs:[]}];for(let i of s)try{let l=n(i.path,[...i.extraArgs,"--version"],{encoding:"utf-8",timeout:5e3,windowsHide:!0});if(l&&l.toLowerCase().includes("python"))return{path:i.path,source:"auto-detected",extraArgs:i.extraArgs}}catch(l){}return{path:"python",source:"auto-detected",extraArgs:[]}}function dt(u,h,e,t,r){t===void 0&&(t=1e4);let n=r||de.execFile;return new Promise(a=>{n(u,["-c","import paperforge; print(paperforge.__version__)"],{cwd:e,timeout:t},(s,i)=>{if(s){a({status:"not-installed",pyVersion:null,pluginVersion:h,error:s.message});return}let l=i&&i.trim()||null;a(l===h?{status:"match",pyVersion:l,pluginVersion:h,error:null}:{status:"mismatch",pyVersion:l,pluginVersion:h,error:null})})})}function Xe(u){let h=String(u),t={ENOENT:{type:"python_missing",message:"Python executable not found",recoverable:!0},"python-missing":{type:"python_missing",message:"Python executable not found",recoverable:!0},MODULE_NOT_FOUND:{type:"import_failed",message:"PaperForge package not installed",recoverable:!0},"import-failed":{type:"import_failed",message:"PaperForge package not installed",recoverable:!0},"version-mismatch":{type:"version_mismatch",message:"Plugin and package versions differ",recoverable:!0,action:"sync-runtime"},"pip-failed":{type:"pip_install_failure",message:"pip install command failed",recoverable:!0},ETIMEDOUT:{type:"timeout",message:"Subprocess timed out",recoverable:!0,action:"retry"},timeout:{type:"timeout",message:"Subprocess timed out",recoverable:!0,action:"retry"},NO_PYTHON:{type:"no_python",message:"Python executable not found",recoverable:!0,action:"open-setup"},VECTOR_NOT_BUILT:{type:"vectors_not_built",message:"Vector index has not been built yet",recoverable:!0,action:"open-vector-settings"},VECTOR_CORRUPTED:{type:"vectors_corrupted",message:"Vector index is corrupted",recoverable:!0,action:"force-rebuild"},MODEL_CHANGED:{type:"model_changed",message:"Embedding model has changed since vectors were built",recoverable:!0,action:"rebuild-vectors"},BACKEND_UNAVAILABLE:{type:"backend_unavailable",message:"Python CLI search backend is not responding",recoverable:!0,action:"run-doctor"},TIMEOUT:{type:"timeout",message:"Search timed out",recoverable:!0,action:"retry"},INTERNAL_ERROR:{type:"internal_error",message:"An internal error occurred",recoverable:!1}}[h];return t?{...t}:{type:"unknown",message:String(u),recoverable:!1}}function ut(u,h,e){e===void 0&&(e=[]);let t=`paperforge==${h}`,r=`git+https://github.com/LLLin000/PaperForge.git@${h}`,n=[...e,"-m","pip","install","--upgrade",t],a=[...e,"-m","pip","install","--upgrade",r];return{cmd:u,url:r,args:a,pypiArgs:n,gitArgs:a,timeout:12e4}}function ht(u,h,e,t,r,n){let a=r||de.spawn;return new Promise(s=>{let i=Date.now(),l={cwd:e,timeout:t,windowsHide:!0};n&&(l.env=n);let c=a(u,h,l),d=[],f=[];c.stdout.on("data",p=>{d.push(p.toString("utf-8"))}),c.stderr.on("data",p=>{f.push(p.toString("utf-8"))}),c.on("close",p=>{s({stdout:d.join(""),stderr:f.join(""),exitCode:p,elapsed:Date.now()-i})}),c.on("error",p=>{s({stdout:d.join(""),stderr:f.join("")+` +`+p.message,exitCode:-1,elapsed:Date.now()-i})})})}function Ye(){if(ct)return Ge;ct=!0;try{let u;if(process.platform==="win32"){let h=process.env.ComSpec||"C:\\Windows\\System32\\cmd.exe";u=(0,de.execFileSync)(h,["/c","where","git"],{timeout:5e3,windowsHide:!0,encoding:"utf-8"})}else u=(0,de.execFileSync)("which",["git"],{timeout:5e3,encoding:"utf-8"});if(u){let h=u.split(` +`)[0].trim();h&&(Ge=oe.dirname(h))}}catch(u){}return Ge}function be(){let u={...process.env},h=process.platform,e=pt.homedir(),t=[],r=Ye();r&&t.push(r),h==="darwin"?t.push("/opt/homebrew/bin","/usr/local/bin","/usr/bin",`${e}/.local/bin`):h==="linux"&&t.push("/usr/local/bin","/usr/bin",`${e}/.local/bin`);let n=u.PATH||"";return u.PATH=[...t,n].filter(Boolean).join(oe.delimiter),u}function _t(u){return String(u).toLowerCase().replace(/[^a-z0-9]/g,"").includes("betterbibtex")}function Qe(u){if(!u)return!1;try{if(!le.existsSync(u))return!1;for(let h of le.readdirSync(u))if(_t(h))return!0}catch(h){}return!1}function Me(u){if(!u)return!1;try{if(!le.existsSync(u))return!1;for(let h of le.readdirSync(u)){let e=oe.join(u,h,"extensions");try{if(!le.existsSync(e))continue;for(let t of le.readdirSync(e))if(_t(t))return!0}catch(t){}}}catch(h){}return!1}var ge=V(require("fs")),H=V(require("path")),et=require("child_process"),ce=null;function $t(u,h){let e=h||ge,t=H.join(u,"paperforge.json"),r={system_dir:"System",resources_dir:"Resources",literature_dir:"Literature",base_dir:"Bases"};try{if(!e.existsSync(t))return{...r,_warning:"paperforge.json not found; using defaults"};let n=e.readFileSync(t,"utf-8"),a=JSON.parse(n),s=a.vault_config||{};return{system_dir:s.system_dir||a.system_dir||r.system_dir,resources_dir:s.resources_dir||a.resources_dir||r.resources_dir,literature_dir:s.literature_dir||a.literature_dir||r.literature_dir,base_dir:s.base_dir||a.base_dir||r.base_dir,_warning:null}}catch(n){return console.warn("PaperForge: Failed to read paperforge.json, using defaults",n),{...r,_warning:"paperforge.json invalid; using defaults"}}}function ne(u,h){let e=$t(u,h),t=H.join(u,e.system_dir,"PaperForge");return{vault:u,systemDir:t,indexesDir:H.join(t,"indexes"),logsDir:H.join(t,"logs"),dbPath:H.join(t,"indexes","paperforge.db"),memoryStatePath:H.join(t,"indexes","memory-runtime-state.json"),vectorStatePath:H.join(t,"indexes","vector-runtime-state.json"),healthStatePath:H.join(t,"indexes","runtime-health.json"),buildStatePath:H.join(t,"indexes","vector-build-state.json"),orphanStatePath:H.join(t,"indexes","sync-orphan-state.json"),exportsDir:H.join(t,"exports"),ocrDir:H.join(t,"ocr"),pluginDataPath:H.join(u,".obsidian","plugins","paperforge","data.json"),pfJsonPath:H.join(u,"paperforge.json"),configWarning:e._warning}}function tt(u){try{return ge.existsSync(u)?JSON.parse(ge.readFileSync(u,"utf-8")):null}catch(h){return null}}function Vt(u){let h=ne(u);return tt(h.memoryStatePath)}var xe=null;function Ne(u){let h=ne(u),e=Date.now();if(xe&&xe.vaultPath===u&&e-xe.ts<2e3)return xe.result;let t="",r=[H.join(u,".paperforge-test-venv","Scripts","python.exe"),H.join(u,".venv","Scripts","python.exe"),H.join(u,"venv","Scripts","python.exe")];for(let a=0;a({...a,_selected:!0,_idx:s})),this.vaultPath=r,this.py=n}_updateUI(){let e=this.orphans.filter(t=>t._selected);this._countEl.setText(o("orphan_delete_selected").replace("{count}",String(e.length))),this._selectAllBtn.setText(e.length===this.orphans.length?o("orphan_deselect_all"):o("orphan_select_all"));for(let t of this.orphans){let r=this._rowEls[t._idx];r&&r.toggleClass("paperforge-orphan-dimmed",!t._selected)}}onOpen(){let{contentEl:e}=this;e.addClass("paperforge-modal"),e.createEl("h2",{text:o("orphan_title").replace("{count}",String(this.orphans.length))}),e.createEl("p",{cls:"paperforge-modal-desc",text:o("orphan_desc")}),this._rowEls=[];let t=e.createEl("div",{cls:"paperforge-orphan-list"});for(let n of this.orphans){let a=t.createEl("div",{cls:"paperforge-orphan-row"+(n._selected?"":" paperforge-orphan-dimmed")});this._rowEls.push(a);let s=a.createEl("div",{cls:"paperforge-orphan-info"}),i=s.createEl("div",{cls:"paperforge-orphan-header"});i.createEl("span",{cls:"paperforge-orphan-key",text:n.citation_key||n.key});let l=i.createEl("span",{cls:"paperforge-orphan-tags"});l.createEl("span",{cls:"paperforge-tag "+(n.has_pdf?"tag-pdf":"tag-nopdf"),text:n.has_pdf?"PDF":"no PDF"}),n.collection_path&&l.createEl("span",{cls:"paperforge-tag tag-collection",text:n.collection_path}),n.title&&s.createEl("div",{cls:"paperforge-orphan-title",text:n.title});let c=[];n.authors&&c.push(n.authors),n.year&&c.push(n.year),c.length>0&&s.createEl("div",{cls:"paperforge-orphan-meta",text:c.join(" \xB7 ")}),s.createEl("div",{cls:"paperforge-orphan-explain",text:o("orphan_explain")}),a.addEventListener("click",()=>{n._selected=!n._selected,this._updateUI()})}let r=e.createEl("div",{cls:"paperforge-modal-actions"});this._selectAllBtn=r.createEl("button",{cls:"paperforge-step-btn",text:"Deselect all"}),this._selectAllBtn.addEventListener("click",()=>{let n=this.orphans.every(a=>a._selected);for(let a of this.orphans)a._selected=!n;this._updateUI()}),this._countEl=r.createEl("button",{cls:"paperforge-step-btn mod-cta",text:"Delete "+this.orphans.length+" selected"}),r.createEl("button",{cls:"paperforge-step-btn",text:"Keep all"}).addEventListener("click",()=>this.close()),this._countEl.addEventListener("click",()=>{let n=this.orphans.filter(s=>s._selected);if(n.length===0){new te.Notice(o("orphan_none_selected"));return}if(this._countEl.setText("Deleting..."),this._countEl.setAttr("disabled",""),this._selectAllBtn.setAttr("disabled",""),!this.py||!this.py.path){new te.Notice("PaperForge: Python not found"),this.close();return}let a=n.map(s=>s.key);(0,Be.execFile)(this.py.path,[...this.py.extraArgs,"-m","paperforge","--vault",this.vaultPath,"prune","--force","--json",...a],{cwd:this.vaultPath,timeout:6e4},(s,i)=>{if(s){new te.Notice("PaperForge: prune failed"),this.close();return}try{let l=JSON.parse(i),c=l.data&&l.data.deleted||[];new te.Notice("Deleted "+c.length+" orphan workspace(s)")}catch(l){new te.Notice("PaperForge: prune done")}this.close()})})}onClose(){this.contentEl.empty()}};function ze(u,h,e){console.log("[PF] checkOrphanState called");try{let r=ne(e).orphanStatePath;if(!ae.existsSync(r)){console.log("[PF] orphan file NOT FOUND");return}console.log("[PF] orphan file FOUND");let n=ae.readFileSync(r,"utf-8"),s=JSON.parse(n).orphans||[];if(console.log("[PF] orphans count:",s.length),s.length===0)return;let i=ue(e,h.settings);console.log("[PF] py.path:",i?i.path:"null"),new st(u,s,e,i).open(),ae.unlinkSync(r),console.log("[PF] orphan file cleaned")}catch(t){console.log("[PF] checkOrphanState exception:",t.message||t)}}var De=class extends te.Modal{constructor(e,t){super(e);this._pendingSave=null;this._showSkipConfirm=!1;this.plugin=t,this._step=1}onOpen(){this._render()}onClose(){this.contentEl.empty()}_render(){let{contentEl:e}=this;e.empty(),e.addClass("paperforge-modal"),this._renderStepIndicator(),this._renderStepContent(),this._renderNavigation()}_renderStepIndicator(){let e=[o("wizard_step1"),o("wizard_step2"),o("wizard_step3"),o("wizard_step4"),o("wizard_step5")],t=this.contentEl.createEl("div",{cls:"paperforge-step-bar"});e.forEach((r,n)=>{let a=n+1,s=t.createEl("div",{cls:`paperforge-step-dot ${a===this._step?"active":""} ${a1&&e.createEl("button",{cls:"paperforge-step-btn",text:o("nav_prev")}).addEventListener("click",()=>{this._step--,this._showSkipConfirm=!1,this._render()}),this._step<5?e.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("nav_next")}).addEventListener("click",()=>{if(this._step===3){let r=this._validateStep3();if(r.blocked){if(r.reason==="zotero")return;if(r.reason==="ocr"){this._showSkipConfirm=!0,this._render();return}}}this._step++,this._showSkipConfirm=!1,this._render()}):e.createEl("button",{cls:"paperforge-step-btn",text:o("nav_close")}).addEventListener("click",()=>this.close())}_validateStep3(){let e=this.plugin.settings,t=mt(this._apiKeyValidated,e.zotero_data_dir);if(t.reason==="ocr")return t;let r=(e.zotero_data_dir||"").trim();if(!r)return new te.Notice("Zotero \u6570\u636E\u76EE\u5F55\u4E3A\u5FC5\u586B\u9879\uFF0C\u8BF7\u586B\u5199\u8DEF\u5F84"),{blocked:!0,reason:"zotero"};if(!ae.existsSync(r))return new te.Notice("Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u5B58\u5728"),{blocked:!0,reason:"zotero"};if(!ae.statSync(r).isDirectory())return new te.Notice("Zotero \u6570\u636E\u76EE\u5F55\u8DEF\u5F84\u4E0D\u662F\u4E00\u4E2A\u76EE\u5F55"),{blocked:!0,reason:"zotero"};let n=yt.join(r,"storage");return!ae.existsSync(n)||!ae.statSync(n).isDirectory()?(new te.Notice("Zotero \u6570\u636E\u76EE\u5F55\u4E2D\u672A\u627E\u5230 storage/ \u5B50\u76EE\u5F55"),{blocked:!0,reason:"zotero"}):{blocked:!1}}_stepOverview(e){e.createEl("h2",{text:o("wizard_title")}),e.createEl("p",{text:o("wizard_intro")});let t=this.plugin.settings,r=this.app.vault.adapter.basePath,n=e.createEl("div",{cls:"paperforge-dir-tree"}),a=n.createEl("div",{cls:"paperforge-dir-node root"});a.textContent=`\u{1F4C1} Vault (${r})`;let s=n.createEl("div",{cls:"paperforge-dir-children"}),i=s.createEl("div",{cls:"paperforge-dir-node folder"});i.textContent=`\u{1F4C1} ${t.resources_dir||"Resources"}/ \u2014 \u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08Base \u6570\u636E\u6765\u6E90\uFF09`,i.createEl("div",{cls:"paperforge-dir-children"}).createEl("div",{cls:"paperforge-dir-node file",text:`\u{1F4C1} ${t.literature_dir||"Literature"}/ \u2014 \u6587\u732E\u5361\u7247`}),s.createEl("div",{cls:"paperforge-dir-node folder",text:`\u{1F4C1} ${t.base_dir||"Bases"}/ \u2014 \u6570\u636E\u7BA1\u7406\u9762\u677F`}),s.createEl("div",{cls:"paperforge-dir-node folder",text:`\u{1F4C1} ${t.system_dir||"System"}/ \u2014 Zotero \u8F6F\u94FE\u63A5 + PaperForge \u7CFB\u7EDF\u6587\u4EF6\u5939`}),e.createEl("p",{text:o("wizard_preview"),cls:"paperforge-modal-hint"}),e.createEl("p",{text:o("wizard_safety"),cls:"paperforge-modal-hint"});let c=e.createEl("div",{cls:"paperforge-summary"}),d=[{label:o("dir_resources"),val:`${r}/${t.resources_dir||"Resources"}`},{label:o("dir_notes"),val:`${r}/${t.resources_dir||"Resources"}/${t.literature_dir||"Literature"}`},{label:o("dir_base"),val:`${r}/${t.base_dir||"Bases"}`},{label:o("dir_system"),val:`${r}/${t.system_dir||"System"}`}];for(let f of d){let p=c.createEl("div",{cls:"paperforge-summary-row"});p.createEl("span",{cls:"paperforge-summary-label",text:f.label}),p.createEl("span",{cls:"paperforge-summary-value",text:f.val})}}_stepDirectories(e){e.createEl("h2",{text:o("wizard_step2")}),e.createEl("p",{text:o("wizard_intro")});let t=this.plugin.settings,r=this.app.vault.adapter.basePath;this._modalField(e,o("dir_vault"),r,!0),e.createEl("p",{text:o("wizard_dir_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u8D44\u6E90\u76EE\u5F55\uFF08\u521B\u5EFA\u6587\u732E\u5361\u7247\u76EE\u5F55\u7684\u5730\u65B9\uFF09","resources_dir",t.resources_dir,"Resources"),e.createEl("p",{text:o("wizard_dir_sub_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u6587\u732E\u5361\u7247\u76EE\u5F55\uFF08\u5B58\u653E\u6587\u732E\u5361\u7247\u7684\u5730\u65B9\uFF0CBase \u6570\u636E\u6765\u6E90\uFF09","literature_dir",t.literature_dir,"Literature"),e.createEl("p",{text:o("wizard_sys_hint"),cls:"paperforge-modal-hint"}),this._modalInput(e,"\u7CFB\u7EDF\u76EE\u5F55\uFF08\u5B58\u653E Zotero \u8F6F\u94FE\u63A5\u548C PaperForge \u7CFB\u7EDF\u6587\u4EF6\uFF09","system_dir",t.system_dir,"System"),this._modalInput(e,"Base \u76EE\u5F55\uFF08\u5B58\u653E\u6570\u636E\u7BA1\u7406\u9762\u677F\u7684\u5730\u65B9\uFF09","base_dir",t.base_dir,"Bases"),e.createEl("p",{text:o("wizard_safety"),cls:"paperforge-modal-hint"});let n=e.createEl("div",{cls:"paperforge-summary"}),a=[{label:o("dir_resources"),val:`${r}/${t.resources_dir||""}`},{label:o("dir_notes"),val:`${r}/${t.resources_dir||""}/${t.literature_dir||""}`},{label:o("dir_system"),val:`${r}/${t.system_dir||""}`},{label:o("dir_base"),val:`${r}/${t.base_dir||""}`}];for(let s of a){let i=n.createEl("div",{cls:"paperforge-summary-row"});i.createEl("span",{cls:"paperforge-summary-label",text:s.label}),i.createEl("span",{cls:"paperforge-summary-value",text:s.val})}}_stepKeys(e){if(e.createEl("h2",{text:o("wizard_step3")}),this._showSkipConfirm){this._renderSkipConfirm(e);return}let t=this.plugin.settings;e.createEl("p",{text:o("wizard_agent_hint"),cls:"paperforge-modal-hint"});let r=[{key:"opencode",name:"OpenCode"},{key:"claude",name:"Claude Code"},{key:"cursor",name:"Cursor"},{key:"github_copilot",name:"GitHub Copilot"},{key:"windsurf",name:"Windsurf"},{key:"codex",name:"Codex"},{key:"gemini",name:"Gemini CLI"},{key:"cline",name:"Cline"}],n=e.createEl("div",{cls:"paperforge-modal-field"});n.createEl("label",{cls:"paperforge-modal-label",text:o("label_agent")});let a=n.createEl("select",{cls:"paperforge-modal-select"});for(let f of r){let p=a.createEl("option",{text:f.name,attr:{value:f.key}});f.key===(t.agent_platform||"opencode")&&(p.selected=!0)}a.addEventListener("change",()=>{t.agent_platform=a.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)}),e.createEl("p",{text:o("wizard_keys_hint"),cls:"paperforge-modal-hint"});let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:o("field_paddleocr")});let i=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"password",placeholder:"API Key"}});i.value=t.paddleocr_api_key||"",this._apiKeyValidated=!1,this._apiKeyStatus=s.createEl("span",{cls:"paperforge-apikey-status",text:""});let l=s.createEl("button",{cls:"paperforge-step-btn",text:"\u9A8C\u8BC1"});l.addEventListener("click",()=>this._validateApiKey(i.value,l)),i.addEventListener("input",()=>{t.paddleocr_api_key=i.value,this._apiKeyValidated=!1,this._apiKeyStatus.textContent="",this._apiKeyStatus.className="paperforge-apikey-status"}),this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500),e.createEl("p",{text:o("wizard_api_hint_skip"),cls:"paperforge-modal-hint"});let c=e.createEl("div",{cls:"paperforge-modal-field"});c.createEl("label",{cls:"paperforge-modal-label",text:o("field_zotero_data")});let d=c.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text",placeholder:o("field_zotero_placeholder")}});d.value=t.zotero_data_dir||"",d.addEventListener("input",()=>{t.zotero_data_dir=d.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_validateApiKey(e,t){if(!e||e.length<10){this._apiKeyStatus.textContent="\u5BC6\u94A5\u683C\u5F0F\u4E0D\u6B63\u786E\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error";return}t.disabled=!0,t.textContent="\u9A8C\u8BC1\u4E2D\u2026",this._apiKeyStatus.textContent="\u6B63\u5728\u9A8C\u8BC1\u2026",this._apiKeyStatus.className="paperforge-apikey-status";let r=JSON.stringify({model:"PaddleOCR-VL-1.5"}),n={hostname:"paddleocr.aistudio-app.com",path:"/api/v2/ocr/jobs",method:"POST",headers:{Authorization:"bearer "+e,"Content-Type":"application/json","Content-Length":Buffer.byteLength(r)},timeout:1e4},a=vt.request(n,s=>{t.disabled=!1,t.textContent="\u9A8C\u8BC1";let i="";s.on("data",l=>i+=l),s.on("end",()=>{try{let l=JSON.parse(i);s.statusCode===400&&l.code===10001?(this._apiKeyStatus.textContent="\u2713 \u5BC6\u94A5\u6709\u6548",this._apiKeyStatus.className="paperforge-apikey-status ok",this._apiKeyValidated=!0):s.statusCode===401?(this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5BC6\u94A5\u65E0\u6548\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1):(this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1AAPI \u8FD4\u56DE "+s.statusCode+"\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1)}catch(l){this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u89E3\u6790\u54CD\u5E94\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1}})});a.on("error",s=>{t.disabled=!1,t.textContent="\u9A8C\u8BC1",this._apiKeyStatus.textContent="\u9A8C\u8BC1\u5931\u8D25\uFF1A\u65E0\u6CD5\u8FDE\u63A5 ("+s.message+")\u3002\u53EF\u70B9\u4E0B\u4E00\u6B65\u8DF3\u8FC7\uFF0C\u7B49\u4F1A\u513F\u518D\u914D\u7F6E\u3002",this._apiKeyStatus.className="paperforge-apikey-status error",this._apiKeyValidated=!1}),a.write(r),a.end()}_renderSkipConfirm(e){e.createEl("p",{text:o("wizard_skip_ocr_desc"),cls:"paperforge-modal-desc"});let t=e.createEl("div",{cls:"paperforge-modal-actions"});t.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("wizard_skip_ocr_continue")}).addEventListener("click",()=>{this._showSkipConfirm=!1,this._step++,this._render()}),t.createEl("button",{cls:"paperforge-step-btn",text:o("wizard_skip_ocr_back")}).addEventListener("click",()=>{this._showSkipConfirm=!1,this._render()})}_modalField(e,t,r,n){let a=e.createEl("div",{cls:"paperforge-modal-field"});a.createEl("label",{cls:"paperforge-modal-label",text:t});let s=a.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text"}});s.value=r,s.disabled=!!n}_modalInput(e,t,r,n,a){let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:t});let i=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"text",placeholder:a||""}});i.value=n;let l=this.plugin.settings;i.addEventListener("input",()=>{l[r]=i.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_modalSecret(e,t,r,n,a){let s=e.createEl("div",{cls:"paperforge-modal-field"});s.createEl("label",{cls:"paperforge-modal-label",text:t});let i=s.createEl("input",{cls:"paperforge-modal-input",attr:{type:"password",placeholder:a||""}});i.value=n;let l=this.plugin.settings;i.addEventListener("input",()=>{l[r]=i.value,this._pendingSave&&clearTimeout(this._pendingSave),this._pendingSave=setTimeout(()=>{this.plugin.saveSettings(),this._pendingSave=null},500)})}_stepInstall(e){e.createEl("h2",{text:o("wizard_step4")}),this._installLog=e.createEl("div",{cls:"paperforge-install-log"});let t=e.createEl("button",{cls:"paperforge-step-btn mod-cta",text:o("install_btn")});t.addEventListener("click",()=>this._runInstall(t))}async _runInstall(e){var s,i,l,c,d,f;e.disabled=!0,e.textContent=o("install_btn_running"),this._installLog.setText(o("install_validating")+` +`),this._log(o("install_validating"));let t=this.plugin.settings,r=this._validate();if(r.length>0){this._log(o("validate_fail")+":"),r.forEach(p=>this._log(" \u2717 "+p)),e.disabled=!1,e.textContent=o("install_btn_retry");return}let n=(p,m={})=>new Promise((y,x)=>{let{path:_,extraArgs:b=[]}=N(t.vault_path.trim(),this.plugin.settings,void 0,void 0),E=(0,Be.spawn)(_,[...b,...p],{cwd:t.vault_path.trim(),env:be(),timeout:12e4,...m}),k="",g="";E.stdout.on("data",v=>{let w=v.toString("utf-8");k+=w,m.logStdout&&this._processSetupOutput(w)}),E.stderr.on("data",v=>{let w=v.toString("utf-8");g+=w,this._log("[stderr] "+w.trim())}),E.on("close",v=>{v===0?y({stdout:k,stderr:g}):x(new Error(g.trim()||k.trim()||`exit code ${v}`))}),E.on("error",v=>x(v))}),a=["-m","paperforge","--vault",t.vault_path.trim(),"setup","--headless","--system-dir",t.system_dir.trim(),"--resources-dir",t.resources_dir.trim(),"--literature-dir",t.literature_dir.trim(),"--base-dir",t.base_dir.trim(),"--agent",t.agent_platform||"opencode"];t.zotero_data_dir&&t.zotero_data_dir.trim()&&a.push("--zotero-data",t.zotero_data_dir.trim()),t.paddleocr_api_key&&t.paddleocr_api_key.trim()&&a.push("--paddleocr-key",t.paddleocr_api_key.trim());try{let p=!0;try{await n(["-c","import paperforge"])}catch(m){p=!1}if(!p){this._log(o("install_bootstrapping"));let m=this.plugin.manifest.version;this._log(`[install] Trying PyPI: pip install paperforge==${m}`);let y=["-m","pip","install","--upgrade"];process.platform!=="win32"&&y.push("--user"),y.push(`paperforge==${m}`);try{await n(y,{logStdout:!0})}catch(x){this._log(`[install] PyPI failed, falling back to git: git+https://...@v${m}`),console.warn("[PaperForge] PyPI install failed, falling back to git:",(s=x.message)==null?void 0:s.slice(0,200));let _=["-m","pip","install","--upgrade"];process.platform!=="win32"&&_.push("--user"),_.push(`git+https://github.com/LLLin000/PaperForge.git@v${m}`),await n(_,{logStdout:!0})}}await n(a,{logStdout:!0,env:be()}),this._log(o("install_complete")),t.setup_complete=!0,await this.plugin.saveSettings(),setTimeout(()=>{this._step=5,this._render()},800)}catch(p){console.error("PaperForge setup failed:",p.message);let m=this._formatSetupError(p.message);this._log(o("install_failed")+m);let y=(i=this._installLog.parentElement)==null?void 0:i.createEl("button",{cls:"paperforge-copy-diag-btn",text:o("error_copy_diagnostic")||"Copy diagnostic"});if(y){let x=p.message,_=((c=(l=this.plugin)==null?void 0:l.settings)==null?void 0:c.python_path)||"auto",b=((f=(d=this.plugin)==null?void 0:d.manifest)==null?void 0:f.version)||"?",E=process.platform+" "+process.arch,k,g;try{k=Ye()||"(not found)"}catch(P){k="(error)"}try{g=N(t.vault_path.trim(),this.plugin.settings,void 0,void 0)}catch(P){g=null}let v=(process.env.PATH||"").length,w=(process.env.PATH||"").toLowerCase().includes("git"),T=["[PaperForge Diagnostic]","Category: "+m,"Plugin version: "+b,"Python: "+_,"Resolved Python: "+((g==null?void 0:g.path)||"?"),"OS: "+E,"Vault path: "+(t.vault_path||"?"),"--- Git ---","Git dir (resolved): "+k,"PATH length: "+v+" chars","PATH contains git: "+w,"--- Raw error ---",x.slice(0,2e3)].join(` +`);y.addEventListener("click",()=>{navigator.clipboard.writeText(T).then(()=>{y.setText(o("error_copied")||"Copied!"),setTimeout(()=>{y.setText(o("error_copy_diagnostic")||"Copy diagnostic")},3e3)}).catch(()=>{new te.Notice("[!!] Clipboard write failed",6e3)})})}e.disabled=!1,e.textContent=o("install_btn_retry")}}_log(e){this._installLog&&this._installLog.setText(this._installLog.textContent+e+` `)}_validate(){let e=[],t=this.plugin.settings;return(!t.vault_path||!t.vault_path.trim())&&e.push(o("validate_vault")),(!t.resources_dir||!t.resources_dir.trim())&&e.push(o("validate_resources")),(!t.literature_dir||!t.literature_dir.trim())&&e.push(o("validate_notes")),(!t.base_dir||!t.base_dir.trim())&&e.push(o("validate_base")),(!t.paddleocr_api_key||!t.paddleocr_api_key.trim())&&this._log(" ! "+o("validate_key")+" "+o("optional_later")),(!t.zotero_data_dir||!t.zotero_data_dir.trim())&&this._log(" ! "+o("validate_zotero")+" "+o("optional_later")),e}_processSetupOutput(e){let t=e.split(` `).filter(Boolean);for(let r of t)if(r.includes("[*]")||r.includes("[OK]")||r.includes("[FAIL]")){let n=r.replace(/^\[\*\].*\d+:?\s*/,"").replace(/^\[OK\]\s*/,"").replace(/^\[FAIL\]\s*/,"");this._log(" "+n)}}_formatSetupError(e){if(process.platform==="darwin"&&/No module named ['"]?paperforge/i.test(e))return"PaperForge not installed \u2014 install Python from Homebrew or python.org (Apple CLT /Library/Developer/CommandLineTools python often fails); then: python3 -m pip install --user git+https://github.com/LLLin000/PaperForge.git";let t=[{match:/pip.*not found|No module named.*pip|command not found.*pip/i,msg:"pip not found"},{match:/command not found|No such file|not recognized/i,msg:"Python not found"},{match:/resolve host|getaddrinfo.*nodename|connect ETIMEDOUT|connect ECONNREFUSED|fetch failed|Network error|ENOTFOUND|ECONNREFUSED|ECONNRESET/i,msg:"Network error"},{match:/certificate verify failed|SSL.*certificate|self.signed.cert|CERTIFICATE_VERIFY_FAILED/i,msg:"SSL certificate error"},{match:/No space left on device|disk full|ENOSPC/i,msg:"Disk full"},{match:/paperforge.*not found|cannot import|ModuleNotFoundError|No module named/i,msg:"PaperForge not installed"},{match:/permission denied|EACCES|EPERM/i,msg:"Permission denied"},{match:/ENOENT/i,msg:"Path not found"},{match:/timeout|timed out/i,msg:"Timeout"}];for(let n of t)if(n.match.test(e))return n.msg;return e.split(` -`).filter(Boolean).slice(0,3).join(" | ").slice(0,200)||"Unknown error"}_stepComplete(e){e.createEl("h2",{text:o("complete_title")});let t=e.createEl("div",{cls:"paperforge-summary"});t.createEl("div",{cls:"paperforge-summary-title",text:o("complete_summary")});let r=this.plugin.settings,n=this.app.vault.adapter.basePath,a=[{label:o("dir_vault"),val:n},{label:o("dir_resources"),val:`${n}/${r.resources_dir}`},{label:o("dir_notes"),val:`${n}/${r.resources_dir}/${r.literature_dir}`},{label:o("dir_base"),val:`${n}/${r.base_dir}`},{label:o("dir_system"),val:`${n}/${r.system_dir}`},{label:"API Key",val:r.paddleocr_api_key?o("api_key_set"):o("api_key_missing")},{label:o("field_zotero_data"),val:r.zotero_data_dir||o("not_set")}];for(let d of a){let g=t.createEl("div",{cls:"paperforge-summary-row"});g.createEl("span",{cls:"paperforge-summary-label",text:d.label}),g.createEl("span",{cls:"paperforge-summary-value",text:d.val})}let s=t.createEl("div",{cls:"paperforge-summary-row"});s.createEl("span",{cls:"paperforge-summary-label",text:"PaperForge"});let l=s.createEl("span",{cls:"paperforge-summary-value",text:"\u2014"});{let d=n,{path:g,extraArgs:p=[]}=L(d,this.plugin.settings,void 0,void 0);(0,De.execFile)(g,[...p,"-c","import paperforge; print(paperforge.__version__)"],{cwd:d,timeout:1e4},(f,y)=>{!f&&y&&(l.textContent="v"+y.trim())})}for(let d of a){let g=t.createEl("div",{cls:"paperforge-summary-row"});g.createEl("span",{cls:"paperforge-summary-label",text:d.label}),g.createEl("span",{cls:"paperforge-summary-value",text:d.val})}e.createEl("h3",{text:o("complete_next")});let i=e.createEl("div",{cls:"paperforge-nextsteps"}),c=[[o("complete_step4"),o("complete_step4_desc")],["",`${o("complete_export_path")} ${n}/${r.system_dir}/PaperForge/exports/`],[o("complete_step1"),o("complete_step1_desc")],[o("complete_step2"),o("complete_step2_desc")],[o("complete_step3"),o("complete_step3_desc")]];for(let[d,g]of c){let p=i.createEl("div",{cls:"paperforge-nextstep-item"});d&&p.createEl("strong",{text:d}),p.createEl("span",{text:g})}}};var xe=$(require("fs")),ze=$(require("path")),vt=require("child_process");function bt(h){return ze.join(h,"System","PaperForge","cache","ocr_maintenance.json")}function xt(h){try{let u=bt(h),e=xe.readFileSync(u,"utf-8");return JSON.parse(e)}catch(u){return null}}function $e(h,u){let e=bt(h),t=ze.dirname(e);xe.mkdirSync(t,{recursive:!0}),xe.writeFileSync(e,JSON.stringify(u,null,2),"utf-8")}function yt(h,u,e){return new Promise((t,r)=>{(0,vt.execFile)(h,u,e,(n,a)=>{n?r(n):t(a)})})}async function Et(h,u,e,t){let r=await yt(u,[...e,"-m","paperforge","ocr","list","--manifest"],{cwd:h,timeout:3e4}),n=JSON.parse(r);if(t){let d=Object.keys(t.manifest),g=Object.keys(n);if(d.length===g.length&&d.every(f=>t.manifest[f]===n[f]))return{data:Object.values(t.papers).filter(y=>y.visible_in_maintenance),changed:!1}}let a=Object.keys(n).filter(d=>!(t!=null&&t.manifest[d])||t.manifest[d]!==n[d]),s=await yt(u,[...e,"-m","paperforge","ocr","list","--json","--keys",...a],{cwd:h,timeout:3e4}),l=JSON.parse(s),i={manifest:n,papers:{},cached_at:new Date().toISOString()};if(t!=null&&t.papers)for(let d of Object.keys(n))t.papers[d]&&(i.papers[d]=t.papers[d]);for(let d of l)i.papers[d.key]=d;return $e(h,i),{data:Object.values(i.papers).filter(d=>d.visible_in_maintenance),changed:!0}}var je=class extends C.PluginSettingTab{constructor(e,t){super(e,t);this._saveTimeout=null;this._pfConfig=null;this._lastSyncTime=null;this._memoryStatusText=null;this._vectorDepsOk=null;this._embedStatusText=null;this._skillsCollapsed={user:!0};this._featurePanelsCollapsed={};this._advCollapsed=!0;this._refreshPending=!1;this._pythonInterpDescEl=null;this._customPathDescEl=null;this._checkEl=null;this.activeTab="setup";this.plugin=t}_refreshPfConfig(){this._pfConfig=this.plugin.readPaperforgeJson()}display(){let{containerEl:e}=this;if(e.empty(),this._refreshPfConfig(),!document.getElementById("paperforge-tab-styles")){let a=document.createElement("style");a.id="paperforge-tab-styles",a.textContent=` +`).filter(Boolean).slice(0,3).join(" | ").slice(0,200)||"Unknown error"}_stepComplete(e){e.createEl("h2",{text:o("complete_title")});let t=e.createEl("div",{cls:"paperforge-summary"});t.createEl("div",{cls:"paperforge-summary-title",text:o("complete_summary")});let r=this.plugin.settings,n=this.app.vault.adapter.basePath,a=[{label:o("dir_vault"),val:n},{label:o("dir_resources"),val:`${n}/${r.resources_dir}`},{label:o("dir_notes"),val:`${n}/${r.resources_dir}/${r.literature_dir}`},{label:o("dir_base"),val:`${n}/${r.base_dir}`},{label:o("dir_system"),val:`${n}/${r.system_dir}`},{label:"API Key",val:r.paddleocr_api_key?o("api_key_set"):o("api_key_missing")},{label:o("field_zotero_data"),val:r.zotero_data_dir||o("not_set")}];for(let d of a){let f=t.createEl("div",{cls:"paperforge-summary-row"});f.createEl("span",{cls:"paperforge-summary-label",text:d.label}),f.createEl("span",{cls:"paperforge-summary-value",text:d.val})}let s=t.createEl("div",{cls:"paperforge-summary-row"});s.createEl("span",{cls:"paperforge-summary-label",text:"PaperForge"});let i=s.createEl("span",{cls:"paperforge-summary-value",text:"\u2014"});{let d=n,{path:f,extraArgs:p=[]}=N(d,this.plugin.settings,void 0,void 0);(0,Be.execFile)(f,[...p,"-c","import paperforge; print(paperforge.__version__)"],{cwd:d,timeout:1e4},(m,y)=>{!m&&y&&(i.textContent="v"+y.trim())})}for(let d of a){let f=t.createEl("div",{cls:"paperforge-summary-row"});f.createEl("span",{cls:"paperforge-summary-label",text:d.label}),f.createEl("span",{cls:"paperforge-summary-value",text:d.val})}e.createEl("h3",{text:o("complete_next")});let l=e.createEl("div",{cls:"paperforge-nextsteps"}),c=[[o("complete_step4"),o("complete_step4_desc")],["",`${o("complete_export_path")} ${n}/${r.system_dir}/PaperForge/exports/`],[o("complete_step1"),o("complete_step1_desc")],[o("complete_step2"),o("complete_step2_desc")],[o("complete_step3"),o("complete_step3_desc")]];for(let[d,f]of c){let p=l.createEl("div",{cls:"paperforge-nextstep-item"});d&&p.createEl("strong",{text:d}),p.createEl("span",{text:f})}}};var ke=V(require("fs")),$e=V(require("path")),xt=require("child_process");function Et(u){return $e.join(u,"System","PaperForge","cache","ocr_maintenance.json")}function kt(u){try{let h=Et(u),e=ke.readFileSync(h,"utf-8");return JSON.parse(e)}catch(h){return null}}function Ve(u,h){let e=Et(u),t=$e.dirname(e);ke.mkdirSync(t,{recursive:!0}),ke.writeFileSync(e,JSON.stringify(h,null,2),"utf-8")}function bt(u,h,e){return new Promise((t,r)=>{(0,xt.execFile)(u,h,e,(n,a)=>{n?r(n):t(a)})})}async function wt(u,h,e,t){let r=await bt(h,[...e,"-m","paperforge","ocr","list","--manifest"],{cwd:u,timeout:3e4}),n=JSON.parse(r);if(t){let d=Object.keys(t.manifest),f=Object.keys(n);if(d.length===f.length&&d.every(m=>t.manifest[m]===n[m]))return{data:Object.values(t.papers).filter(y=>y.visible_in_maintenance),changed:!1}}let a=Object.keys(n).filter(d=>!(t!=null&&t.manifest[d])||t.manifest[d]!==n[d]),s=await bt(h,[...e,"-m","paperforge","ocr","list","--json","--keys",...a],{cwd:u,timeout:3e4}),i=JSON.parse(s),l={manifest:n,papers:{},cached_at:new Date().toISOString()};if(t!=null&&t.papers)for(let d of Object.keys(n))t.papers[d]&&(l.papers[d]=t.papers[d]);for(let d of i)l.papers[d.key]=d;return Ve(u,l),{data:Object.values(l.papers).filter(d=>d.visible_in_maintenance),changed:!0}}var He=class extends R.PluginSettingTab{constructor(e,t){super(e,t);this._saveTimeout=null;this._pfConfig=null;this._lastSyncTime=null;this._memoryStatusText=null;this._vectorDepsOk=null;this._embedStatusText=null;this._skillsCollapsed={user:!0};this._featurePanelsCollapsed={};this._advCollapsed=!0;this._refreshPending=!1;this._pythonInterpDescEl=null;this._customPathDescEl=null;this._checkEl=null;this.activeTab="setup";this._buildState="idle";this._buildProgress={current:0,total:0,key:""};this.plugin=t}_refreshPfConfig(){this._pfConfig=this.plugin.readPaperforgeJson()}display(){let{containerEl:e}=this;if(e.empty(),this._refreshPfConfig(),!document.getElementById("paperforge-tab-styles")){let a=document.createElement("style");a.id="paperforge-tab-styles",a.textContent=` .paperforge-settings-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--background-modifier-border); } .paperforge-settings-tab { padding: 6px 16px; border: none; background: none; cursor: pointer; border-bottom: 2px solid transparent; font-size: 14px; color: var(--text-muted); } .paperforge-settings-tab--active { color: var(--text-accent); border-bottom-color: var(--text-accent); } @@ -29,26 +29,26 @@ .paperforge-manual-links a { color: var(--text-accent); } .paperforge-modal-subtitle { color: var(--text-muted); font-size: 13px; margin-bottom: 12px; } .paperforge-modal-item { font-size: 13px; margin-left: 8px; color: var(--text-muted); } - `,document.head.appendChild(a)}let t=e.createDiv({cls:"paperforge-settings-tabs"}),r=[{id:"setup",label:o("tab_setup")||"\u5B89\u88C5"},{id:"features",label:o("tab_features")||"\u529F\u80FD"},{id:"maintenance",label:o("tab_maintenance")||"\u7EF4\u62A4"},{id:"release-notes",label:"\u66F4\u65B0\u4E0E\u624B\u518C"}],n={};r.forEach(a=>{t.createEl("button",{cls:"paperforge-settings-tab"+(a.id===this.activeTab?" paperforge-settings-tab--active":""),text:a.label}).addEventListener("click",()=>{this.activeTab=a.id,this.display()})}),r.forEach(a=>{n[a.id]=e.createDiv({cls:"paperforge-tab-content"+(a.id===this.activeTab?" paperforge-tab-content--active":"")})}),this.activeTab==="setup"?this._renderSetupTab(n.setup):this.activeTab==="features"?this._renderFeaturesTab(n.features):this.activeTab==="maintenance"?this._renderMaintenanceTab(n.maintenance):this._renderReleaseNotesTab(n["release-notes"])}_renderSetupTab(e){let t=this.app.vault.adapter.basePath;this.plugin.settings.vault_path||(this.plugin.settings.vault_path=t,this._debouncedSave()),this.plugin.settings.setup_complete&&(N.existsSync(Z.join(t,"paperforge.json"))||(this.plugin.settings.setup_complete=!1,this._debouncedSave())),e.createEl("h2",{text:o("header_title")||"PaperForge"}),e.createEl("p",{text:o("desc"),cls:"paperforge-settings-desc"});let n=e.createEl("div",{cls:"paperforge-setup-bar"}).createEl("span",{cls:"paperforge-setup-label"});this.plugin.settings.setup_complete?(n.setText(o("setup_done")),n.addClass("paperforge-setup-done")):(n.setText(o("setup_pending")),n.addClass("paperforge-setup-pending"));let a=this.app.vault.adapter.basePath,s=L(a,this.plugin.settings,void 0,void 0),l=s.path,i=this.plugin.settings._python_path_stale?"stale":s.source,c=new C.Setting(e).setName(o("field_python_interp")).setDesc(this._getPythonDesc(l,i));this._pythonInterpDescEl=c.descEl;let d=new C.Setting(e).setName(o("field_python_custom")).setDesc("");this._customPathDescEl=d.descEl,d.addText(E=>{E.setPlaceholder("e.g. C:\\Python310\\python.exe").setValue(this.plugin.settings.python_path||"").onChange(_=>{if(this.plugin.settings.python_path=_,this.plugin.saveSettings(),_&&_.trim()){let S=N.existsSync(_.trim());this.plugin.settings._python_path_stale=!S}else this.plugin.settings._python_path_stale=!1;let v=L(this.app.vault.adapter.basePath,this.plugin.settings,void 0,void 0),k=this.plugin.settings._python_path_stale?"stale":v.source;this._pythonInterpDescEl&&(this._pythonInterpDescEl.textContent=this._getPythonDesc(v.path,k))})}),d.addButton(E=>{E.setButtonText(o("btn_validate")).onClick(()=>this._validatePythonOverride())}),e.createEl("h3",{text:o("runtime_health")}),e.createEl("p",{text:o("runtime_health_desc"),cls:"paperforge-settings-desc"});let g=new C.Setting(e).setName("PaperForge").setDesc(o("runtime_health_checking")),p=g.descEl.createEl("span",{cls:"paperforge-runtime-badge"}),f=null;g.addButton(E=>{f=E,E.setButtonText(o("runtime_health_sync")).setDisabled(!0).onClick(()=>this._syncRuntime(E))});{let E=this.app.vault.adapter.basePath,{path:_,extraArgs:v=[]}=L(E,this.plugin.settings,void 0,void 0),k=this.plugin.manifest.version||"?";(0,j.execFile)(_,[...v,"-c","import paperforge; print(paperforge.__version__)"],{cwd:E,timeout:1e4},(S,P)=>{let A=this.plugin.settings.setup_complete,T=!S&&P?P.trim():null,I=T?`${o("runtime_health_plugin_ver").replace("{0}",k)} \u2192 ${o("runtime_health_package_ver").replace("{0}",T)}`:A?`Plugin v${k} \u2192 Python package not installed. Click "Sync Runtime" to install.`:`Plugin v${k} \u2192 Not configured. Please open the setup wizard first.`;g.setDesc(I),T===k?(p.setText(o("runtime_health_match")),p.className="paperforge-runtime-badge match",f&&f.setDisabled(!0)):T?(p.setText(o("runtime_health_mismatch")),p.className="paperforge-runtime-badge mismatch",f&&f.setDisabled(!1)):(p.setText(A?"Not installed":"Setup needed"),p.className="paperforge-runtime-badge missing",f&&f.setDisabled(!1))})}e.createEl("h3",{text:o("section_prep")}),e.createEl("p",{text:o("section_prep_desc"),cls:"paperforge-settings-desc"});let y=e.createEl("div",{cls:"paperforge-guide"}),b=[["prep_python","prep_python_desc"],["prep_zotero","prep_zotero_desc"],["prep_bbt","prep_bbt_desc"],["prep_key","prep_key_desc"]];for(let[E,_]of b){let v=y.createEl("div",{cls:"paperforge-guide-item"});v.createEl("strong",{text:o(E)}),v.createEl("span",{text:" \u2014 "+o(_)})}this._checkEl=e.createEl("div",{cls:"paperforge-message"});let m=!this.plugin.settings.setup_complete;new C.Setting(e).setName(o(m?"btn_install":"btn_reconfig")).setDesc(o(m?"btn_install_desc":"btn_reconfig_desc")).addButton(E=>{E.setButtonText(o(m?"btn_install":"btn_reconfig")).setCta().onClick(()=>{m?this._preCheck(()=>{new Te(this.app,this.plugin).open()}):new Te(this.app,this.plugin).open()})}),e.createEl("h3",{text:o("section_guide")});let x=e.createEl("div",{cls:"paperforge-guide"}),w=[["guide_open","guide_open_desc"],["guide_sync","guide_sync_desc"],["guide_ocr","guide_ocr_desc"]];for(let[E,_]of w){let v=x.createEl("div",{cls:"paperforge-guide-item"});v.createEl("strong",{text:o(E)}),v.createEl("span",{text:" \u2014 "+o(_)})}if(this.plugin.settings.setup_complete){e.createEl("h3",{text:o("section_config")});let E=e.createEl("div",{cls:"paperforge-summary"}),_=this.plugin.settings,v=this._pfConfig,k=[{label:o("dir_vault"),val:t},{label:o("dir_resources"),val:`${t}/${v==null?void 0:v.resources_dir}`},{label:" "+o("dir_notes"),val:`${t}/${v==null?void 0:v.resources_dir}/${v==null?void 0:v.literature_dir}`},{label:o("dir_base"),val:`${t}/${v==null?void 0:v.base_dir}`},{label:o("dir_system"),val:`${t}/${v==null?void 0:v.system_dir}`},{label:"API Key",val:_.paddleocr_api_key?o("api_key_set"):o("api_key_missing")},{label:o("field_zotero_data"),val:_.zotero_data_dir||o("not_set")}];for(let S of k){let P=E.createEl("div",{cls:"paperforge-summary-row"});P.createEl("span",{cls:"paperforge-summary-label",text:S.label}),P.createEl("span",{cls:"paperforge-summary-value",text:S.val})}}}_execMemoryStatus(e,t,r){(0,j.exec)(`"${e}" -m paperforge --vault "${t}" memory status --json`,{encoding:"utf-8",timeout:15e3},(n,a)=>{if(n){r("Status unavailable");return}try{let s=JSON.parse(a);if(s.ok){let l=s.data,i=l.fresh?"fresh":"stale";r(`Papers: ${l.paper_count_db} | ${i}${l.needs_rebuild?" - needs rebuild":""}`)}else r("DB not found. Run paperforge memory build.")}catch(s){r("Could not parse status.")}})}_execEmbedStatus(e,t,r){(0,j.exec)(`"${e}" -m paperforge --vault "${t}" embed status --json`,{encoding:"utf-8",timeout:15e3},(n,a)=>{if(n){r("Status unavailable");return}try{let s=JSON.parse(a);s.ok?r(`Chunks: ${s.data.chunk_count} | ${s.data.model} | ${s.data.mode}`):r("Could not parse status.")}catch(s){r("Could not parse status.")}})}_callPython(e,t){let r=this.app.vault.adapter.basePath,n=ce(r,this.plugin.settings),a=[...n.extraArgs,"-m","paperforge","--vault",r,...e];if(t&&t.stream){let s=(0,j.spawn)(n.path,a,{cwd:r,env:t.env||process.env,windowsHide:!0});return t.onData&&s.stdout.on("data",t.onData),t.onStderr&&s.stderr.on("data",t.onStderr),t.onError&&s.on("error",t.onError),s.on("close",t.onClose),s}return(0,j.execFile)(n.path,a,{cwd:r,timeout:t&&t.timeout||6e4},(s,l,i)=>{t&&t.onClose&&t.onClose(s?1:0,l,i)}),null}_renderMemoryStatusText(e,t,r){e.innerHTML="",e.createEl("span",{text:t,cls:"paperforge-memory-text"}),r==="syncing"?e.createEl("span",{text:"Syncing...",cls:"paperforge-sync-status"}):r&&e.createEl("span",{text:r,cls:"paperforge-sync-status"});let n=e.createEl("button",{cls:"paperforge-rebuild-btn",text:o("feat_memory_rebuild_btn")});n.title="Rebuild memory database",n.onclick=()=>{let s=this.app.vault.adapter.basePath,l=ce(s,this.plugin.settings);if(!l.path){new C.Notice(o("feat_no_python"));return}console.log("[PaperForge] Rebuilding memory:",l.path),n.setText(o("feat_memory_rebuilding")),n.setAttr("disabled",""),this._callPython(["memory","build"],{timeout:6e4,onClose:(i,c,d)=>{console.log("[PaperForge] memory build exit:",i?"FAIL:"+i:"OK",(c||"").slice(0,200),(d||"").slice(0,200)),n.setText(o("feat_memory_rebuild_btn")),n.removeAttribute("disabled"),i===0?new C.Notice(o("feat_memory_rebuild_done")):new C.Notice(o("feat_memory_rebuild_failed")+(d?" "+d.slice(0,80):"")),this._memoryStatusText=Ie(s),this._refreshSnapshots(s)}})};let a=e.createEl("button",{cls:"paperforge-refresh-btn",text:"\u21BB"});a.title="Sync now",a.onclick=()=>{this._memoryStatusText=null,this._runManualSync()}}_getBuildCommand(e){let t=this.app.vault.adapter.basePath,r=L(t,e,void 0,void 0);return r.path?`"${r.path}" -m paperforge --vault "${t}" sync`:null}_runManualSync(){let e=this.app.vault.adapter.basePath;if(!ce(e,this.plugin.settings).path)return;let r=document.querySelector(".paperforge-memory-status");r&&this._renderMemoryStatusText(r,"Checking...","syncing"),this.plugin._autoSyncRunning=!0,this._callPython(["sync"],{timeout:12e4,onClose:n=>{this.plugin._autoSyncRunning=!1,this._memoryStatusText=null,n===0&&(this._lastSyncTime=new Date().toLocaleTimeString(),this.plugin._lastSyncTime=this._lastSyncTime),this.display(),this._refreshSnapshots(e),Ne(this.app,this.plugin,e)}})}_refreshSnapshots(e){let t=ce(e,this.plugin.settings),r=[...t.extraArgs,"-m","paperforge","--vault",e,"runtime-health","--json"];this._refreshPending=!0,(0,j.execFile)(t.path,r,{cwd:e,timeout:3e4,windowsHide:!0},(n,a,s)=>{this._refreshPending=!1,this._memoryStatusText=Ie(e),this._embedStatusText=be(e),this.display()})}_renderFeaturesTab(e){e.createEl("h3",{text:"Skills"});let t=e.createEl("div",{cls:"paperforge-desc-box"});t.setText(o("feat_skills_desc")),t.createEl("br"),t.createEl("span",{text:o("feat_skills_system")});let r={opencode:"OpenCode",claude:"Claude Code",codex:"Codex",cursor:"Cursor",windsurf:"Windsurf",github_copilot:"GitHub Copilot",gemini:"Gemini CLI"},n={opencode:".opencode/skills",claude:".claude/skills",codex:".codex/skills",cursor:".cursor/skills",windsurf:".windsurf/skills",github_copilot:".github/skills",gemini:".gemini/skills"},a=this.app.vault.adapter.basePath,s=this.plugin.settings.selected_skill_platform||"opencode";new C.Setting(e).setName(o("feat_agent_platform")).setDesc(o("feat_agent_platform_desc")).addDropdown(_=>{Object.entries(r).forEach(([v,k])=>_.addOption(v,k)),_.setValue(s).onChange(v=>{this.plugin.settings.selected_skill_platform=v,this.plugin.saveSettings(),this.display()})}).addExtraButton(_=>{_.setIcon("folder").setTooltip("Open skills folder").onClick(()=>{let v=n[s]||".opencode/skills",k=Z.join(a,v);N.existsSync(k)?(0,j.exec)(`start "" "${k}"`):new C.Notice(`Skills folder not found: ${v}`)})});let l=Z.join(a,n[s]),i=[],c=[];N.existsSync(l)&&N.readdirSync(l,{withFileTypes:!0}).forEach(_=>{if(!_.isDirectory())return;let v=Z.join(l,_.name,"SKILL.md");if(!N.existsSync(v))return;let k=N.readFileSync(v,"utf-8"),S=k.match(/^name:\s*(.+)$/m),P=k.split(` -`),A=P.findIndex(q=>/^description:/.test(q)),T="";if(A>=0){let q=P[A].match(/^description:\s*(.+)$/);if(q&&q[1]&&q[1]!==">"&&q[1]!=="|-"&&q[1]!=="|")T=q[1].trim();else{for(let F=A+1;F{if(v.length===0)return;let S=d.createEl("div",{cls:"paperforge-skills-group"}),P=S.createEl("div",{cls:"paperforge-skills-collapse-header"}),A=S.createEl("div",{cls:"paperforge-skills-collapse-content"}),T=P.createEl("span",{text:"\u25BC",cls:"paperforge-skills-arrow"});P.createEl("h4",{text:`${_} (${v.length})`,cls:"paperforge-skills-subheader"}),v.forEach(O=>{let U=O.name+(O.version?" v"+O.version:""),q=k?" [system]":" [user]",F=O.desc||"",D=new C.Setting(A).setName(U+q).setDesc(F);D.settingEl.style.opacity=O.disabled?"0.4":"1",D.addToggle(X=>{X.setValue(!O.disabled).onChange(ee=>{let oe=!ee,de=O.content.match(/^disable-model-invocation:\s*(.+)$/m)?O.content.replace(/^disable-model-invocation:\s*.+$/m,`disable-model-invocation: ${oe}`):O.content.replace(/^(---\r?\n)/,`$1disable-model-invocation: ${oe} -`);N.writeFileSync(O.path,de,"utf-8"),O.disabled=oe,O.content=de,D.settingEl.style.opacity=O.disabled?"0.4":"1"})})});let I=k?"system":"user";(this._skillsCollapsed[I]||!1)&&(A.style.display="none",T.style.transform="rotate(-90deg)"),P.addEventListener("click",()=>{A.style.display!=="none"?(A.style.display="none",T.style.transform="rotate(-90deg)"):(A.style.display="",T.style.transform="rotate(0deg)"),this._skillsCollapsed[I]=A.style.display==="none"})};g("System Skills",i,!0),g("User Skills",c,!1),i.length===0&&c.length===0&&d.createEl("p",{text:`No skills found in ${n[s]}. Run setup to deploy skills.`,cls:"setting-item-description"}),this._advCollapsed===void 0&&(this._advCollapsed=!0);let p=e.createEl("div",{cls:"paperforge-collapsible-header"}),f=p.createEl("span",{text:"\u25B6",cls:"paperforge-collapsible-arrow"});f.style.transform=this._advCollapsed?"rotate(0deg)":"rotate(90deg)";let y=p.createEl("span",{cls:"paperforge-collapsible-title",text:"Advanced"}),b=p.createEl("span",{cls:"paperforge-collapsible-sub",text:"Memory + Vector DB + Embedding"}),m=e.createEl("div",{cls:"paperforge-collapsible-content"});m.style.display=this._advCollapsed?"none":"",p.addEventListener("click",()=>{this._advCollapsed=!this._advCollapsed,m.style.display=this._advCollapsed?"none":"",f.style.transform=this._advCollapsed?"rotate(0deg)":"rotate(90deg)"}),m.createEl("h4",{text:"Memory Layer"}),m.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_memory_desc"));let w=m.createEl("div",{cls:"paperforge-memory-status"}),E=this.app.vault.adapter.basePath;this.plugin._lastSyncTime&&!this._lastSyncTime&&(this._lastSyncTime=this.plugin._lastSyncTime),this._memoryStatusText===null&&(this._memoryStatusText=Ie(E)),this._renderMemoryStatusText(w,this._memoryStatusText,this._lastSyncTime),this._renderVectorSection(m)}_renderVectorSection(e){var i;if(e.createEl("h4",{text:"Vector Database"}),this.plugin.settings.features||(this.plugin.settings.features={memory_layer:!0,vector_db:!1}),e.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_vector_desc")),new C.Setting(e).setName(o("feat_vector_enable")).setDesc(o("feat_vector_enable_desc")).addToggle(c=>{c.setValue(!!this.plugin.settings.features.vector_db).onChange(d=>{this.plugin.settings.features.vector_db=d,this.plugin.saveSettings(),this._vectorDepsOk=null,this._embedStatusText=null,this.display()})}),!this.plugin.settings.features.vector_db)return;let r=this.app.vault.adapter.basePath,n=e.createEl("div",{cls:"paperforge-vec-header"}),a=n.createEl("span",{text:"\u25BC",cls:"paperforge-skills-arrow"});n.createEl("span",{cls:"paperforge-vec-header-label",text:o("feat_vector_config_label")});let s=e.createEl("div",{cls:"paperforge-vector-config"}),l=c=>{s.style.display=c?"none":"",a.style.transform=c?"rotate(-90deg)":"rotate(0deg)"};if(l(Qe(this._featurePanelsCollapsed,"vectorConfig",!1)),n.addEventListener("click",()=>{let c=ft(this._featurePanelsCollapsed,"vectorConfig",!1);l(c)}),this._vectorDepsOk===!0){this._renderVectorReady(s,r);return}if(this._vectorDepsOk===!1){this._renderVectorNoDeps(s);return}if(this._vectorDepsOk===null){let c=Re(r);this._vectorDepsOk=c&&(i=c.deps_installed)!=null?i:!1,this._vectorDepsOk&&(this._embedStatusText=be(r)),this.display()}}_renderApiConfig(e){new C.Setting(e).setName(o("feat_openai_key")).setDesc(o("feat_openai_key_desc")).addText(t=>{t.setPlaceholder("sk-...").setValue(this.plugin.settings.vector_db_api_key||"").onChange(r=>{this.plugin.settings.vector_db_api_key=r,this.plugin.saveSettings()})}),new C.Setting(e).setName(o("feat_api_base_url")).setDesc(o("feat_api_base_url_desc")).addText(t=>{t.setPlaceholder("https://api.openai.com/v1").setValue(this.plugin.settings.vector_db_api_base||"").onChange(r=>{this.plugin.settings.vector_db_api_base=r,this.plugin.saveSettings()})}),new C.Setting(e).setName(o("feat_api_model")).setDesc(o("feat_api_model_desc")).addText(t=>{t.setPlaceholder("text-embedding-3-small").setValue(this.plugin.settings.vector_db_api_model||"text-embedding-3-small").onChange(r=>{this.plugin.settings.vector_db_api_model=r,this.plugin.saveSettings()})})}_renderVectorNoDeps(e){e.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_deps_missing")),new C.Setting(e).setName(o("feat_install_deps")).setDesc(o("feat_install_deps_desc")).addButton(r=>{r.setButtonText(o("feat_install_btn")).setCta().onClick(async()=>{let n=this.app.vault.adapter.basePath,a=ce(n,this.plugin.settings);if(!a.path){new C.Notice(o("feat_no_python"));return}r.setButtonText(o("feat_installing")),r.setDisabled(!0);let s="chromadb openai",l=new C.Notice(o("feat_installing_pkgs").replace("{pkgs}",s),0);try{let i=Object.assign({},process.env,{PYTHONIOENCODING:"utf-8",PYTHONUTF8:"1"}),c=s.split(" ");await new Promise((d,g)=>{(0,j.execFile)(a.path,[...a.extraArgs,"-m","pip","install",...c],{cwd:n,timeout:3e5,env:i,windowsHide:!0},p=>{p?g(p):d()})}),l.hide(),new C.Notice(o("feat_install_done")),this._vectorDepsOk=!0,this._embedStatusText=be(n),this.display()}catch(i){l.hide(),new C.Notice(o("feat_install_failed")+(i.stderr||i.message||i)),r.setButtonText(o("feat_retry_btn")),r.setDisabled(!1)}})})}_renderVectorReady(e,t){e.createEl("div",{cls:"paperforge-desc-box"}).setText(be(t)),this._renderApiConfig(e);let n=e.createEl("div",{cls:"paperforge-embed-section"});n.createEl("div",{cls:"paperforge-embed-header"}).createEl("span",{text:o("feat_rebuild_vectors"),cls:"setting-item-name"});let s=n.createEl("div",{cls:"paperforge-embed-controls"}),l=n.createEl("div",{cls:"paperforge-embed-status-text"});(()=>{var y,b,m;s.empty(),l.empty();let c=(Re(t)||{}).build_state||{};this.plugin._embedProgress=this.plugin._embedProgress||{current:0,total:0,key:""},!this.plugin._embedProcess&&c.status==="running"&&(this.plugin._embedProgress={current:c.current||0,total:c.total||1,key:c.paper_id||""});let{current:d,total:g,key:p}=this.plugin._embedProgress;if(!!this.plugin._embedProcess||c.status==="running"){let x=s.createEl("div",{cls:"paperforge-progress-track"});x.style.cssText="flex:1;";let w=g>0?(d/g*100).toFixed(1):"0",E=x.createEl("div",{cls:"paperforge-progress-seg done"});if(E.style.cssText=`width:${w}%; min-width:${d>0?"2px":"0"};`,d{this._callPython(["embed","stop","--json"],{timeout:8e3}),this.plugin._embedProcess&&(this.plugin._embedProcess.kill(),this.plugin._embedProcess=null),this.display()})}else{let x=Re(t),w=((y=x==null?void 0:x.chunk_count)!=null?y:0)+((b=x==null?void 0:x.body_chunk_count)!=null?b:0)+((m=x==null?void 0:x.object_chunk_count)!=null?m:0),E=w>0,_=x?!!x.corrupted:!1,v=S=>{if(!ce(t,this.plugin.settings).path){new C.Notice(o("feat_no_python"));return}let A=Object.assign({},process.env,{PYTHONIOENCODING:"utf-8",PYTHONUTF8:"1",VECTOR_DB_API_KEY:this.plugin.settings.vector_db_api_key||"",VECTOR_DB_API_BASE:this.plugin.settings.vector_db_api_base||"",VECTOR_DB_API_MODEL:this.plugin.settings.vector_db_api_model||""});this.plugin._embedStderr="",this.plugin._embedProgress={current:0,total:0,key:""},this.plugin._embedProcess=this._callPython(["embed","build",S],{stream:!0,env:A,onData:T=>{let I=T.toString("utf-8").split(` -`);for(let z of I)if(z.startsWith("EMBED_START:"))this.plugin._embedProgress.total=parseInt(z.split(":")[1])||0;else if(z.startsWith("EMBED_PROGRESS:")){let O=z.split(":");this.plugin._embedProgress.current=parseInt(O[1])||0,this.plugin._embedProgress.key=O[3]||""}else z.startsWith("EMBED_DONE")&&(this.plugin._embedProcess=null,this.plugin._embedProgress.current=this.plugin._embedProgress.total);this.display()},onStderr:T=>{this.plugin._embedStderr||(this.plugin._embedStderr=""),this.plugin._embedStderr+=T.toString("utf-8")},onError:T=>{this.plugin._embedProcess=null,new C.Notice(o("feat_build_failed")+": "+(T.message||T)),this.display()},onClose:T=>{if(this.plugin._embedProcess=null,T===0)this.plugin._embedProgress.current=this.plugin._embedProgress.total,this.plugin.saveSettings(),this._embedStatusText=be(t),new C.Notice(o("feat_build_complete"));else{this._embedStatusText=null;let I=(this.plugin._embedStderr||"").slice(0,200);new C.Notice(o("feat_build_failed")+(I?": "+I:""),8e3)}this.plugin._embedStderr="",this.display(),this._refreshSnapshots(t)}}),this.display()};if(_){let S=n.createEl("div");S.style.cssText="padding:8px 12px; margin:8px 0; background:var(--background-modifier-warning); border-radius:4px; font-size:12px; display:flex; align-items:center; justify-content:space-between;",S.createEl("span",{text:o("feat_vector_corrupted")});let P=S.createEl("button",{text:o("feat_vector_rebuild_force_btn")});P.className="mod-cta",P.addEventListener("click",()=>v("--force"))}E&&!_&&s.createEl("span",{text:w+" chunks embedded",cls:"setting-item-description"});let k=s.createEl("button");if(k.setText(E?o("feat_rebuild_btn"):o("feat_build_btn")),k.addClass("mod-cta"),k.addEventListener("click",()=>v("--resume")),!_&&E){let S=s.createEl("button");S.setText(o("feat_vector_rebuild_force_btn")),S.style.marginLeft="6px",S.addEventListener("click",()=>v("--force"))}}})()}_getCurrentModelKey(){return this.plugin.settings.vector_db_api_model||"text-embedding-3-small"}_parseEmbedStatus(e){let t={};return e&&(e.split(` -`).forEach(r=>{let n=r.match(/^\s*([^:]+):\s*(.*)/);n&&(t[n[1].trim()]=n[2].trim())}),t.db_exists!==void 0&&(t.db_exists=t.db_exists==="True"),t.chunk_count!==void 0&&(t.chunk_count=parseInt(t.chunk_count,10)||0)),t}_getPythonDesc(e,t){return t==="stale"?`[!!] ${e} (stale \u2014 path no longer exists, update or clear the override below)`:t==="manual"?`${e} (manual)`:`${e} (auto-detected)`}_refreshPythonInterpDesc(e,t){let r=this._pythonInterpDescEl;r&&(t==="stale"?r.textContent=`[!!] ${e} (stale \u2014 path no longer exists, update or clear the override below)`:t==="manual"?r.textContent=`${e} (manual)`:r.textContent=`${e} (auto-detected)`)}_validatePythonOverride(){let e=this.plugin.settings.python_path?this.plugin.settings.python_path.trim():"",t=this._customPathDescEl;if(!e){let r="\u8BF7\u8F93\u5165\u8DEF\u5F84 / Enter a path first";t&&(t.innerHTML=`\u2717 ${r}`),new C.Notice(r);return}if(!N.existsSync(e)){let r="\u8DEF\u5F84\u4E0D\u5B58\u5728 / Path does not exist";t&&(t.innerHTML=`\u2717 ${r}`),new C.Notice(r,4e3);return}try{N.accessSync(e,N.constants.X_OK)}catch(r){let n="\u4E0D\u53EF\u6267\u884C / Not executable";t&&(t.innerHTML=`\u2717 ${n}`),new C.Notice(n,4e3);return}(0,j.execFile)(e,["--version"],{timeout:8e3},(r,n)=>{if(r||!n){let i="\u65E0\u6CD5\u8FD0\u884C / Cannot run";t&&(t.innerHTML=`\u2717 ${i}`),new C.Notice(i,4e3);return}let a=n.match(/Python (\d+)\.(\d+)/);if(!a){let i="\u65E0\u6CD5\u89E3\u6790\u7248\u672C / Cannot parse version";t&&(t.innerHTML=`\u2717 ${i}`),new C.Notice(i,4e3);return}let s=parseInt(a[1],10),l=parseInt(a[2],10);if(s<3||s===3&&l<10){let i="Python \u7248\u672C\u8FC7\u4F4E\uFF0C\u9700\u8981 3.10+ / Python version too low, need 3.10+";t&&(t.innerHTML=`\u2717 ${i}`),new C.Notice(i,4e3);return}(0,j.execFile)(e,["-m","pip","--version"],{timeout:8e3},i=>{if(i){let c=`\u2713 Python ${s}.${l} \u6709\u6548\uFF0C\u4F46\u672A\u68C0\u6D4B\u5230 pip / Valid, but pip not found`;t&&(t.innerHTML=`\u26A0 ${c}`),new C.Notice(c,4e3)}else{let c=`\u2713 Python ${s}.${l} \u6709\u6548 / Valid`;t&&(t.innerHTML=`${c}`),new C.Notice(c,4e3)}})})}_syncRuntime(e){let t=this.app.vault.adapter.basePath,{path:r,extraArgs:n=[]}=L(t,this.plugin.settings,void 0,void 0),a=this.plugin.manifest.version,s=ct(r,a,n);e.setDisabled(!0),e.setButtonText(o("runtime_health_syncing"));let l=(c,d)=>(console.log(`[PaperForge] Sync Runtime: trying ${d}`),pt(s.cmd,c,t,s.timeout,void 0,me())),i=()=>{let c="opencode";try{let f=N.readFileSync(Z.join(t,"paperforge.json"),"utf-8"),y=JSON.parse(f);y.agent_key&&(c=y.agent_key)}catch(f){}let d=[...n,"-c",'from paperforge.services.skill_deploy import deploy_skills; from pathlib import Path; r=deploy_skills(vault=Path(r"'+t.replace(/\\/g,"\\\\")+'"), agent_key="'+c+'", overwrite=True); print("skills deployed" if r["skill_deployed"] else "skills skipped", flush=True)'],g=(0,j.spawn)(r,d,{cwd:t,timeout:3e4,windowsHide:!0}),p="";g.stdout.on("data",f=>{p+=f.toString("utf-8")}),g.on("close",f=>{console.log(`[PaperForge] Skill deploy: ${p.trim()} (exit ${f})`)})};l(s.pypiArgs,"PyPI").then(c=>{if(c.exitCode===0){console.log("[PaperForge] Sync Runtime: installed via PyPI"),i(),new C.Notice(o("runtime_health_sync_done").replace("{0}",a),5e3),this.display();return}console.warn("[PaperForge] Sync Runtime: PyPI failed, falling back to git..."),l(s.gitArgs,"git").then(d=>{d.exitCode===0?(console.log("[PaperForge] Sync Runtime: installed via git"),i(),new C.Notice(o("runtime_health_sync_done").replace("{0}",a),5e3),this.display()):(e.setDisabled(!1),e.setButtonText(o("runtime_health_sync")),console.error("[PaperForge] git fallback stderr:",d.stderr),new C.Notice(o("runtime_health_sync_fail").replace("{0}","pip exit code "+d.exitCode),8e3))})})}_debouncedSave(){clearTimeout(this._saveTimeout),this._saveTimeout=setTimeout(()=>this.plugin.saveSettings(),500)}_preCheck(e){var a;let t=this.app.vault.adapter.basePath,{path:r,extraArgs:n=[]}=L(t,(a=this.plugin)==null?void 0:a.settings,void 0,void 0);(0,j.execFile)(r,[...n,"--version"],{timeout:8e3},(s,l)=>{let i=[];i.push({label:"Python",ok:!s,detail:s?o("check_python_fail"):l.trim()});let c=!1,d=process.env.HOME||process.env.USERPROFILE||kt.homedir()||"";if(process.platform==="darwin")c=["/Applications/Zotero.app",Z.join(d,"Applications","Zotero.app")].some(x=>{try{return N.existsSync(x)}catch(w){return!1}});else if(process.platform==="win32"){let m=process.env.ProgramFiles||"",x=process.env.LOCALAPPDATA||"";c=[Z.join(m,"Zotero"),Z.join(m,"(x86)","Zotero"),Z.join(x,"Programs","Zotero"),Z.join(x,"Zotero"),Z.join(d,"AppData","Local","Programs","Zotero")].filter(Boolean).some(E=>{try{return N.existsSync(E)}catch(_){return!1}})}else c=[Z.join(d,".local","share","zotero","zotero"),"/usr/bin/zotero","/usr/local/bin/zotero"].some(x=>{try{return N.existsSync(x)}catch(w){return!1}});let g=this.plugin.settings.zotero_data_dir;if(!c&&g)try{c=N.existsSync(g)}catch(m){}i.push({label:"Zotero",ok:c,detail:c?o("check_zotero_ok"):o("check_zotero_fail")});let p=!1,f=process.env.APPDATA||"";process.platform==="win32"&&f&&(p=Me(Z.join(f,"Zotero","Zotero","Profiles"))),!p&&process.platform==="darwin"&&d&&(p=Me(Z.join(d,"Library","Application Support","Zotero","Profiles"))),!p&&process.platform!=="win32"&&process.platform!=="darwin"&&d&&(p=Me(Z.join(d,".zotero","zotero","Profiles"))),!p&&g&&String(g).trim()&&(p=Ge(g.trim())),!p&&d&&(p=Ge(Z.join(d,"Zotero"))),i.push({label:"Better BibTeX",ok:p,detail:p?o("check_bbt_ok"):o("check_bbt_fail")});let y={true:"\u2713",false:"\u2717"};if(this._checkEl){this._checkEl.setText(i.map(x=>`${y[String(x.ok)]} ${x.label}: ${x.detail}`).join(` -`));let m=i.some(x=>!x.ok);this._checkEl.className=`paperforge-message msg-${m?"error":"ok"}`}let b=i.filter(m=>!m.ok);b.length>0&&new C.Notice(`[!!] \u672A\u901A\u8FC7: ${b.map(m=>m.label).join(", ")}`,6e3),e()})}_renderMaintenanceTab(e){e.createEl("h2",{text:o("tab_maintenance")||"\u7EF4\u62A4"});let t=this.app.vault.adapter.basePath,r=e.createEl("div"),n=(g,p)=>p==="retry_ocr"||p==="upgrade_legacy"?{cmd:["-m","paperforge","ocr","redo",...g],timeout:3e5}:p==="rebuild_result"?{cmd:["-m","paperforge","ocr","rebuild",...g],timeout:12e4}:null,a=null;try{a=xt(t)}catch(g){}let s=L(t,this.plugin.settings,N,j.execFileSync);if(!s.path){r.createEl("p",{text:"\u26A0 Python \u672A\u914D\u7F6E\uFF0C\u8BF7\u5148\u5728\u300C\u5B89\u88C5\u300D\u6807\u7B7E\u9875\u914D\u7F6E\u3002",cls:"setting-item-description"});return}let l=g=>{r.empty();let p=g.filter(m=>m.visible_in_maintenance);if(p.length===0){r.createEl("p",{text:o("maintenance_all_good")||"\u2705 \u5168\u90E8\u6B63\u5E38"});return}let f=s.path,y=s.extraArgs||[],b=[{key:"retry",title:o("maintenance_group_retry")||"\u9700\u8981\u91CD\u8BD5",items:[]},{key:"rebuild",title:o("maintenance_group_rebuild")||"\u53EF\u91CD\u5EFA\u7ED3\u679C",items:[]},{key:"legacy_optional",title:o("maintenance_group_legacy")||"\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09",items:[]}];for(let m of p){let x=b.find(w=>w.key===m.display_group);x&&x.items.push(m)}for(let m of b){if(m.items.length===0)continue;let x=m.key==="legacy_optional",w=x?r.createEl("details"):r.createEl("div");x?w.createEl("summary").createEl("strong",{text:m.title+" ("+m.items.length+")"}):w.createEl("h3",{text:m.title+" ("+m.items.length+")"});let E=new Map;for(let F of m.items)E.set(F.key,!1);let _=w.createEl("div",{cls:"pf-maint-toolbar"}),v=_.createEl("button",{text:"\u5168\u9009"}),k=_.createEl("button",{text:"\u53D6\u6D88\u5168\u9009"}),S=_.createEl("button",{text:"\u25B6 \u6267\u884C\u5DF2\u9009",cls:"mod-cta"}),P=_.createEl("span",{cls:"pf-maint-exec-label"}),A=()=>{let F=m.items.filter(D=>E.get(D.key)).length;P.setText("\u5DF2\u9009 "+F+" \u7BC7")};A(),v.addEventListener("click",()=>{for(let D of m.items)E.set(D.key,!0);A(),w.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach(D=>{D.checked=!0})}),k.addEventListener("click",()=>{for(let D of m.items)E.set(D.key,!1);A(),w.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach(D=>{D.checked=!1})}),S.addEventListener("click",()=>{let F=m.items.filter(D=>E.get(D.key));if(F.length===0){new C.Notice("\u8BF7\u5148\u9009\u62E9\u8981\u5904\u7406\u7684\u8BBA\u6587\u3002");return}for(let D of F){let X=n([D.key],D.display_action);X&&(0,j.execFile)(f,[...y,...X.cmd],{cwd:t,timeout:X.timeout,windowsHide:!0},()=>{new C.Notice(D.display_label+" \u2014 "+D.key)})}});let I=w.createEl("div",{cls:"pf-maint-table-wrap"}).createEl("table",{cls:"pf-maint-table"}),z=I.createEl("thead"),O=I.createEl("tbody"),U=z.insertRow();["","Key","Title","\u5EFA\u8BAE\u64CD\u4F5C","\u539F\u56E0","\u64CD\u4F5C"].forEach(F=>{let D=document.createElement("th");D.textContent=F,U.appendChild(D)});let q=F=>F==="retry_ocr"?o("maintenance_btn_retry")||"\u91CD\u8BD5":F==="rebuild_result"?o("maintenance_btn_rebuild")||"\u91CD\u5EFA":F==="upgrade_legacy"?o("maintenance_btn_upgrade")||"\u5347\u7EA7":"";for(let F of m.items){let D=O.insertRow(),X=D.insertCell();X.style.cssText="padding:3px 4px;text-align:center;";let ee=document.createElement("input");ee.type="checkbox",ee.className="pf-maint-sel",ee.checked=E.get(F.key)||!1,ee.addEventListener("change",()=>{E.set(F.key,ee.checked),A()}),X.appendChild(ee);let oe=D.insertCell();oe.style.cssText="padding:3px 4px;white-space:nowrap;font-size:11px;max-width:90px;overflow:hidden;text-overflow:ellipsis;",oe.textContent=F.key;let ve=D.insertCell();ve.style.cssText="padding:3px 4px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis;",ve.textContent=F.title||F.key;let de=D.insertCell();de.style.cssText="padding:3px 4px;white-space:nowrap;",de.textContent=F.display_label;let we=D.insertCell();we.style.cssText="padding:3px 4px;white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis;font-size:11px;color:var(--text-muted);",we.textContent=F.display_reason||"";let Se=D.insertCell();Se.style.cssText="padding:3px 4px;text-align:center;white-space:nowrap;";let ge=document.createElement("button");ge.textContent=q(F.display_action),ge.textContent&&(ge.addEventListener("click",()=>{let R=n([F.key],F.display_action);R&&(0,j.execFile)(f,[...y,...R.cmd],{cwd:t,timeout:R.timeout,windowsHide:!0},()=>{new C.Notice(F.display_label+" \u2014 "+F.key)})}),Se.appendChild(ge))}}};if(a){let g=Object.values(a.papers);l(g)}else r.createEl("p",{text:"\u6B63\u5728\u52A0\u8F7D OCR \u7EF4\u62A4\u6570\u636E\u2026"});Et(t,s.path,s.extraArgs||[],a||null).then(g=>{g.changed?(l(g.data),$e(t,{manifest:{},papers:Object.fromEntries(g.data.map(p=>[p.key,p])),cached_at:new Date().toISOString()})):a||(l(g.data),$e(t,{manifest:{},papers:Object.fromEntries(g.data.map(p=>[p.key,p])),cached_at:new Date().toISOString()}))}).catch(()=>{a||(r.empty(),r.createEl("p",{text:"\u65E0\u6CD5\u52A0\u8F7D OCR \u6570\u636E\u3002\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 paperforge \u5E76\u8FD0\u884C\u8FC7 OCR\u3002",cls:"setting-item-description"}))}),e.createEl("hr"),e.createEl("h3",{text:"\u5168\u5C40\u64CD\u4F5C"});let i=e.createEl("div",{cls:"pf-maint-global"});i.createEl("button",{text:"\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15"}).addEventListener("click",()=>{new C.Notice("\u6B63\u5728\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15\u2026"),(0,j.execFile)(s.path,[...s.extraArgs||[],"-m","paperforge","embed","build","--force"],{cwd:t,timeout:3e5,windowsHide:!0},()=>{new C.Notice("\u641C\u7D22\u7D22\u5F15\u91CD\u5EFA\u5B8C\u6210\u3002")})}),i.createEl("button",{text:"\u91CD\u5EFA\u8BB0\u5FC6\u5E93"}).addEventListener("click",()=>{new C.Notice("\u6B63\u5728\u91CD\u5EFA\u8BB0\u5FC6\u5E93\u2026"),(0,j.execFile)(s.path,[...s.extraArgs||[],"-m","paperforge","repair","--fix"],{cwd:t,timeout:12e4,windowsHide:!0},()=>{new C.Notice("\u8BB0\u5FC6\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002")})})}_renderReleaseNotesTab(e){e.createEl("h2",{text:"\u66F4\u65B0\u4E0E\u624B\u518C"}),e.createEl("h3",{text:"\u7248\u672C\u66F4\u65B0\u8BB0\u5F55"});let t=wt.default.versions||[];for(let a of t){let s=e.createEl("div",{cls:"paperforge-release-card"}),l=s.createEl("div",{cls:"paperforge-release-header"});if(l.createEl("strong",{text:`v${a.version} \u2014 ${a.title}`}),l.createEl("span",{cls:"paperforge-release-date",text:` (${a.date})`}),a.breaking_or_migration&&a.breaking_or_migration.length>0){let i=s.createEl("div",{cls:"paperforge-release-section"});i.createEl("div",{cls:"paperforge-release-label",text:"\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F"});for(let c of a.breaking_or_migration)i.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.new_features&&a.new_features.length>0){let i=s.createEl("div",{cls:"paperforge-release-section"});i.createEl("div",{cls:"paperforge-release-label",text:"\u65B0\u529F\u80FD"});for(let c of a.new_features)i.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.fixes&&a.fixes.length>0){let i=s.createEl("div",{cls:"paperforge-release-section"});i.createEl("div",{cls:"paperforge-release-label",text:"\u4FEE\u590D"});for(let c of a.fixes)i.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.recommended_actions&&a.recommended_actions.length>0){let i=s.createEl("div",{cls:"paperforge-release-section paperforge-release-recommended"});i.createEl("div",{cls:"paperforge-release-label",text:"\u5EFA\u8BAE\u64CD\u4F5C"});for(let c of a.recommended_actions)i.createEl("div",{cls:"paperforge-release-item paperforge-release-item-bold",text:`\u2022 ${c}`})}}e.createEl("h3",{text:"\u4F7F\u7528\u624B\u518C"}),e.createEl("div",{cls:"paperforge-manual-links"}).createEl("a",{text:"\u2192 \u67E5\u770B\u5B8C\u6574\u4F7F\u7528\u624B\u518C\uFF08GitHub\uFF09",href:"https://github.com/LLLin000/PaperForge/blob/master/docs/user-manual.md"}).setAttr("target","_blank")}};var B=require("obsidian"),pe=$(require("fs")),Oe=$(require("path")),fe=require("child_process");var Be=$(require("path"));function St(h){if(!h)return null;let u=Be.dirname(h);for(;;){let e=Be.basename(u);if(!e||e===".")break;let t=e.match(/^([A-Z0-9]{8})(?:\s*-\s*.*)?$/i);if(t)return t[1];let r=Be.dirname(u);if(r===u)break;u=r}return null}var V=$(require("fs")),he=$(require("path"));function Ae(h){return Q(h).ocrDir}function jt(h,u){let e=he.join(Ae(h),u,"versions","manifest.json");try{if(!V.existsSync(e))return null;let t=V.readFileSync(e,"utf-8"),r=JSON.parse(t);if(r&&typeof r=="object"&&"versions"in r&&"current"in r){let n=r,a=n.versions,s=n.current;if(Array.isArray(a)&&s&&typeof s=="object"&&"label"in s)return r}return null}catch(t){return null}}function Ht(h){let u=Ae(h);try{return V.existsSync(u)?V.readdirSync(u,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name):[]}catch(e){return[]}}function tt(h){let u=Ht(h),e=[];for(let t of u){let r=jt(h,t);if(!r)continue;let n=r.versions.map(s=>s.label),a=0;for(let s of n){let l=he.join(Ae(h),t,"versions",s,"fulltext.md");try{V.existsSync(l)&&(a+=V.statSync(l).size)}catch(i){}}e.push({key:t,title:t.replace(/_/g," "),versions:r.versions,currentLabel:r.current.label,totalSize:a})}return e.sort((t,r)=>t.title.localeCompare(r.title)),e}function Ct(h,u,e){let t=Ae(h),r=he.join(t,u,"versions",e,"fulltext.md"),n=he.join(t,u,"render"),a=he.join(n,"fulltext.md");try{return V.existsSync(r)?(V.existsSync(n)||V.mkdirSync(n,{recursive:!0}),V.copyFileSync(r,a),!0):!1}catch(s){return!1}}function Ft(h,u,e,t){var p;let r=Ae(h),n=he.join(r,u,"versions",e,"fulltext.md"),a=he.join(r,u,"versions",t,"fulltext.md"),s="",l="";try{V.existsSync(n)&&(s=V.readFileSync(n,"utf-8"))}catch(f){}try{V.existsSync(a)&&(l=V.readFileSync(a,"utf-8"))}catch(f){}let i=Pt(s),c=Pt(l),d=Math.max(i.length,c.length),g=[];for(let f=0;f0)e.push(t.join(` + `,document.head.appendChild(a)}let t=e.createDiv({cls:"paperforge-settings-tabs"}),r=[{id:"setup",label:o("tab_setup")||"\u5B89\u88C5"},{id:"features",label:o("tab_features")||"\u529F\u80FD"},{id:"maintenance",label:o("tab_maintenance")||"\u7EF4\u62A4"},{id:"release-notes",label:"\u66F4\u65B0\u4E0E\u624B\u518C"}],n={};r.forEach(a=>{t.createEl("button",{cls:"paperforge-settings-tab"+(a.id===this.activeTab?" paperforge-settings-tab--active":""),text:a.label}).addEventListener("click",()=>{this.activeTab=a.id,this.display()})}),r.forEach(a=>{n[a.id]=e.createDiv({cls:"paperforge-tab-content"+(a.id===this.activeTab?" paperforge-tab-content--active":"")})}),this.activeTab==="setup"?this._renderSetupTab(n.setup):this.activeTab==="features"?this._renderFeaturesTab(n.features):this.activeTab==="maintenance"?this._renderMaintenanceTab(n.maintenance):this._renderReleaseNotesTab(n["release-notes"])}_renderSetupTab(e){let t=this.app.vault.adapter.basePath;this.plugin.settings.vault_path||(this.plugin.settings.vault_path=t,this._debouncedSave()),this.plugin.settings.setup_complete&&($.existsSync(X.join(t,"paperforge.json"))||(this.plugin.settings.setup_complete=!1,this._debouncedSave())),e.createEl("h2",{text:o("header_title")||"PaperForge"}),e.createEl("p",{text:o("desc"),cls:"paperforge-settings-desc"});let n=e.createEl("div",{cls:"paperforge-setup-bar"}).createEl("span",{cls:"paperforge-setup-label"});this.plugin.settings.setup_complete?(n.setText(o("setup_done")),n.addClass("paperforge-setup-done")):(n.setText(o("setup_pending")),n.addClass("paperforge-setup-pending"));let a=this.app.vault.adapter.basePath,s=N(a,this.plugin.settings,void 0,void 0),i=s.path,l=this.plugin.settings._python_path_stale?"stale":s.source,c=new R.Setting(e).setName(o("field_python_interp")).setDesc(this._getPythonDesc(i,l));this._pythonInterpDescEl=c.descEl;let d=new R.Setting(e).setName(o("field_python_custom")).setDesc("");this._customPathDescEl=d.descEl,d.addText(k=>{k.setPlaceholder("e.g. C:\\Python310\\python.exe").setValue(this.plugin.settings.python_path||"").onChange(g=>{if(this.plugin.settings.python_path=g,this.plugin.saveSettings(),g&&g.trim()){let T=$.existsSync(g.trim());this.plugin.settings._python_path_stale=!T}else this.plugin.settings._python_path_stale=!1;let v=N(this.app.vault.adapter.basePath,this.plugin.settings,void 0,void 0),w=this.plugin.settings._python_path_stale?"stale":v.source;this._pythonInterpDescEl&&(this._pythonInterpDescEl.textContent=this._getPythonDesc(v.path,w))})}),d.addButton(k=>{k.setButtonText(o("btn_validate")).onClick(()=>this._validatePythonOverride())}),e.createEl("h3",{text:o("runtime_health")}),e.createEl("p",{text:o("runtime_health_desc"),cls:"paperforge-settings-desc"});let f=new R.Setting(e).setName("PaperForge").setDesc(o("runtime_health_checking")),p=f.descEl.createEl("span",{cls:"paperforge-runtime-badge"}),m=null;f.addButton(k=>{m=k,k.setButtonText(o("runtime_health_sync")).setDisabled(!0).onClick(()=>this._syncRuntime(k))});{let k=this.app.vault.adapter.basePath,{path:g,extraArgs:v=[]}=N(k,this.plugin.settings,void 0,void 0),w=this.plugin.manifest.version||"?";(0,K.execFile)(g,[...v,"-c","import paperforge; print(paperforge.__version__)"],{cwd:k,timeout:1e4},(T,P)=>{let L=this.plugin.settings.setup_complete,O=!T&&P?P.trim():null,z=O?`${o("runtime_health_plugin_ver").replace("{0}",w)} \u2192 ${o("runtime_health_package_ver").replace("{0}",O)}`:L?`Plugin v${w} \u2192 Python package not installed. Click "Sync Runtime" to install.`:`Plugin v${w} \u2192 Not configured. Please open the setup wizard first.`;f.setDesc(z),O===w?(p.setText(o("runtime_health_match")),p.className="paperforge-runtime-badge match",m&&m.setDisabled(!0)):O?(p.setText(o("runtime_health_mismatch")),p.className="paperforge-runtime-badge mismatch",m&&m.setDisabled(!1)):(p.setText(L?"Not installed":"Setup needed"),p.className="paperforge-runtime-badge missing",m&&m.setDisabled(!1))})}e.createEl("h3",{text:o("section_prep")}),e.createEl("p",{text:o("section_prep_desc"),cls:"paperforge-settings-desc"});let y=e.createEl("div",{cls:"paperforge-guide"}),x=[["prep_python","prep_python_desc"],["prep_zotero","prep_zotero_desc"],["prep_bbt","prep_bbt_desc"],["prep_key","prep_key_desc"]];for(let[k,g]of x){let v=y.createEl("div",{cls:"paperforge-guide-item"});v.createEl("strong",{text:o(k)}),v.createEl("span",{text:" \u2014 "+o(g)})}this._checkEl=e.createEl("div",{cls:"paperforge-message"});let _=!this.plugin.settings.setup_complete;new R.Setting(e).setName(o(_?"btn_install":"btn_reconfig")).setDesc(o(_?"btn_install_desc":"btn_reconfig_desc")).addButton(k=>{k.setButtonText(o(_?"btn_install":"btn_reconfig")).setCta().onClick(()=>{_?this._preCheck(()=>{new De(this.app,this.plugin).open()}):new De(this.app,this.plugin).open()})}),e.createEl("h3",{text:o("section_guide")});let b=e.createEl("div",{cls:"paperforge-guide"}),E=[["guide_open","guide_open_desc"],["guide_sync","guide_sync_desc"],["guide_ocr","guide_ocr_desc"]];for(let[k,g]of E){let v=b.createEl("div",{cls:"paperforge-guide-item"});v.createEl("strong",{text:o(k)}),v.createEl("span",{text:" \u2014 "+o(g)})}if(this.plugin.settings.setup_complete){e.createEl("h3",{text:o("section_config")});let k=e.createEl("div",{cls:"paperforge-summary"}),g=this.plugin.settings,v=this._pfConfig,w=[{label:o("dir_vault"),val:t},{label:o("dir_resources"),val:`${t}/${v==null?void 0:v.resources_dir}`},{label:" "+o("dir_notes"),val:`${t}/${v==null?void 0:v.resources_dir}/${v==null?void 0:v.literature_dir}`},{label:o("dir_base"),val:`${t}/${v==null?void 0:v.base_dir}`},{label:o("dir_system"),val:`${t}/${v==null?void 0:v.system_dir}`},{label:"API Key",val:g.paddleocr_api_key?o("api_key_set"):o("api_key_missing")},{label:o("field_zotero_data"),val:g.zotero_data_dir||o("not_set")}];for(let T of w){let P=k.createEl("div",{cls:"paperforge-summary-row"});P.createEl("span",{cls:"paperforge-summary-label",text:T.label}),P.createEl("span",{cls:"paperforge-summary-value",text:T.val})}}}_execMemoryStatus(e,t,r){(0,K.exec)(`"${e}" -m paperforge --vault "${t}" memory status --json`,{encoding:"utf-8",timeout:15e3},(n,a)=>{if(n){r("Status unavailable");return}try{let s=JSON.parse(a);if(s.ok){let i=s.data,l=i.fresh?"fresh":"stale";r(`Papers: ${i.paper_count_db} | ${l}${i.needs_rebuild?" - needs rebuild":""}`)}else r("DB not found. Run paperforge memory build.")}catch(s){r("Could not parse status.")}})}_execEmbedStatus(e,t,r){(0,K.exec)(`"${e}" -m paperforge --vault "${t}" embed status --json`,{encoding:"utf-8",timeout:15e3},(n,a)=>{if(n){r("Status unavailable");return}try{let s=JSON.parse(a);s.ok?r(`Chunks: ${s.data.chunk_count} | ${s.data.model} | ${s.data.mode}`):r("Could not parse status.")}catch(s){r("Could not parse status.")}})}_callPython(e,t){let r=this.app.vault.adapter.basePath,n=ue(r,this.plugin.settings),a=[...n.extraArgs,"-m","paperforge","--vault",r,...e];if(t&&t.stream){let s=(0,K.spawn)(n.path,a,{cwd:r,env:t.env||process.env,windowsHide:!0});return t.onData&&s.stdout.on("data",t.onData),t.onStderr&&s.stderr.on("data",t.onStderr),t.onError&&s.on("error",t.onError),s.on("close",t.onClose),s}return(0,K.execFile)(n.path,a,{cwd:r,timeout:t&&t.timeout||6e4},(s,i,l)=>{t&&t.onClose&&t.onClose(s?1:0,i,l)}),null}_renderMemoryStatusText(e,t,r){e.innerHTML="",e.createEl("span",{text:t,cls:"paperforge-memory-text"}),r==="syncing"?e.createEl("span",{text:"Syncing...",cls:"paperforge-sync-status"}):r&&e.createEl("span",{text:r,cls:"paperforge-sync-status"});let n=e.createEl("button",{cls:"paperforge-rebuild-btn",text:o("feat_memory_rebuild_btn")});n.title="Rebuild memory database",n.onclick=()=>{let s=this.app.vault.adapter.basePath,i=ue(s,this.plugin.settings);if(!i.path){new R.Notice(o("feat_no_python"));return}console.log("[PaperForge] Rebuilding memory:",i.path),n.setText(o("feat_memory_rebuilding")),n.setAttr("disabled",""),this._callPython(["memory","build"],{timeout:6e4,onClose:(l,c,d)=>{console.log("[PaperForge] memory build exit:",l?"FAIL:"+l:"OK",(c||"").slice(0,200),(d||"").slice(0,200)),n.setText(o("feat_memory_rebuild_btn")),n.removeAttribute("disabled"),l===0?new R.Notice(o("feat_memory_rebuild_done")):new R.Notice(o("feat_memory_rebuild_failed")+(d?" "+d.slice(0,80):"")),this._memoryStatusText=je(s),this._refreshSnapshots(s)}})};let a=e.createEl("button",{cls:"paperforge-refresh-btn",text:"\u21BB"});a.title="Sync now",a.onclick=()=>{this._memoryStatusText=null,this._runManualSync()}}_getBuildCommand(e){let t=this.app.vault.adapter.basePath,r=N(t,e,void 0,void 0);return r.path?`"${r.path}" -m paperforge --vault "${t}" sync`:null}_runManualSync(){let e=this.app.vault.adapter.basePath;if(!ue(e,this.plugin.settings).path)return;let r=document.querySelector(".paperforge-memory-status");r&&this._renderMemoryStatusText(r,"Checking...","syncing"),this.plugin._autoSyncRunning=!0,this._callPython(["sync"],{timeout:12e4,onClose:n=>{this.plugin._autoSyncRunning=!1,this._memoryStatusText=null,n===0&&(this._lastSyncTime=new Date().toLocaleTimeString(),this.plugin._lastSyncTime=this._lastSyncTime),this.display(),this._refreshSnapshots(e),ze(this.app,this.plugin,e)}})}_refreshSnapshots(e){let t=ue(e,this.plugin.settings),r=[...t.extraArgs,"-m","paperforge","--vault",e,"runtime-health","--json"];this._refreshPending=!0,(0,K.execFile)(t.path,r,{cwd:e,timeout:3e4,windowsHide:!0},(n,a,s)=>{this._refreshPending=!1,this._memoryStatusText=je(e),this._embedStatusText=Ee(e),this.display()})}_renderFeaturesTab(e){e.createEl("h3",{text:"Skills"});let t=e.createEl("div",{cls:"paperforge-desc-box"});t.setText(o("feat_skills_desc")),t.createEl("br"),t.createEl("span",{text:o("feat_skills_system")});let r={opencode:"OpenCode",claude:"Claude Code",codex:"Codex",cursor:"Cursor",windsurf:"Windsurf",github_copilot:"GitHub Copilot",gemini:"Gemini CLI"},n={opencode:".opencode/skills",claude:".claude/skills",codex:".codex/skills",cursor:".cursor/skills",windsurf:".windsurf/skills",github_copilot:".github/skills",gemini:".gemini/skills"},a=this.app.vault.adapter.basePath,s=this.plugin.settings.selected_skill_platform||"opencode";new R.Setting(e).setName(o("feat_agent_platform")).setDesc(o("feat_agent_platform_desc")).addDropdown(g=>{Object.entries(r).forEach(([v,w])=>g.addOption(v,w)),g.setValue(s).onChange(v=>{this.plugin.settings.selected_skill_platform=v,this.plugin.saveSettings(),this.display()})}).addExtraButton(g=>{g.setIcon("folder").setTooltip("Open skills folder").onClick(()=>{let v=n[s]||".opencode/skills",w=X.join(a,v);$.existsSync(w)?(0,K.exec)(`start "" "${w}"`):new R.Notice(`Skills folder not found: ${v}`)})});let i=X.join(a,n[s]),l=[],c=[];$.existsSync(i)&&$.readdirSync(i,{withFileTypes:!0}).forEach(g=>{if(!g.isDirectory())return;let v=X.join(i,g.name,"SKILL.md");if(!$.existsSync(v))return;let w=$.readFileSync(v,"utf-8"),T=w.match(/^name:\s*(.+)$/m),P=w.split(` +`),L=P.findIndex(M=>/^description:/.test(M)),O="";if(L>=0){let M=P[L].match(/^description:\s*(.+)$/);if(M&&M[1]&&M[1]!==">"&&M[1]!=="|-"&&M[1]!=="|")O=M[1].trim();else{for(let C=L+1;C{if(v.length===0)return;let T=d.createEl("div",{cls:"paperforge-skills-group"}),P=T.createEl("div",{cls:"paperforge-skills-collapse-header"}),L=T.createEl("div",{cls:"paperforge-skills-collapse-content"}),O=P.createEl("span",{text:"\u25BC",cls:"paperforge-skills-arrow"});P.createEl("h4",{text:`${g} (${v.length})`,cls:"paperforge-skills-subheader"}),v.forEach(D=>{let S=D.name+(D.version?" v"+D.version:""),M=w?" [system]":" [user]",C=D.desc||"",F=new R.Setting(L).setName(S+M).setDesc(C);F.settingEl.style.opacity=D.disabled?"0.4":"1",F.addToggle(A=>{A.setValue(!D.disabled).onChange(J=>{let G=!J,Q=D.content.match(/^disable-model-invocation:\s*(.+)$/m)?D.content.replace(/^disable-model-invocation:\s*.+$/m,`disable-model-invocation: ${G}`):D.content.replace(/^(---\r?\n)/,`$1disable-model-invocation: ${G} +`);$.writeFileSync(D.path,Q,"utf-8"),D.disabled=G,D.content=Q,F.settingEl.style.opacity=D.disabled?"0.4":"1"})})});let z=w?"system":"user";(this._skillsCollapsed[z]||!1)&&(L.style.display="none",O.style.transform="rotate(-90deg)"),P.addEventListener("click",()=>{L.style.display!=="none"?(L.style.display="none",O.style.transform="rotate(-90deg)"):(L.style.display="",O.style.transform="rotate(0deg)"),this._skillsCollapsed[z]=L.style.display==="none"})};f("System Skills",l,!0),f("User Skills",c,!1),l.length===0&&c.length===0&&d.createEl("p",{text:`No skills found in ${n[s]}. Run setup to deploy skills.`,cls:"setting-item-description"}),this._advCollapsed===void 0&&(this._advCollapsed=!0);let p=e.createEl("div",{cls:"paperforge-collapsible-header"}),m=p.createEl("span",{text:"\u25B6",cls:"paperforge-collapsible-arrow"});m.style.transform=this._advCollapsed?"rotate(0deg)":"rotate(90deg)";let y=p.createEl("span",{cls:"paperforge-collapsible-title",text:"Advanced"}),x=p.createEl("span",{cls:"paperforge-collapsible-sub",text:"Memory + Vector DB + Embedding"}),_=e.createEl("div",{cls:"paperforge-collapsible-content"});_.style.display=this._advCollapsed?"none":"",p.addEventListener("click",()=>{this._advCollapsed=!this._advCollapsed,_.style.display=this._advCollapsed?"none":"",m.style.transform=this._advCollapsed?"rotate(0deg)":"rotate(90deg)"}),_.createEl("h4",{text:"Memory Layer"}),_.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_memory_desc"));let E=_.createEl("div",{cls:"paperforge-memory-status"}),k=this.app.vault.adapter.basePath;this.plugin._lastSyncTime&&!this._lastSyncTime&&(this._lastSyncTime=this.plugin._lastSyncTime),this._memoryStatusText===null&&(this._memoryStatusText=je(k)),this._renderMemoryStatusText(E,this._memoryStatusText,this._lastSyncTime),this._renderVectorSection(_)}_renderVectorSection(e){var l;if(e.createEl("h4",{text:"Vector Database"}),this.plugin.settings.features||(this.plugin.settings.features={memory_layer:!0,vector_db:!1}),e.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_vector_desc")),new R.Setting(e).setName(o("feat_vector_enable")).setDesc(o("feat_vector_enable_desc")).addToggle(c=>{c.setValue(!!this.plugin.settings.features.vector_db).onChange(d=>{this.plugin.settings.features.vector_db=d,this.plugin.saveSettings(),this._vectorDepsOk=null,this._embedStatusText=null,this.display()})}),!this.plugin.settings.features.vector_db)return;let r=this.app.vault.adapter.basePath,n=e.createEl("div",{cls:"paperforge-vec-header"}),a=n.createEl("span",{text:"\u25BC",cls:"paperforge-skills-arrow"});n.createEl("span",{cls:"paperforge-vec-header-label",text:o("feat_vector_config_label")});let s=e.createEl("div",{cls:"paperforge-vector-config"}),i=c=>{s.style.display=c?"none":"",a.style.transform=c?"rotate(-90deg)":"rotate(0deg)"};if(i(rt(this._featurePanelsCollapsed,"vectorConfig",!1)),n.addEventListener("click",()=>{let c=gt(this._featurePanelsCollapsed,"vectorConfig",!1);i(c)}),this._vectorDepsOk===!0){this._renderVectorReady(s,r);return}if(this._vectorDepsOk===!1){this._renderVectorNoDeps(s);return}if(this._vectorDepsOk===null){let c=Ne(r);this._vectorDepsOk=c&&(l=c.deps_installed)!=null?l:!1,this._vectorDepsOk&&(this._embedStatusText=Ee(r)),this.display()}}_renderApiConfig(e){new R.Setting(e).setName(o("feat_openai_key")).setDesc(o("feat_openai_key_desc")).addText(t=>{t.setPlaceholder("sk-...").setValue(this.plugin.settings.vector_db_api_key||"").onChange(r=>{this.plugin.settings.vector_db_api_key=r,this.plugin.saveSettings()})}),new R.Setting(e).setName(o("feat_api_base_url")).setDesc(o("feat_api_base_url_desc")).addText(t=>{t.setPlaceholder("https://api.openai.com/v1").setValue(this.plugin.settings.vector_db_api_base||"").onChange(r=>{this.plugin.settings.vector_db_api_base=r,this.plugin.saveSettings()})}),new R.Setting(e).setName(o("feat_api_model")).setDesc(o("feat_api_model_desc")).addText(t=>{t.setPlaceholder("text-embedding-3-small").setValue(this.plugin.settings.vector_db_api_model||"text-embedding-3-small").onChange(r=>{this.plugin.settings.vector_db_api_model=r,this.plugin.saveSettings()})})}_renderVectorNoDeps(e){e.createEl("div",{cls:"paperforge-desc-box"}).setText(o("feat_deps_missing")),new R.Setting(e).setName(o("feat_install_deps")).setDesc(o("feat_install_deps_desc")).addButton(r=>{r.setButtonText(o("feat_install_btn")).setCta().onClick(async()=>{let n=this.app.vault.adapter.basePath,a=ue(n,this.plugin.settings);if(!a.path){new R.Notice(o("feat_no_python"));return}r.setButtonText(o("feat_installing")),r.setDisabled(!0);let s="chromadb openai",i=new R.Notice(o("feat_installing_pkgs").replace("{pkgs}",s),0);try{let l=Object.assign({},process.env,{PYTHONIOENCODING:"utf-8",PYTHONUTF8:"1"}),c=s.split(" ");await new Promise((d,f)=>{(0,K.execFile)(a.path,[...a.extraArgs,"-m","pip","install",...c],{cwd:n,timeout:3e5,env:l,windowsHide:!0},p=>{p?f(p):d()})}),i.hide(),new R.Notice(o("feat_install_done")),this._vectorDepsOk=!0,this._embedStatusText=Ee(n),this.display()}catch(l){i.hide(),new R.Notice(o("feat_install_failed")+(l.stderr||l.message||l)),r.setButtonText(o("feat_retry_btn")),r.setDisabled(!1)}})})}_renderVectorReady(e,t){e.createEl("div",{cls:"paperforge-desc-box"}).setText(Ee(t)),this._renderApiConfig(e);let n=e.createEl("div",{cls:"paperforge-embed-section"});n.createEl("div",{cls:"paperforge-embed-header"}).createEl("span",{text:o("retrieval_rebuild_vectors"),cls:"setting-item-name"});let s=n.createEl("div",{cls:"paperforge-embed-controls"}),i=n.createEl("div",{cls:"paperforge-embed-status-text",attr:{"aria-live":"polite"}});(()=>{s.empty(),i.empty();let c=Ne(t),d=c==null?void 0:c.build_state,f=d&&typeof d=="object"&&!Array.isArray(d)?d:{};this.plugin._embedProgress=this.plugin._embedProgress||{current:0,total:0,key:""},!this.plugin._embedProcess&&f.status==="running"&&(this.plugin._embedProgress={current:typeof f.current=="number"?f.current:0,total:typeof f.total=="number"?f.total:1,key:typeof f.paper_id=="string"?f.paper_id:""});let{current:p,total:m,key:y}=this.plugin._embedProgress,x=typeof(c==null?void 0:c.body_chunk_count)=="number"?c.body_chunk_count:0,_=typeof(c==null?void 0:c.object_chunk_count)=="number"?c.object_chunk_count:0,E=(typeof(c==null?void 0:c.chunk_count)=="number"?c.chunk_count:0)+x+_,k=E>0,g=c!==null&&typeof c.corrupted=="boolean"&&c.corrupted,v=!!this.plugin._embedProcess,w=!this.plugin._embedProcess&&f.status==="running",T=(c==null?void 0:c.deps_installed)!==void 0?!!c.deps_installed:!0,P=typeof f.status=="string"?f.status:"",L=typeof f.message=="string"?f.message:"",O=S=>{var F;if(S==="--resume"&&k&&!g){let A=o("retrieval_rebuild_warning").replace("{n}",String(E));if(!confirm(A))return}if(S==="--force"&&k&&!g){let A="Force rebuild will replace "+E+" existing chunk(s). Continue?";if(!confirm(A))return}if(!ue(t,this.plugin.settings).path){new R.Notice(o("retrieval_no_python"));return}let C=Object.assign({},process.env,{PYTHONIOENCODING:"utf-8",PYTHONUTF8:"1",VECTOR_DB_API_KEY:this.plugin.settings.vector_db_api_key||"",VECTOR_DB_API_BASE:this.plugin.settings.vector_db_api_base||"",VECTOR_DB_API_MODEL:this.plugin.settings.vector_db_api_model||""});this.plugin._embedStderr="",this.plugin._embedProgress={current:0,total:0,key:""},this.plugin._embedProcess=this._callPython(["embed","build",S],{stream:!0,env:C,onData:A=>{let G=(typeof A=="string"?A:Buffer.isBuffer(A)?A.toString("utf-8"):String(A)).split(` +`);for(let ee of G)if(ee.startsWith("EMBED_START:"))this.plugin._embedProgress.total=parseInt(ee.split(":")[1])||0;else if(ee.startsWith("EMBED_PROGRESS:")){let Q=ee.split(":");this.plugin._embedProgress.current=parseInt(Q[1])||0,this.plugin._embedProgress.key=Q[3]||""}else ee.startsWith("EMBED_DONE")&&(this.plugin._embedProcess=null,this.plugin._embedProgress.current=this.plugin._embedProgress.total);this.display()},onStderr:A=>{this.plugin._embedStderr||(this.plugin._embedStderr=""),this.plugin._embedStderr+=String(A)},onError:A=>{this.plugin._embedProcess=null,new R.Notice(o("feat_build_failed")+": "+(A.message||A)),this.display()},onClose:A=>{var J;if(clearInterval((J=this.plugin._embedPollInterval)!=null?J:void 0),this.plugin._embedPollInterval=null,this.plugin._embedProcess=null,A===0)this.plugin._embedProgress.current=this.plugin._embedProgress.total,this.plugin.saveSettings(),this._embedStatusText=Ee(t),new R.Notice(o("feat_build_complete"));else{this._embedStatusText=null;let G=(this.plugin._embedStderr||"").slice(0,200);new R.Notice(o("feat_build_failed")+(G?": "+G:""),8e3)}this.plugin._embedStderr="",this.display(),this._refreshSnapshots(t)}}),clearInterval((F=this.plugin._embedPollInterval)!=null?F:void 0),this.plugin._embedPollInterval=setInterval(()=>{this.plugin._embedPolling||(this.plugin._embedPolling=!0,this._callPython(["embed","status","--json"],{timeout:5e3,onClose:(A,J)=>{var G;if(this.plugin._embedPolling=!1,A===0&&J)try{let Q=JSON.parse(J).data;if(Q&&Q.build_state){let re=Q.build_state;(re.status==="stopping"||re.status==="idle")&&this.plugin._embedProcess&&(this.plugin._embedProcess=null,clearInterval((G=this.plugin._embedPollInterval)!=null?G:void 0),this.plugin._embedPollInterval=null,this.display()),re.current!==void 0&&re.total!==void 0&&(this.plugin._embedProgress.current=re.current,this.plugin._embedProgress.total=re.total||1,this.plugin._embedProgress.key=re.paper_id||"")}}catch(ee){}}}))},2e3),this.display()},z=Te(t),q=!1;z&&typeof z.summary=="object"&&z.summary!==null&&"status"in z.summary&&(q=z.summary.status==="version_mismatch");let D;switch(T?q?D="runtime-mismatch":P==="stopping"?D="stopping":v&&P==="running"?D="building":P==="failed"?D="failed":P==="stopped"?D="stopped":w?D="stale":g?D="corrupted":k?D="ready":D="idle":D="deps-missing",D){case"building":{let S=s.createEl("div",{cls:"paperforge-progress-track"});S.style.cssText="flex:1;";let M=m>0?(p/m*100).toFixed(1):"0",C=S.createEl("div",{cls:"paperforge-progress-seg done"});if(C.style.cssText=`width:${M}%; min-width:${p>0?"2px":"0"};`,p{this._callPython(["embed","stop","--json"],{timeout:8e3}),this.display()});break}case"stopping":{let S=s.createEl("div",{cls:"paperforge-progress-track"});S.style.cssText="flex:1; opacity:0.5;";let M=m>0?(p/m*100).toFixed(1):"0",C=S.createEl("div",{cls:"paperforge-progress-seg done"});if(C.style.cssText=`width:${M}%; min-width:${p>0?"2px":"0"};`,pO("--resume"));let M=s.createEl("button");M.setText(o("retrieval_force_rebuild")),M.style.marginLeft="6px",M.addEventListener("click",()=>O("--force"));break}case"stopped":{i.setText(o("retrieval_build_stopped"));let S=s.createEl("button");S.setText(o("retrieval_retry")),S.className="mod-cta",S.addEventListener("click",()=>O("--resume"));break}case"corrupted":{i.createEl("div",{cls:"paperforge-desc-box",text:o("feat_vector_corrupted"),attr:{style:"background:var(--background-modifier-warning);"}});let S=s.createEl("button");S.setText(o("retrieval_force_rebuild")),S.className="mod-cta",S.addEventListener("click",()=>O("--force"));break}case"stale":{i.createEl("div",{cls:"paperforge-desc-box",text:o("retrieval_build_stale"),attr:{style:"color:var(--text-warning);"}});let S=s.createEl("button");S.setText(o("retrieval_rebuild_vectors")),S.className="mod-cta",S.addEventListener("click",()=>O("--resume"));break}case"ready":{s.createEl("span",{text:E+" chunks embedded",cls:"setting-item-description"});let S=s.createEl("button");S.setText(o("retrieval_rebuild_vectors")),S.className="mod-cta",S.addEventListener("click",()=>O("--resume"));let M=s.createEl("button");M.setText(o("retrieval_force_rebuild")),M.style.marginLeft="6px",M.addEventListener("click",()=>O("--force"));break}case"deps-missing":{i.setText(o("retrieval_build_deps_missing"));let S=s.createEl("a");S.setText(o("feat_install_deps")),S.style.cssText="cursor:pointer; text-decoration:underline;",S.addEventListener("click",()=>{this.display()});break}case"runtime-mismatch":{i.createEl("div",{cls:"paperforge-desc-box",text:o("retrieval_build_runtime_mismatch"),attr:{style:"color:var(--text-warning);"}});let S=s.createEl("a");S.setText(o("runtime_health_sync")),S.style.cssText="cursor:pointer; text-decoration:underline;",S.addEventListener("click",()=>{this.display()});break}case"idle":default:{i.setText(o("retrieval_build_idle"));let S=s.createEl("button");S.setText(o("feat_build_btn")),S.className="mod-cta",S.addEventListener("click",()=>O("--resume"));break}}})()}_getCurrentModelKey(){return this.plugin.settings.vector_db_api_model||"text-embedding-3-small"}_parseEmbedStatus(e){let t={};return e&&(e.split(` +`).forEach(r=>{let n=r.match(/^\s*([^:]+):\s*(.*)/);n&&(t[n[1].trim()]=n[2].trim())}),t.db_exists!==void 0&&(t.db_exists=t.db_exists==="True"),t.chunk_count!==void 0&&(t.chunk_count=parseInt(t.chunk_count,10)||0)),t}_getPythonDesc(e,t){return t==="stale"?`[!!] ${e} (stale \u2014 path no longer exists, update or clear the override below)`:t==="manual"?`${e} (manual)`:`${e} (auto-detected)`}_refreshPythonInterpDesc(e,t){let r=this._pythonInterpDescEl;r&&(t==="stale"?r.textContent=`[!!] ${e} (stale \u2014 path no longer exists, update or clear the override below)`:t==="manual"?r.textContent=`${e} (manual)`:r.textContent=`${e} (auto-detected)`)}_validatePythonOverride(){let e=this.plugin.settings.python_path?this.plugin.settings.python_path.trim():"",t=this._customPathDescEl;if(!e){let r="\u8BF7\u8F93\u5165\u8DEF\u5F84 / Enter a path first";t&&(t.innerHTML=`\u2717 ${r}`),new R.Notice(r);return}if(!$.existsSync(e)){let r="\u8DEF\u5F84\u4E0D\u5B58\u5728 / Path does not exist";t&&(t.innerHTML=`\u2717 ${r}`),new R.Notice(r,4e3);return}try{$.accessSync(e,$.constants.X_OK)}catch(r){let n="\u4E0D\u53EF\u6267\u884C / Not executable";t&&(t.innerHTML=`\u2717 ${n}`),new R.Notice(n,4e3);return}(0,K.execFile)(e,["--version"],{timeout:8e3},(r,n)=>{if(r||!n){let l="\u65E0\u6CD5\u8FD0\u884C / Cannot run";t&&(t.innerHTML=`\u2717 ${l}`),new R.Notice(l,4e3);return}let a=n.match(/Python (\d+)\.(\d+)/);if(!a){let l="\u65E0\u6CD5\u89E3\u6790\u7248\u672C / Cannot parse version";t&&(t.innerHTML=`\u2717 ${l}`),new R.Notice(l,4e3);return}let s=parseInt(a[1],10),i=parseInt(a[2],10);if(s<3||s===3&&i<10){let l="Python \u7248\u672C\u8FC7\u4F4E\uFF0C\u9700\u8981 3.10+ / Python version too low, need 3.10+";t&&(t.innerHTML=`\u2717 ${l}`),new R.Notice(l,4e3);return}(0,K.execFile)(e,["-m","pip","--version"],{timeout:8e3},l=>{if(l){let c=`\u2713 Python ${s}.${i} \u6709\u6548\uFF0C\u4F46\u672A\u68C0\u6D4B\u5230 pip / Valid, but pip not found`;t&&(t.innerHTML=`\u26A0 ${c}`),new R.Notice(c,4e3)}else{let c=`\u2713 Python ${s}.${i} \u6709\u6548 / Valid`;t&&(t.innerHTML=`${c}`),new R.Notice(c,4e3)}})})}_syncRuntime(e){let t=this.app.vault.adapter.basePath,{path:r,extraArgs:n=[]}=N(t,this.plugin.settings,void 0,void 0),a=this.plugin.manifest.version,s=ut(r,a,n);e.setDisabled(!0),e.setButtonText(o("runtime_health_syncing"));let i=(c,d)=>(console.log(`[PaperForge] Sync Runtime: trying ${d}`),ht(s.cmd,c,t,s.timeout,void 0,be())),l=()=>{let c="opencode";try{let m=$.readFileSync(X.join(t,"paperforge.json"),"utf-8"),y=JSON.parse(m);y.agent_key&&(c=y.agent_key)}catch(m){}let d=[...n,"-c",'from paperforge.services.skill_deploy import deploy_skills; from pathlib import Path; r=deploy_skills(vault=Path(r"'+t.replace(/\\/g,"\\\\")+'"), agent_key="'+c+'", overwrite=True); print("skills deployed" if r["skill_deployed"] else "skills skipped", flush=True)'],f=(0,K.spawn)(r,d,{cwd:t,timeout:3e4,windowsHide:!0}),p="";f.stdout.on("data",m=>{p+=m.toString("utf-8")}),f.on("close",m=>{console.log(`[PaperForge] Skill deploy: ${p.trim()} (exit ${m})`)})};i(s.pypiArgs,"PyPI").then(c=>{if(c.exitCode===0){console.log("[PaperForge] Sync Runtime: installed via PyPI"),l(),new R.Notice(o("runtime_health_sync_done").replace("{0}",a),5e3),this.display();return}console.warn("[PaperForge] Sync Runtime: PyPI failed, falling back to git..."),i(s.gitArgs,"git").then(d=>{d.exitCode===0?(console.log("[PaperForge] Sync Runtime: installed via git"),l(),new R.Notice(o("runtime_health_sync_done").replace("{0}",a),5e3),this.display()):(e.setDisabled(!1),e.setButtonText(o("runtime_health_sync")),console.error("[PaperForge] git fallback stderr:",d.stderr),new R.Notice(o("runtime_health_sync_fail").replace("{0}","pip exit code "+d.exitCode),8e3))})})}_debouncedSave(){clearTimeout(this._saveTimeout),this._saveTimeout=setTimeout(()=>this.plugin.saveSettings(),500)}_preCheck(e){var a;let t=this.app.vault.adapter.basePath,{path:r,extraArgs:n=[]}=N(t,(a=this.plugin)==null?void 0:a.settings,void 0,void 0);(0,K.execFile)(r,[...n,"--version"],{timeout:8e3},(s,i)=>{let l=[];l.push({label:"Python",ok:!s,detail:s?o("check_python_fail"):i.trim()});let c=!1,d=process.env.HOME||process.env.USERPROFILE||St.homedir()||"";if(process.platform==="darwin")c=["/Applications/Zotero.app",X.join(d,"Applications","Zotero.app")].some(b=>{try{return $.existsSync(b)}catch(E){return!1}});else if(process.platform==="win32"){let _=process.env.ProgramFiles||"",b=process.env.LOCALAPPDATA||"";c=[X.join(_,"Zotero"),X.join(_,"(x86)","Zotero"),X.join(b,"Programs","Zotero"),X.join(b,"Zotero"),X.join(d,"AppData","Local","Programs","Zotero")].filter(Boolean).some(k=>{try{return $.existsSync(k)}catch(g){return!1}})}else c=[X.join(d,".local","share","zotero","zotero"),"/usr/bin/zotero","/usr/local/bin/zotero"].some(b=>{try{return $.existsSync(b)}catch(E){return!1}});let f=this.plugin.settings.zotero_data_dir;if(!c&&f)try{c=$.existsSync(f)}catch(_){}l.push({label:"Zotero",ok:c,detail:c?o("check_zotero_ok"):o("check_zotero_fail")});let p=!1,m=process.env.APPDATA||"";process.platform==="win32"&&m&&(p=Me(X.join(m,"Zotero","Zotero","Profiles"))),!p&&process.platform==="darwin"&&d&&(p=Me(X.join(d,"Library","Application Support","Zotero","Profiles"))),!p&&process.platform!=="win32"&&process.platform!=="darwin"&&d&&(p=Me(X.join(d,".zotero","zotero","Profiles"))),!p&&f&&String(f).trim()&&(p=Qe(f.trim())),!p&&d&&(p=Qe(X.join(d,"Zotero"))),l.push({label:"Better BibTeX",ok:p,detail:p?o("check_bbt_ok"):o("check_bbt_fail")});let y={true:"\u2713",false:"\u2717"};if(this._checkEl){this._checkEl.setText(l.map(b=>`${y[String(b.ok)]} ${b.label}: ${b.detail}`).join(` +`));let _=l.some(b=>!b.ok);this._checkEl.className=`paperforge-message msg-${_?"error":"ok"}`}let x=l.filter(_=>!_.ok);x.length>0&&new R.Notice(`[!!] \u672A\u901A\u8FC7: ${x.map(_=>_.label).join(", ")}`,6e3),e()})}_renderMaintenanceTab(e){e.createEl("h2",{text:o("tab_maintenance")||"\u7EF4\u62A4"});let t=this.app.vault.adapter.basePath,r=e.createEl("div"),n=(f,p)=>p==="retry_ocr"||p==="upgrade_legacy"?{cmd:["-m","paperforge","ocr","redo",...f],timeout:3e5}:p==="rebuild_result"?{cmd:["-m","paperforge","ocr","rebuild",...f],timeout:12e4}:null,a=null;try{a=kt(t)}catch(f){}let s=N(t,this.plugin.settings,$,K.execFileSync);if(!s.path){r.createEl("p",{text:"\u26A0 Python \u672A\u914D\u7F6E\uFF0C\u8BF7\u5148\u5728\u300C\u5B89\u88C5\u300D\u6807\u7B7E\u9875\u914D\u7F6E\u3002",cls:"setting-item-description"});return}let i=f=>{r.empty();let p=f.filter(_=>_.visible_in_maintenance);if(p.length===0){r.createEl("p",{text:o("maintenance_all_good")||"\u2705 \u5168\u90E8\u6B63\u5E38"});return}let m=s.path,y=s.extraArgs||[],x=[{key:"retry",title:o("maintenance_group_retry")||"\u9700\u8981\u91CD\u8BD5",items:[]},{key:"rebuild",title:o("maintenance_group_rebuild")||"\u53EF\u91CD\u5EFA\u7ED3\u679C",items:[]},{key:"legacy_optional",title:o("maintenance_group_legacy")||"\u53EF\u5347\u7EA7\u65E7\u7ED3\u679C\uFF08\u53EF\u9009\uFF09",items:[]}];for(let _ of p){let b=x.find(E=>E.key===_.display_group);b&&b.items.push(_)}for(let _ of x){if(_.items.length===0)continue;let b=_.key==="legacy_optional",E=b?r.createEl("details"):r.createEl("div");b?E.createEl("summary").createEl("strong",{text:_.title+" ("+_.items.length+")"}):E.createEl("h3",{text:_.title+" ("+_.items.length+")"});let k=new Map;for(let C of _.items)k.set(C.key,!1);let g=E.createEl("div",{cls:"pf-maint-toolbar"}),v=g.createEl("button",{text:"\u5168\u9009"}),w=g.createEl("button",{text:"\u53D6\u6D88\u5168\u9009"}),T=g.createEl("button",{text:"\u25B6 \u6267\u884C\u5DF2\u9009",cls:"mod-cta"}),P=g.createEl("span",{cls:"pf-maint-exec-label"}),L=()=>{let C=_.items.filter(F=>k.get(F.key)).length;P.setText("\u5DF2\u9009 "+C+" \u7BC7")};L(),v.addEventListener("click",()=>{for(let F of _.items)k.set(F.key,!0);L(),E.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach(F=>{F.checked=!0})}),w.addEventListener("click",()=>{for(let F of _.items)k.set(F.key,!1);L(),E.querySelectorAll("input[type=checkbox].pf-maint-sel").forEach(F=>{F.checked=!1})}),T.addEventListener("click",()=>{let C=_.items.filter(F=>k.get(F.key));if(C.length===0){new R.Notice("\u8BF7\u5148\u9009\u62E9\u8981\u5904\u7406\u7684\u8BBA\u6587\u3002");return}for(let F of C){let A=n([F.key],F.display_action);A&&(0,K.execFile)(m,[...y,...A.cmd],{cwd:t,timeout:A.timeout,windowsHide:!0},()=>{new R.Notice(F.display_label+" \u2014 "+F.key)})}});let z=E.createEl("div",{cls:"pf-maint-table-wrap"}).createEl("table",{cls:"pf-maint-table"}),q=z.createEl("thead"),D=z.createEl("tbody"),S=q.insertRow();["","Key","Title","\u5EFA\u8BAE\u64CD\u4F5C","\u539F\u56E0","\u64CD\u4F5C"].forEach(C=>{let F=document.createElement("th");F.textContent=C,S.appendChild(F)});let M=C=>C==="retry_ocr"?o("maintenance_btn_retry")||"\u91CD\u8BD5":C==="rebuild_result"?o("maintenance_btn_rebuild")||"\u91CD\u5EFA":C==="upgrade_legacy"?o("maintenance_btn_upgrade")||"\u5347\u7EA7":"";for(let C of _.items){let F=D.insertRow(),A=F.insertCell();A.style.cssText="padding:3px 4px;text-align:center;";let J=document.createElement("input");J.type="checkbox",J.className="pf-maint-sel",J.checked=k.get(C.key)||!1,J.addEventListener("change",()=>{k.set(C.key,J.checked),L()}),A.appendChild(J);let G=F.insertCell();G.style.cssText="padding:3px 4px;white-space:nowrap;font-size:11px;max-width:90px;overflow:hidden;text-overflow:ellipsis;",G.textContent=C.key;let ee=F.insertCell();ee.style.cssText="padding:3px 4px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis;",ee.textContent=C.title||C.key;let Q=F.insertCell();Q.style.cssText="padding:3px 4px;white-space:nowrap;",Q.textContent=C.display_label;let re=F.insertCell();re.style.cssText="padding:3px 4px;white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis;font-size:11px;color:var(--text-muted);",re.textContent=C.display_reason||"";let Pe=F.insertCell();Pe.style.cssText="padding:3px 4px;text-align:center;white-space:nowrap;";let ye=document.createElement("button");ye.textContent=M(C.display_action),ye.textContent&&(ye.addEventListener("click",()=>{let B=n([C.key],C.display_action);B&&(0,K.execFile)(m,[...y,...B.cmd],{cwd:t,timeout:B.timeout,windowsHide:!0},()=>{new R.Notice(C.display_label+" \u2014 "+C.key)})}),Pe.appendChild(ye))}}};if(a){let f=Object.values(a.papers);i(f)}else r.createEl("p",{text:"\u6B63\u5728\u52A0\u8F7D OCR \u7EF4\u62A4\u6570\u636E\u2026"});wt(t,s.path,s.extraArgs||[],a||null).then(f=>{f.changed?(i(f.data),Ve(t,{manifest:{},papers:Object.fromEntries(f.data.map(p=>[p.key,p])),cached_at:new Date().toISOString()})):a||(i(f.data),Ve(t,{manifest:{},papers:Object.fromEntries(f.data.map(p=>[p.key,p])),cached_at:new Date().toISOString()}))}).catch(()=>{a||(r.empty(),r.createEl("p",{text:"\u65E0\u6CD5\u52A0\u8F7D OCR \u6570\u636E\u3002\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 paperforge \u5E76\u8FD0\u884C\u8FC7 OCR\u3002",cls:"setting-item-description"}))}),e.createEl("hr"),e.createEl("h3",{text:"\u5168\u5C40\u64CD\u4F5C"});let l=e.createEl("div",{cls:"pf-maint-global"});l.createEl("button",{text:"\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15"}).addEventListener("click",()=>{new R.Notice("\u6B63\u5728\u91CD\u5EFA\u641C\u7D22\u7D22\u5F15\u2026"),(0,K.execFile)(s.path,[...s.extraArgs||[],"-m","paperforge","embed","build","--force"],{cwd:t,timeout:3e5,windowsHide:!0},()=>{new R.Notice("\u641C\u7D22\u7D22\u5F15\u91CD\u5EFA\u5B8C\u6210\u3002")})}),l.createEl("button",{text:"\u91CD\u5EFA\u8BB0\u5FC6\u5E93"}).addEventListener("click",()=>{new R.Notice("\u6B63\u5728\u91CD\u5EFA\u8BB0\u5FC6\u5E93\u2026"),(0,K.execFile)(s.path,[...s.extraArgs||[],"-m","paperforge","repair","--fix"],{cwd:t,timeout:12e4,windowsHide:!0},()=>{new R.Notice("\u8BB0\u5FC6\u5E93\u91CD\u5EFA\u5B8C\u6210\u3002")})})}_renderReleaseNotesTab(e){e.createEl("h2",{text:"\u66F4\u65B0\u4E0E\u624B\u518C"}),e.createEl("h3",{text:"\u7248\u672C\u66F4\u65B0\u8BB0\u5F55"});let t=Pt.default.versions||[];for(let a of t){let s=e.createEl("div",{cls:"paperforge-release-card"}),i=s.createEl("div",{cls:"paperforge-release-header"});if(i.createEl("strong",{text:`v${a.version} \u2014 ${a.title}`}),i.createEl("span",{cls:"paperforge-release-date",text:` (${a.date})`}),a.breaking_or_migration&&a.breaking_or_migration.length>0){let l=s.createEl("div",{cls:"paperforge-release-section"});l.createEl("div",{cls:"paperforge-release-label",text:"\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F"});for(let c of a.breaking_or_migration)l.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.new_features&&a.new_features.length>0){let l=s.createEl("div",{cls:"paperforge-release-section"});l.createEl("div",{cls:"paperforge-release-label",text:"\u65B0\u529F\u80FD"});for(let c of a.new_features)l.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.fixes&&a.fixes.length>0){let l=s.createEl("div",{cls:"paperforge-release-section"});l.createEl("div",{cls:"paperforge-release-label",text:"\u4FEE\u590D"});for(let c of a.fixes)l.createEl("div",{cls:"paperforge-release-item",text:`\u2022 ${c}`})}if(a.recommended_actions&&a.recommended_actions.length>0){let l=s.createEl("div",{cls:"paperforge-release-section paperforge-release-recommended"});l.createEl("div",{cls:"paperforge-release-label",text:"\u5EFA\u8BAE\u64CD\u4F5C"});for(let c of a.recommended_actions)l.createEl("div",{cls:"paperforge-release-item paperforge-release-item-bold",text:`\u2022 ${c}`})}}e.createEl("h3",{text:"\u4F7F\u7528\u624B\u518C"}),e.createEl("div",{cls:"paperforge-manual-links"}).createEl("a",{text:"\u2192 \u67E5\u770B\u5B8C\u6574\u4F7F\u7528\u624B\u518C\uFF08GitHub\uFF09",href:"https://github.com/LLLin000/PaperForge/blob/master/docs/user-manual.md"}).setAttr("target","_blank")}};var I=require("obsidian"),he=V(require("fs")),Le=V(require("path")),_e=require("child_process");var Ae=V(require("path"));function Ct(u){if(!u)return null;let h=Ae.dirname(u);for(;;){let e=Ae.basename(h);if(!e||e===".")break;let t=e.match(/^([A-Z0-9]{8})(?:\s*-\s*.*)?$/i);if(t)return t[1];let r=Ae.dirname(h);if(r===h)break;h=r}return null}var Z=V(require("fs")),me=V(require("path"));function Oe(u){return ne(u).ocrDir}function Ht(u,h){let e=me.join(Oe(u),h,"versions","manifest.json");try{if(!Z.existsSync(e))return null;let t=Z.readFileSync(e,"utf-8"),r=JSON.parse(t);if(r&&typeof r=="object"&&"versions"in r&&"current"in r){let n=r,a=n.versions,s=n.current;if(Array.isArray(a)&&s&&typeof s=="object"&&"label"in s)return r}return null}catch(t){return null}}function Kt(u){let h=Oe(u);try{return Z.existsSync(h)?Z.readdirSync(h,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name):[]}catch(e){return[]}}function nt(u){let h=Kt(u),e=[];for(let t of h){let r=Ht(u,t);if(!r)continue;let n=r.versions.map(s=>s.label),a=0;for(let s of n){let i=me.join(Oe(u),t,"versions",s,"fulltext.md");try{Z.existsSync(i)&&(a+=Z.statSync(i).size)}catch(l){}}e.push({key:t,title:t.replace(/_/g," "),versions:r.versions,currentLabel:r.current.label,totalSize:a})}return e.sort((t,r)=>t.title.localeCompare(r.title)),e}function Rt(u,h,e){let t=Oe(u),r=me.join(t,h,"versions",e,"fulltext.md"),n=me.join(t,h,"render"),a=me.join(n,"fulltext.md");try{return Z.existsSync(r)?(Z.existsSync(n)||Z.mkdirSync(n,{recursive:!0}),Z.copyFileSync(r,a),!0):!1}catch(s){return!1}}function Tt(u,h,e,t){var p;let r=Oe(u),n=me.join(r,h,"versions",e,"fulltext.md"),a=me.join(r,h,"versions",t,"fulltext.md"),s="",i="";try{Z.existsSync(n)&&(s=Z.readFileSync(n,"utf-8"))}catch(m){}try{Z.existsSync(a)&&(i=Z.readFileSync(a,"utf-8"))}catch(m){}let l=Ft(s),c=Ft(i),d=Math.max(l.length,c.length),f=[];for(let m=0;m0)e.push(t.join(` `).trim()),t=[r];else if(r.trim()===""&&t.length>0){let n=t.join(` `).trim();n&&(e.push(n),t=[])}else t.push(r);if(t.length>0){let r=t.join(` -`).trim();r&&e.push(r)}return e}var Ee=class extends B.ItemView{constructor(e){super(e);this._currentMode=null;this._currentDomain=null;this._currentPaperKey=null;this._currentPaperEntry=null;this._currentFilePath=null;this._cachedItems=null;this._modeSubscribers=[];this._leafChangeTimer=null;this._ocrPrivacyShown=!1;this._cachedStats=null;this._techDetailsExpanded=!1;this._paperforgeVersion="";this._dashboardPermissions={};this._headerTitle=null;this._versionBadge=null;this._messageEl=null;this._metricsEl=null;this._ocrSection=null;this._ocrEmpty=null;this._ocrBadge=null;this._ocrTrack=null;this._ocrCounts=null;this._driftBannerEl=null;this._versionPapers=null;this._versionFilter="";this._searchContainer=null;this._searchInput=null;this._searchResultsEl=null;this._searchTimer=void 0;this._currentMode=null,this._currentDomain=null,this._currentPaperKey=null,this._currentPaperEntry=null,this._currentFilePath=null,this._cachedItems=null,this._modeSubscribers=[],this._leafChangeTimer=null,this._ocrPrivacyShown=!1}getViewType(){return _e}getDisplayText(){return"PaperForge"}getIcon(){return Ce}async onOpen(){this._buildPanel(),this._modeSubscribers=[],this._leafChangeTimer=null,this._setupEventSubscriptions(),this._fetchVersion(),this._detectAndSwitch()}async onClose(){if(this._modeSubscribers&&this._modeSubscribers.length>0){for(let e of this._modeSubscribers)e.event==="active-leaf-change"?this.app.workspace.off("active-leaf-change",e.ref):e.event==="modify"&&this.app.vault.off("modify",e.ref);this._modeSubscribers=[]}this._leafChangeTimer&&(clearTimeout(this._leafChangeTimer),this._leafChangeTimer=null),this._cachedItems=null,this._cachedStats=null}_buildPanel(){let e=this.containerEl;e.empty(),e.addClass("paperforge-status-panel");let t=e.createEl("div",{cls:"paperforge-header"}),r=t.createEl("div",{cls:"paperforge-header-left"});r.createEl("div",{cls:"paperforge-header-logo",text:"P"}),this._modeContextEl=r.createEl("div",{cls:"paperforge-mode-context"}),this._headerTitle=r.createEl("h3",{cls:"paperforge-header-title",text:"PaperForge"}),this._versionBadge=r.createEl("span",{cls:"paperforge-header-badge",text:"v\u2014"});let n=t.createEl("button",{cls:"paperforge-header-refresh",attr:{"aria-label":"Refresh"}});n.innerHTML="\u21BB",n.addEventListener("click",()=>{this._invalidateIndex(),this._detectAndSwitch()}),this._messageEl=e.createEl("div",{cls:"paperforge-message"}),this._contentEl=e.createEl("div",{cls:"paperforge-content-area"})}_fetchVersion(){var s,l;let e=this.app.vault.adapter.basePath,t=this.app.plugins.plugins.paperforge,r=((s=t==null?void 0:t.manifest)==null?void 0:s.version)||"?",{path:n,extraArgs:a=[]}=L(e,(l=t==null?void 0:t.settings)!=null?l:null,void 0,void 0);lt(n,r,e,1e4,void 0).then(i=>{if(i.status==="not-installed")return;let c=i.pyVersion||"";this._paperforgeVersion=c.startsWith("v")?c:"v"+c,this._versionBadge&&this._versionBadge.setText(this._paperforgeVersion),this._driftBannerEl&&r&&this._paperforgeVersion!=="v"+r.replace(/^v/,"")?(this._driftBannerEl.style.display="block",this._driftBannerEl.setText(o("dashboard_drift_warning").replace("{0}",this._paperforgeVersion).replace("{1}","v"+r.replace(/^v/,"")))):this._driftBannerEl&&(this._driftBannerEl.style.display="none")})}_fetchStats(e){var s;if(!this._metricsEl)return;if(!e&&!this._cachedStats)this._metricsEl.empty(),this._metricsEl.createEl("div",{cls:"paperforge-status-loading",text:"Loading..."});else if(e&&!this._cachedStats)return;let t=this.app.vault.adapter.basePath,r=this.app.plugins.plugins.paperforge,{path:n,extraArgs:a=[]}=L(t,(s=r==null?void 0:r.settings)!=null?s:null,void 0,void 0);(0,fe.execFile)(n,[...a,"-m","paperforge","dashboard","--json"],{cwd:t,timeout:3e4},(l,i)=>{if(!l)try{let c=JSON.parse(i);if(c.ok&&c.data){let d=this._normalizeDashboardData(c.data);this._cachedStats=d,this._metricsEl.empty(),this._renderStats(d),this._renderOcr(d),this._dashboardPermissions=c.data.permissions||{};return}}catch(c){}this._fallbackFetchStats(e,t,r)})}_normalizeDashboardData(e){let t=e.stats||{},r=t.ocr_health||{},n=t.pdf_health||{},a=e.ocr_version_state||{},s=(r.done||0)+(r.pending||0)+(r.failed||0);return{total_papers:t.papers||0,formal_notes:t.papers||0,exports:0,bases:0,ocr:{total:s,pending:r.pending||0,processing:0,done:r.done||0,failed:r.failed||0},path_errors:(n.broken||0)+(n.missing||0),ocr_version_state:{total_papers:a.total_papers||0,derived_stale_count:a.derived_stale_count||0,raw_upgradable_count:a.raw_upgradable_count||0}}}_fallbackFetchStats(e,t,r){var s,l,i;let n=((s=r==null?void 0:r.settings)==null?void 0:s.system_dir)||"System",a=Oe.join(t,n,"PaperForge","indexes","formal-library.json");try{let c=pe.readFileSync(a,"utf-8"),d=JSON.parse(c),g=d.items||[],p={},f={pdf_health:{healthy:0,unhealthy:0},ocr_health:{healthy:0,unhealthy:0},note_health:{healthy:0,unhealthy:0},asset_health:{healthy:0,unhealthy:0}},y=0,b=0,m=0,x=0,w=0,E=0;for(let _ of g){_.note_path&&E++;let v=_.lifecycle||"pdf_ready";p[v]=(p[v]||0)+1;let k=_.health||{};for(let P of["pdf_health","ocr_health","note_health","asset_health"])(k[P]||"healthy")==="healthy"?f[P].healthy++:f[P].unhealthy++;let S=_.ocr_status||"";y++,S==="done"?b++:S==="pending"?m++:S==="processing"||S==="queued"||S==="running"?x++:w++}this._cachedStats={version:d.paperforge_version||((l=this._cachedStats)==null?void 0:l.version)||"\u2014",total_papers:g.length,formal_notes:E,exports:0,bases:0,ocr:{total:y,pending:m,processing:x,done:b,failed:w},path_errors:0,lifecycle_level_counts:p,health_aggregate:f},this._metricsEl.empty(),this._renderStats(this._cachedStats),this._renderOcr(this._cachedStats)}catch(c){!e&&!this._cachedStats&&this._metricsEl.createEl("div",{cls:"paperforge-status-loading",text:"No index \u2014 trying CLI..."});let{path:d,extraArgs:g=[]}=L(t,(i=r==null?void 0:r.settings)!=null?i:null,void 0,void 0);(0,fe.execFile)(d,[...g,"-m","paperforge","status","--json"],{cwd:t,timeout:3e4},(p,f)=>{if(p){if(this._cachedStats)return;this._metricsEl.createEl("div",{cls:"paperforge-status-error",text:`Cannot reach PaperForge CLI. -Make sure paperforge is installed and in your PATH.`});return}try{let y=JSON.parse(f);this._cachedStats=y,this._metricsEl.empty(),this._renderStats(y),this._renderOcr(y)}catch(y){this._cachedStats||this._metricsEl.createEl("div",{cls:"paperforge-status-error",text:"Invalid response from paperforge status."})}})}}_renderSkeleton(e){e.addClass("paperforge-loading")}_renderEmptyState(e,t){e.createEl("div",{cls:"paperforge-empty-state",text:t||"No data"})}_buildMetricBar(e,t,r){if(r<=0)return;let n=Math.min(100,t/r*100);e.createEl("div",{cls:"paperforge-metric-progress"}).createEl("div",{cls:"paperforge-metric-progress-fill",attr:{style:`width:${n.toFixed(1)}%`}})}_loadIndex(){var a;let e=this.app.vault.adapter.basePath,t=this.app.plugins.plugins.paperforge,r=((a=t==null?void 0:t.settings)==null?void 0:a.system_dir)||"System",n=Oe.join(e,r,"PaperForge","indexes","formal-library.json");try{let s=pe.readFileSync(n,"utf-8");return JSON.parse(s)}catch(s){return null}}_getCachedIndex(){if(!this._cachedItems){let e=this._loadIndex();this._cachedItems=e?e.items||[]:[]}return this._cachedItems}_findEntry(e){if(!e)return null;let t=this._getCachedIndex().find(r=>r.zotero_key===e)||null;return nt(this.app,t)}_patchCachedEntry(e,t){if(!e||!this._cachedItems)return;let r=this._cachedItems.findIndex(n=>n.zotero_key===e);r!==-1&&(this._cachedItems[r]=Ke(this._cachedItems[r],t))}_filterByDomain(e){return e?this._getCachedIndex().filter(t=>t.domain===e):[]}_renderStats(e){var s;if(this._versionBadge&&this._versionBadge.setText(this._paperforgeVersion||(e.version?"v"+e.version:"v\u2014")),!e||typeof e.total_papers=="undefined"){this._metricsEl&&this._renderSkeleton(this._metricsEl);return}if(!this._metricsEl)return;this._metricsEl.removeClass("paperforge-loading");let t=e.total_papers||0,r=e.formal_notes||0,n=[{value:t,label:"Papers",color:"var(--color-cyan)",barMax:0},{value:r,label:"Formal Notes",color:"var(--color-blue)",barMax:t},{value:e.exports||0,label:"Exports",color:"var(--color-purple)",barMax:0}];for(let l of n){let i=this._metricsEl.createEl("div",{cls:"paperforge-metric-card"});i.style.setProperty("--metric-color",l.color),i.createEl("div",{cls:"paperforge-metric-value",text:((s=l.value)==null?void 0:s.toString())||"\u2014"}),i.createEl("div",{cls:"paperforge-metric-label",text:l.label}),l.barMax>0&&this._buildMetricBar(i,l.value,l.barMax)}let a=e.ocr_version_state||{};if(a.total_papers>0&&(a.derived_stale_count>0||a.raw_upgradable_count>0)){let l=[];a.derived_stale_count>0&&l.push(`${a.derived_stale_count} stale`),a.raw_upgradable_count>0&&l.push(`${a.raw_upgradable_count} upgradable`);let i=this._metricsEl.createEl("div",{cls:"paperforge-metric-card"});i.style.setProperty("--metric-color","var(--color-yellow)"),i.createEl("div",{cls:"paperforge-metric-value",text:l.join(", ")}),i.createEl("div",{cls:"paperforge-metric-label",text:"OCR Version"})}}_renderOcr(e){if(!this._ocrSection)return;let t=e.ocr||{},r=t.total||0;if(r===0){this._ocrSection.style.display="none";return}this._ocrSection.style.display="block",this._ocrEmpty&&(this._ocrEmpty.style.display="none");let n=t.done||0,a=t.pending||0,s=t.processing||0,l=t.failed||0;if(this._ocrBadge&&(this._ocrBadge.removeClass("active","idle"),s>0?(this._ocrBadge.addClass("active"),this._ocrBadge.setText("Processing")):a>0?(this._ocrBadge.addClass("idle"),this._ocrBadge.setText("Pending")):(this._ocrBadge.addClass("idle"),this._ocrBadge.setText("Idle"))),this._ocrTrack){this._ocrTrack.empty(),s>0?this._ocrTrack.addClass("paperforge-processing"):this._ocrTrack.removeClass("paperforge-processing");let i=[{cls:"pending",count:a},{cls:"active",count:s},{cls:"done",count:n},{cls:"failed",count:l}];for(let c of i)if(c.count>0){let d=(c.count/r*100).toFixed(1);this._ocrTrack.createEl("div",{cls:`paperforge-progress-seg ${c.cls}`,attr:{style:`width:${d}%`}})}}if(this._ocrCounts){this._ocrCounts.empty();let i=[{cls:"pending",value:a,label:"Pending"},{cls:"active",value:s,label:"Processing"},{cls:"done",value:n,label:"Done"},{cls:"failed",value:l,label:"Failed"}];for(let c of i){let d=this._ocrCounts.createEl("div",{cls:"paperforge-ocr-count"});d.createEl("div",{cls:"paperforge-ocr-count-value",text:c.value.toString()}),d.createEl("div",{cls:"paperforge-ocr-count-label",text:c.label})}}}_renderLifecycleStepper(e,t,r){if(!t||!r){this._renderSkeleton(e);return}let n=[{key:"indexed",label:"Indexed"},{key:"pdf_ready",label:"PDF Ready"},{key:"fulltext_ready",label:"Fulltext Ready"},{key:"deep_read_done",label:"Deep Read"}],a=e.createEl("div",{cls:"paperforge-lifecycle-stepper"}),s=!1;for(let l of n){let i=a.createEl("div",{cls:"step"});i.createEl("div",{cls:"step-indicator"}),i.createEl("div",{cls:"step-label",text:l.label}),l.key===r?(i.addClass("current"),s=!0):s?i.addClass("pending"):i.addClass("completed")}}_renderHealthMatrix(e,t){if(!t){this._renderSkeleton(e);return}let r=[{key:"pdf_health",label:"PDF Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"ocr_health",label:"OCR Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"note_health",label:"Note Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"asset_health",label:"Asset Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"}],n=e.createEl("div",{cls:"paperforge-health-matrix"});for(let a of r){let s=t[a.key]||"healthy",l=n.createEl("div",{cls:"paperforge-health-cell"}),i,c,d;s==="healthy"||s==="ok"?(i=a.iconOk,c="ok",d=`${a.label}: OK`):s==="warn"||s==="warning"||s==="degraded"?(i=a.iconWarn,c="warn",d=`${a.label}: Needs Attention`):(i=a.iconFail,c="fail",d=`${a.label}: Failed`),l.addClass(c),l.setAttribute("title",d),l.createEl("div",{cls:"paperforge-health-cell-icon",text:i}),l.createEl("div",{cls:"paperforge-health-cell-label",text:a.label})}}_renderMaturityGauge(e,t,r){if(t==null||t===void 0){this._renderSkeleton(e);return}let n=e.createEl("div",{cls:"paperforge-maturity-gauge"}),a=n.createEl("div",{cls:"gauge-track"}),s=4,l=Math.max(1,Math.min(s,Math.round(t)));for(let i=1;i<=s;i++){let c=a.createEl("div",{cls:"gauge-segment"});i<=l&&(c.addClass("filled"),c.addClass(`level-${i}`))}if(n.createEl("div",{cls:"gauge-level",text:`Level ${l} / ${s}`}),l0){let c=n.createEl("ul",{cls:"gauge-blockers"});for(let d of i)c.createEl("li",{text:d})}}}_renderBarChart(e,t){if(!t||Object.keys(t).length===0){this._renderEmptyState(e,"No lifecycle data");return}let r=[{key:"indexed",label:"Indexed",cls:"stage-indexed"},{key:"pdf_ready",label:"PDF Ready",cls:"stage-pdf-ready"},{key:"fulltext_ready",label:"Fulltext Ready",cls:"stage-fulltext-ready"},{key:"deep_read_done",label:"Deep Read",cls:"stage-deep-read"}],n=e.createEl("div",{cls:"paperforge-bar-chart"}),a=Math.max(1,...r.map(s=>t[s.key]||0));for(let s of r){let l=t[s.key]||0,i=l/a*100,c=n.createEl("div",{cls:"bar-row"});c.createEl("div",{cls:"bar-label",text:s.label}),c.createEl("div",{cls:"bar-track"}).createEl("div",{cls:`bar-fill ${s.cls}`,attr:{style:`width:${i.toFixed(1)}%`}}),c.createEl("div",{cls:"bar-count",text:l.toString()})}}_invalidateIndex(){this._cachedItems=null}_extractZoteroKeyFromPath(e){return St(e)}_resolveModeForFile(e){if(!e)return{mode:"global",filePath:null,key:null,domain:null};let t=e.extension,r=e.path;if(t==="base")return{mode:"collection",filePath:r,key:null,domain:e.basename.trim()};if(t==="md"){let a=this.app.metadataCache.getFileCache(e),s=a&&a.frontmatter&&a.frontmatter.zotero_key;if(s)return{mode:"paper",filePath:r,key:s,domain:null}}if(t==="pdf"){let a=this._getCachedIndex();for(let s of a){let l=(s.pdf_path||"").match(/\[\[([^\]]+)\]\]/);if((l?l[1]:s.pdf_path)===r)return{mode:"paper",filePath:r,key:s.zotero_key,domain:null}}}let n=this._extractZoteroKeyFromPath(r);return n?{mode:"paper",filePath:r,key:n,domain:null}:{mode:"global",filePath:r,key:null,domain:null}}_detectAndSwitch(){let e=this._resolveModeForFile(this.app.workspace.getActiveFile());this._currentDomain=e.domain||null,this._currentPaperKey=e.key||null,this._currentPaperEntry=e.key?this._findEntry(e.key):null,this._switchMode(e.mode,e.filePath)}_switchMode(e,t){if(this._currentMode===e&&this._currentFilePath===t){this._refreshCurrentMode();return}if(this._currentMode=e,this._currentFilePath=t,this._techDetailsExpanded=!1,!!this._contentEl)switch(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader(e),e){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}_renderGlobalMode(){var ee,oe,ve,de,we,Se,ge;if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-global-view"});this._driftBannerEl=e.createEl("div",{cls:"paperforge-drift-banner"}),this._driftBannerEl.style.display="none";let t=this._getCachedIndex(),r=t.length,n=0,a=0,s=0;for(let R of t)R.has_pdf&&n++,R.ocr_status==="done"&&a++,R.deep_reading_status==="done"&&s++;let l=e.createEl("div",{cls:"paperforge-library-snapshot"});l.createEl("div",{cls:"paperforge-section-label",text:"Library Snapshot"});let i=l.createEl("div",{cls:"paperforge-snapshot-pills"}),c=[{value:r,label:"papers"},{value:n,label:"PDFs ready"},{value:a,label:"OCR done"},{value:s,label:"deep-read done"}];for(let R of c){let M=i.createEl("div",{cls:"paperforge-snapshot-pill"});M.createEl("span",{cls:"paperforge-snapshot-value",text:String(R.value)}),M.createEl("span",{cls:"paperforge-snapshot-label",text:" "+R.label})}let d=e.createEl("div",{cls:"paperforge-system-status"});d.createEl("div",{cls:"paperforge-section-label",text:"System Status"});let g=d.createEl("div",{cls:"paperforge-status-grid"}),p=this.app.plugins.plugins.paperforge,f=((ee=p==null?void 0:p.manifest)==null?void 0:ee.version)||"?",y=this._paperforgeVersion;if(!y)try{let R=this.app.vault.adapter.basePath,{path:M,extraArgs:re=[]}=L(R,(oe=p==null?void 0:p.settings)!=null?oe:null,void 0,void 0),J=(0,fe.execFileSync)(M,[...re,"-c","import paperforge; print(paperforge.__version__)"],{cwd:R,timeout:5e3,encoding:"utf-8",windowsHide:!0}).trim();J&&(y=J.startsWith("v")?J:"v"+J,this._paperforgeVersion=y)}catch(R){}y=y||"\u2014";let b=y==="v"+f;this._renderSystemStatusRow(g,"Runtime",b?"healthy":"mismatch",b?"v"+f:"plugin v"+f+" \u2260 CLI "+y);let m=this._loadIndex(),x=m&&m.items&&m.items.length>0;this._renderSystemStatusRow(g,"Index",x?"healthy":"missing",x?m.items.length+" entries":"formal-library.json not found");let w=((ve=p==null?void 0:p.settings)==null?void 0:ve.system_dir)||"System",E=this.app.vault.adapter.basePath,_=!1,v="No exports found";try{let R=Oe.join(E,w,"PaperForge","exports");if(pe.existsSync(R)){let M=pe.readdirSync(R).filter(re=>re.endsWith(".json"));_=M.length>0,v=_?M.length+" export(s)":"No JSON exports"}}catch(R){}this._renderSystemStatusRow(g,"Zotero Export",_?"healthy":"missing",v);let k=!!((de=p==null?void 0:p.settings)!=null&&de.paddleocr_api_key);if(!k)try{let R=((we=p==null?void 0:p.settings)==null?void 0:we.system_dir)||"System",M=Oe.join(E,R,"PaperForge",".env");if(pe.existsSync(M)){let J=pe.readFileSync(M,"utf-8").match(/^PADDLEOCR_API_TOKEN\s*=\s*(.+)$/m);k=!!(J&&J[1]&&J[1].trim())}}catch(R){}k||(k=!!(process.env.PADDLEOCR_API_TOKEN||process.env.PADDLEOCR_API_KEY||process.env.OCR_TOKEN)),this._renderSystemStatusRow(g,"OCR Token",k?"configured":"missing",k?"Configured":"Not set");let S=!1,P="",A=this.app.vault.adapter.basePath,T=Ye(A);S=ht(A),P=T&&((Se=T.summary)==null?void 0:Se.reason)||T&&((ge=T.summary)==null?void 0:ge.status)||"Unknown",this._renderSystemStatusRow(g,"Memory Layer",S?"healthy":"fail",P);let I=!b&&y!=="\u2014";if(I||!x||!_||!k){let R=e.createEl("div",{cls:"paperforge-issue-summary"});R.createEl("div",{cls:"paperforge-section-label",text:"\u9700\u8981\u5904\u7406"});let M=R.createEl("div",{cls:"paperforge-issue-list"});I&&M.createEl("div",{cls:"paperforge-issue-item",text:"Runtime version mismatch"}),x||M.createEl("div",{cls:"paperforge-issue-item",text:"Index missing or corrupted"}),_||M.createEl("div",{cls:"paperforge-issue-item",text:"No Zotero export found"}),k||M.createEl("div",{cls:"paperforge-issue-item",text:"PaddleOCR API key not configured"});let re=R.createEl("div",{cls:"paperforge-issue-actions"}),J=re.createEl("button",{cls:"paperforge-contextual-btn"});J.createEl("span",{text:"Run Doctor"}),J.addEventListener("click",()=>{let Pe=Y.find(Ve=>Ve.id==="paperforge-doctor");Pe&&this._runAction(Pe,J)});let ue=re.createEl("button",{cls:"paperforge-contextual-btn"});ue.createEl("span",{text:"Repair Issues"}),ue.addEventListener("click",()=>{let Pe=Y.find(Ve=>Ve.id==="paperforge-repair");Pe&&this._runAction(Pe,ue)})}let O=e.createEl("div",{cls:"paperforge-global-actions"});O.createEl("div",{cls:"paperforge-section-label",text:"Start Working"});let U=O.createEl("div",{cls:"paperforge-global-actions-row"}),q=U.createEl("button",{cls:"paperforge-contextual-btn primary"});q.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4C1}"}),q.createEl("span",{text:"Open Literature Hub"}),q.addEventListener("click",()=>{var re;let R=((re=p==null?void 0:p.settings)==null?void 0:re.base_dir)||"Bases",M=this.app.vault.getAbstractFileByPath(R);if(M){let J=null;if(M.children&&(J=M.children.find(ue=>ue.extension==="base")),J){let ue=this.app.workspace.getLeaf(!1);ue&&ue.openFile(J)}else new B.Notice("[!!] No .base file found in "+R,6e3)}else new B.Notice("[!!] Base directory not found: "+R,6e3)});let F=U.createEl("button",{cls:"paperforge-contextual-btn"});F.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),F.createEl("span",{text:"Sync Library"}),F.addEventListener("click",()=>{let R=Y.find(M=>M.id==="paperforge-sync");R&&this._runAction(R,F)});let D=U.createEl("button",{cls:"paperforge-contextual-btn"});D.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),D.createEl("span",{text:"Run OCR"}),D.addEventListener("click",()=>{let R=Y.find(M=>M.id==="paperforge-ocr");R&&this._runAction(R,D)});let X=U.createEl("button",{cls:"paperforge-contextual-btn warn"});X.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),X.createEl("span",{text:"Redo OCR"}),X.addEventListener("click",()=>{let R=Y.find(M=>M.id==="paperforge-ocr-redo");R&&this._runAction(R,X)})}_renderSystemStatusRow(e,t,r,n){let a=e.createEl("div",{cls:"paperforge-status-row"});a.createEl("span",{cls:"paperforge-status-dot"}).addClass(r==="healthy"||r==="configured"?"ok":"fail"),a.createEl("span",{cls:"paperforge-status-label",text:t}),a.createEl("span",{cls:"paperforge-status-detail",text:n||""})}_renderPaperMode(){let e=this._currentPaperEntry,t=this._currentPaperKey;if(!this._contentEl)return;if(!t){this._renderEmptyState(this._contentEl,"No paper data available.");return}if(!e){this._contentEl.createEl("div",{cls:"paperforge-content-placeholder",text:'Paper "'+t+'" not found in canonical index. Sync first.'});return}let r=this._contentEl.createEl("div",{cls:"paperforge-paper-view"}),n=r.createEl("div",{cls:"paperforge-paper-header"});n.createEl("div",{cls:"paperforge-paper-title pf-copy",text:e.title||"Untitled"}).addEventListener("click",()=>{navigator.clipboard.writeText(e.title||""),new B.Notice("Title copied")});let s=n.createEl("div",{cls:"paperforge-paper-meta"});e.authors&&e.authors.length>0&&s.createEl("span",{cls:"paperforge-paper-authors",text:e.authors.join(", ")}),e.year&&s.createEl("span",{cls:"paperforge-paper-year",text:String(e.year)});let l=r.createEl("div",{cls:"paperforge-status-strip"}),i=l.createEl("div",{cls:"paperforge-status-strip-left"}),c=l.createEl("div",{cls:"paperforge-status-strip-right"}),d=[{key:"pdf",label:"PDF",ok:e.has_pdf===!0},{key:"ocr",label:"OCR",ok:e.ocr_status==="done",pending:["pending","queued","processing"].includes(e.ocr_status||""),fail:["failed","blocked","done_incomplete","nopdf"].includes(e.ocr_status||"")},{key:"deep",label:"\u7CBE\u8BFB",ok:e.deep_reading_status==="done"}];for(let p of d){let f=i.createEl("span",{cls:"paperforge-status-pill"}),y="pending";p.ok?y="ok":p.fail?y="fail":p.pending&&(y="pending"),f.addClass(y);let b=p.ok?"\u2713":p.fail?"\u2717":"\u25CB";f.createEl("span",{cls:"paperforge-status-pill-icon",text:b}),f.createEl("span",{text:" "+p.label})}if(e.pdf_path){let p=c.createEl("button",{cls:"paperforge-contextual-btn"});p.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4C4}"}),p.createEl("span",{text:"\u6253\u5F00 PDF"}),p.addEventListener("click",()=>{let f=e.pdf_path.match(/\[\[([^\]]+)\]\]/),y=f?f[1]:e.pdf_path;this.app.vault.getAbstractFileByPath(y)?this.app.workspace.openLinkText(y,""):new B.Notice("[!!] PDF not found: "+y,6e3)})}if(e.fulltext_path){let p=c.createEl("button",{cls:"paperforge-contextual-btn"});p.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4DD}"}),p.createEl("span",{text:"\u6253\u5F00\u5168\u6587"}),p.addEventListener("click",()=>this._openFulltext(e.fulltext_path))}let g=c.createEl("button",{cls:"paperforge-contextual-btn"});if(g.createEl("span",{text:o("version_panel_title")}),g.addEventListener("click",()=>{this._switchToVersionMode(t)}),this._renderPaperOverviewCard(r,e),e.next_step==="ready"&&e.deep_reading_status==="done"){let p=r.createEl("div",{cls:"paperforge-complete-row"});p.createEl("span",{text:"\u2713"}),p.createEl("span",{text:"\u5DF2\u5B8C\u6210\uFF0C\u53EF\u76F4\u63A5\u4F7F\u7528"})}else this._renderNextStepCard(r,e,t);this._renderRecentDiscussionCard(r,e),this._renderPaperTechnicalDetails(r,e)}_renderPaperOverviewCard(e,t){let r=e.createEl("div",{cls:"paperforge-paper-overview"});r.createEl("div",{cls:"paperforge-paper-overview-header"}).createEl("span",{cls:"paperforge-paper-overview-title",text:"\u6587\u7AE0\u6982\u89C8"});let a=r.createEl("div",{cls:"paperforge-paper-overview-body"}),s=a.createEl("div",{cls:"paperforge-paper-overview-excerpt",text:"\u52A0\u8F7D\u4E2D..."});if(t.note_path){let l=this.app.vault.getAbstractFileByPath(t.note_path);l?this.app.vault.read(l).then(i=>{let c=this._extractOverviewFromNote(i);if(c){let d=c.length>200?c.slice(0,200)+"...":c;if(s.setText(d),c.length>200){let g=a.createEl("div",{cls:"paperforge-expand-container"}),p=g.createEl("button",{cls:"paperforge-expand-icon",title:"\u5C55\u5F00/\u6536\u8D77"});p.innerHTML='';let f=!1;g.addEventListener("click",()=>{s.setText(f?d:c),p.innerHTML=f?'':'',f=!f})}}else s.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8\u3002\u8FD0\u884C /pf-deep \u5F00\u59CB\u7CBE\u8BFB\u3002")}).catch(()=>{s.setText("\u65E0\u6CD5\u8BFB\u53D6\u7B14\u8BB0\u5185\u5BB9")}):s.setText("\u7B14\u8BB0\u6587\u4EF6\u4E0D\u5B58\u5728")}else s.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8")}_extractOverviewFromNote(e){if(!e)return null;let t=e.indexOf("## \u{1F50D} \u7CBE\u8BFB");if(t===-1)return null;let r=e.slice(t),n=["**\u4E00\u53E5\u8BDD\u603B\u89C8:**","**\u4E00\u53E5\u8BDD\u603B\u89C8**","**\u6587\u7AE0\u6458\u8981:**","**\u6587\u7AE0\u6458\u8981**"];for(let l of n){let i=r.indexOf(l);if(i!==-1){let c=r.slice(i+l.length),d=["**5 Cs","**Figure","**\u8BC1\u636E","### Pass 2","## "],g=c.length;for(let y of d){let b=c.indexOf(y);b!==-1&&b{var t,r,n;if(e.key==="/"&&!e.ctrlKey&&!e.metaKey&&!e.altKey){let a=(r=(t=e.target)==null?void 0:t.tagName)==null?void 0:r.toLowerCase();a!=="input"&&a!=="textarea"&&(e.preventDefault(),(n=this._searchInput)==null||n.focus())}},document.addEventListener("keydown",this._onKeyDown)}async onClose(){if(this._modeSubscribers&&this._modeSubscribers.length>0){for(let e of this._modeSubscribers)e.event==="active-leaf-change"?this.app.workspace.off("active-leaf-change",e.ref):e.event==="modify"&&this.app.vault.off("modify",e.ref);this._modeSubscribers=[]}this._leafChangeTimer&&(clearTimeout(this._leafChangeTimer),this._leafChangeTimer=null),this._onKeyDown&&(document.removeEventListener("keydown",this._onKeyDown),this._onKeyDown=null),this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._searchTimer=void 0,this._cachedItems=null,this._cachedStats=null}_buildPanel(){let e=this.containerEl;e.empty(),e.addClass("paperforge-status-panel");let t=e.createEl("div",{cls:"paperforge-header"}),r=t.createEl("div",{cls:"paperforge-header-left"});r.createEl("div",{cls:"paperforge-header-logo",text:"P"}),this._modeContextEl=r.createEl("div",{cls:"paperforge-mode-context"}),this._headerTitle=r.createEl("h3",{cls:"paperforge-header-title",text:"PaperForge"}),this._versionBadge=r.createEl("span",{cls:"paperforge-header-badge",text:"v\u2014"});let n=t.createEl("button",{cls:"paperforge-header-refresh",attr:{"aria-label":"Refresh"}});n.innerHTML="\u21BB",n.addEventListener("click",()=>{this._invalidateIndex(),this._detectAndSwitch()}),this._messageEl=e.createEl("div",{cls:"paperforge-message",attr:{"aria-live":"polite"}}),this._contentEl=e.createEl("div",{cls:"paperforge-content-area"})}_fetchVersion(){var s,i;let e=this.app.vault.adapter.basePath,t=this.app.plugins.plugins.paperforge,r=((s=t==null?void 0:t.manifest)==null?void 0:s.version)||"?",{path:n,extraArgs:a=[]}=N(e,(i=t==null?void 0:t.settings)!=null?i:null,void 0,void 0);dt(n,r,e,1e4,void 0).then(l=>{if(l.status==="not-installed")return;let c=l.pyVersion||"";this._paperforgeVersion=c.startsWith("v")?c:"v"+c,this._versionBadge&&this._versionBadge.setText(this._paperforgeVersion),this._driftBannerEl&&r&&this._paperforgeVersion!=="v"+r.replace(/^v/,"")?(this._driftBannerEl.style.display="block",this._driftBannerEl.setText(o("dashboard_drift_warning").replace("{0}",this._paperforgeVersion).replace("{1}","v"+r.replace(/^v/,"")))):this._driftBannerEl&&(this._driftBannerEl.style.display="none")})}_fetchStats(e){var s;if(!this._metricsEl)return;if(!e&&!this._cachedStats)this._metricsEl.empty(),this._metricsEl.createEl("div",{cls:"paperforge-status-loading",text:"Loading..."});else if(e&&!this._cachedStats)return;let t=this.app.vault.adapter.basePath,r=this.app.plugins.plugins.paperforge,{path:n,extraArgs:a=[]}=N(t,(s=r==null?void 0:r.settings)!=null?s:null,void 0,void 0);(0,_e.execFile)(n,[...a,"-m","paperforge","dashboard","--json"],{cwd:t,timeout:3e4},(i,l)=>{if(!i)try{let c=JSON.parse(l);if(c.ok&&c.data){let d=this._normalizeDashboardData(c.data);this._cachedStats=d,this._metricsEl.empty(),this._renderStats(d),this._renderOcr(d),this._dashboardPermissions=c.data.permissions||{};return}}catch(c){}this._fallbackFetchStats(e,t,r)})}_normalizeDashboardData(e){let t=e.stats||{},r=t.ocr_health||{},n=t.pdf_health||{},a=e.ocr_version_state||{},s=(r.done||0)+(r.pending||0)+(r.failed||0);return{total_papers:t.papers||0,formal_notes:t.papers||0,exports:0,bases:0,ocr:{total:s,pending:r.pending||0,processing:0,done:r.done||0,failed:r.failed||0},path_errors:(n.broken||0)+(n.missing||0),ocr_version_state:{total_papers:a.total_papers||0,derived_stale_count:a.derived_stale_count||0,raw_upgradable_count:a.raw_upgradable_count||0}}}_fallbackFetchStats(e,t,r){var s,i,l;let n=((s=r==null?void 0:r.settings)==null?void 0:s.system_dir)||"System",a=Le.join(t,n,"PaperForge","indexes","formal-library.json");try{let c=he.readFileSync(a,"utf-8"),d=JSON.parse(c),f=d.items||[],p={},m={pdf_health:{healthy:0,unhealthy:0},ocr_health:{healthy:0,unhealthy:0},note_health:{healthy:0,unhealthy:0},asset_health:{healthy:0,unhealthy:0}},y=0,x=0,_=0,b=0,E=0,k=0;for(let g of f){g.note_path&&k++;let v=g.lifecycle||"pdf_ready";p[v]=(p[v]||0)+1;let w=g.health||{};for(let P of["pdf_health","ocr_health","note_health","asset_health"])(w[P]||"healthy")==="healthy"?m[P].healthy++:m[P].unhealthy++;let T=g.ocr_status||"";y++,T==="done"?x++:T==="pending"?_++:T==="processing"||T==="queued"||T==="running"?b++:E++}this._cachedStats={version:d.paperforge_version||((i=this._cachedStats)==null?void 0:i.version)||"\u2014",total_papers:f.length,formal_notes:k,exports:0,bases:0,ocr:{total:y,pending:_,processing:b,done:x,failed:E},path_errors:0,lifecycle_level_counts:p,health_aggregate:m},this._metricsEl.empty(),this._renderStats(this._cachedStats),this._renderOcr(this._cachedStats)}catch(c){!e&&!this._cachedStats&&this._metricsEl.createEl("div",{cls:"paperforge-status-loading",text:"No index \u2014 trying CLI..."});let{path:d,extraArgs:f=[]}=N(t,(l=r==null?void 0:r.settings)!=null?l:null,void 0,void 0);(0,_e.execFile)(d,[...f,"-m","paperforge","status","--json"],{cwd:t,timeout:3e4},(p,m)=>{if(p){if(this._cachedStats)return;this._metricsEl.createEl("div",{cls:"paperforge-status-error",text:`Cannot reach PaperForge CLI. +Make sure paperforge is installed and in your PATH.`});return}try{let y=JSON.parse(m);this._cachedStats=y,this._metricsEl.empty(),this._renderStats(y),this._renderOcr(y)}catch(y){this._cachedStats||this._metricsEl.createEl("div",{cls:"paperforge-status-error",text:"Invalid response from paperforge status."})}})}}_renderSkeleton(e){e.addClass("paperforge-loading")}_renderEmptyState(e,t){e.createEl("div",{cls:"paperforge-empty-state",text:t||"No data"})}_buildMetricBar(e,t,r){if(r<=0)return;let n=Math.min(100,t/r*100);e.createEl("div",{cls:"paperforge-metric-progress"}).createEl("div",{cls:"paperforge-metric-progress-fill",attr:{style:`width:${n.toFixed(1)}%`}})}_loadIndex(){var a;let e=this.app.vault.adapter.basePath,t=this.app.plugins.plugins.paperforge,r=((a=t==null?void 0:t.settings)==null?void 0:a.system_dir)||"System",n=Le.join(e,r,"PaperForge","indexes","formal-library.json");try{let s=he.readFileSync(n,"utf-8");return JSON.parse(s)}catch(s){return null}}_getCachedIndex(){if(!this._cachedItems){let e=this._loadIndex();this._cachedItems=e?e.items||[]:[]}return this._cachedItems}_findEntry(e){if(!e)return null;let t=this._getCachedIndex().find(r=>r.zotero_key===e)||null;return ot(this.app,t)}_patchCachedEntry(e,t){if(!e||!this._cachedItems)return;let r=this._cachedItems.findIndex(n=>n.zotero_key===e);r!==-1&&(this._cachedItems[r]=Ze(this._cachedItems[r],t))}_filterByDomain(e){return e?this._getCachedIndex().filter(t=>t.domain===e):[]}_renderStats(e){var s;if(this._versionBadge&&this._versionBadge.setText(this._paperforgeVersion||(e.version?"v"+e.version:"v\u2014")),!e||typeof e.total_papers=="undefined"){this._metricsEl&&this._renderSkeleton(this._metricsEl);return}if(!this._metricsEl)return;this._metricsEl.removeClass("paperforge-loading");let t=e.total_papers||0,r=e.formal_notes||0,n=[{value:t,label:"Papers",color:"var(--color-cyan)",barMax:0},{value:r,label:"Formal Notes",color:"var(--color-blue)",barMax:t},{value:e.exports||0,label:"Exports",color:"var(--color-purple)",barMax:0}];for(let i of n){let l=this._metricsEl.createEl("div",{cls:"paperforge-metric-card"});l.style.setProperty("--metric-color",i.color),l.createEl("div",{cls:"paperforge-metric-value",text:((s=i.value)==null?void 0:s.toString())||"\u2014"}),l.createEl("div",{cls:"paperforge-metric-label",text:i.label}),i.barMax>0&&this._buildMetricBar(l,i.value,i.barMax)}let a=e.ocr_version_state||{};if(a.total_papers>0&&(a.derived_stale_count>0||a.raw_upgradable_count>0)){let i=[];a.derived_stale_count>0&&i.push(`${a.derived_stale_count} stale`),a.raw_upgradable_count>0&&i.push(`${a.raw_upgradable_count} upgradable`);let l=this._metricsEl.createEl("div",{cls:"paperforge-metric-card"});l.style.setProperty("--metric-color","var(--color-yellow)"),l.createEl("div",{cls:"paperforge-metric-value",text:i.join(", ")}),l.createEl("div",{cls:"paperforge-metric-label",text:"OCR Version"})}}_renderOcr(e){if(!this._ocrSection)return;let t=e.ocr||{},r=t.total||0;if(r===0){this._ocrSection.style.display="none";return}this._ocrSection.style.display="block",this._ocrEmpty&&(this._ocrEmpty.style.display="none");let n=t.done||0,a=t.pending||0,s=t.processing||0,i=t.failed||0;if(this._ocrBadge&&(this._ocrBadge.removeClass("active","idle"),s>0?(this._ocrBadge.addClass("active"),this._ocrBadge.setText("Processing")):a>0?(this._ocrBadge.addClass("idle"),this._ocrBadge.setText("Pending")):(this._ocrBadge.addClass("idle"),this._ocrBadge.setText("Idle"))),this._ocrTrack){this._ocrTrack.empty(),s>0?this._ocrTrack.addClass("paperforge-processing"):this._ocrTrack.removeClass("paperforge-processing");let l=[{cls:"pending",count:a},{cls:"active",count:s},{cls:"done",count:n},{cls:"failed",count:i}];for(let c of l)if(c.count>0){let d=(c.count/r*100).toFixed(1);this._ocrTrack.createEl("div",{cls:`paperforge-progress-seg ${c.cls}`,attr:{style:`width:${d}%`}})}}if(this._ocrCounts){this._ocrCounts.empty();let l=[{cls:"pending",value:a,label:"Pending"},{cls:"active",value:s,label:"Processing"},{cls:"done",value:n,label:"Done"},{cls:"failed",value:i,label:"Failed"}];for(let c of l){let d=this._ocrCounts.createEl("div",{cls:"paperforge-ocr-count"});d.createEl("div",{cls:"paperforge-ocr-count-value",text:c.value.toString()}),d.createEl("div",{cls:"paperforge-ocr-count-label",text:c.label})}}}_renderLifecycleStepper(e,t,r){if(!t||!r){this._renderSkeleton(e);return}let n=[{key:"indexed",label:"Indexed"},{key:"pdf_ready",label:"PDF Ready"},{key:"fulltext_ready",label:"Fulltext Ready"},{key:"deep_read_done",label:"Deep Read"}],a=e.createEl("div",{cls:"paperforge-lifecycle-stepper"}),s=!1;for(let i of n){let l=a.createEl("div",{cls:"step"});l.createEl("div",{cls:"step-indicator"}),l.createEl("div",{cls:"step-label",text:i.label}),i.key===r?(l.addClass("current"),s=!0):s?l.addClass("pending"):l.addClass("completed")}}_renderHealthMatrix(e,t){if(!t){this._renderSkeleton(e);return}let r=[{key:"pdf_health",label:"PDF Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"ocr_health",label:"OCR Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"note_health",label:"Note Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"},{key:"asset_health",label:"Asset Health",iconOk:"\u2713",iconWarn:"\u26A0",iconFail:"\u2717"}],n=e.createEl("div",{cls:"paperforge-health-matrix"});for(let a of r){let s=t[a.key]||"healthy",i=n.createEl("div",{cls:"paperforge-health-cell"}),l,c,d;s==="healthy"||s==="ok"?(l=a.iconOk,c="ok",d=`${a.label}: OK`):s==="warn"||s==="warning"||s==="degraded"?(l=a.iconWarn,c="warn",d=`${a.label}: Needs Attention`):(l=a.iconFail,c="fail",d=`${a.label}: Failed`),i.addClass(c),i.setAttribute("title",d),i.createEl("div",{cls:"paperforge-health-cell-icon",text:l}),i.createEl("div",{cls:"paperforge-health-cell-label",text:a.label})}}_renderMaturityGauge(e,t,r){if(t==null||t===void 0){this._renderSkeleton(e);return}let n=e.createEl("div",{cls:"paperforge-maturity-gauge"}),a=n.createEl("div",{cls:"gauge-track"}),s=4,i=Math.max(1,Math.min(s,Math.round(t)));for(let l=1;l<=s;l++){let c=a.createEl("div",{cls:"gauge-segment"});l<=i&&(c.addClass("filled"),c.addClass(`level-${l}`))}if(n.createEl("div",{cls:"gauge-level",text:`Level ${i} / ${s}`}),i0){let c=n.createEl("ul",{cls:"gauge-blockers"});for(let d of l)c.createEl("li",{text:d})}}}_renderBarChart(e,t){if(!t||Object.keys(t).length===0){this._renderEmptyState(e,"No lifecycle data");return}let r=[{key:"indexed",label:"Indexed",cls:"stage-indexed"},{key:"pdf_ready",label:"PDF Ready",cls:"stage-pdf-ready"},{key:"fulltext_ready",label:"Fulltext Ready",cls:"stage-fulltext-ready"},{key:"deep_read_done",label:"Deep Read",cls:"stage-deep-read"}],n=e.createEl("div",{cls:"paperforge-bar-chart"}),a=Math.max(1,...r.map(s=>t[s.key]||0));for(let s of r){let i=t[s.key]||0,l=i/a*100,c=n.createEl("div",{cls:"bar-row"});c.createEl("div",{cls:"bar-label",text:s.label}),c.createEl("div",{cls:"bar-track"}).createEl("div",{cls:`bar-fill ${s.cls}`,attr:{style:`width:${l.toFixed(1)}%`}}),c.createEl("div",{cls:"bar-count",text:i.toString()})}}_invalidateIndex(){this._cachedItems=null}_extractZoteroKeyFromPath(e){return Ct(e)}_resolveModeForFile(e){if(!e)return{mode:"global",filePath:null,key:null,domain:null};let t=e.extension,r=e.path;if(t==="base")return{mode:"collection",filePath:r,key:null,domain:e.basename.trim()};if(t==="md"){let a=this.app.metadataCache.getFileCache(e),s=a&&a.frontmatter&&a.frontmatter.zotero_key;if(s)return{mode:"paper",filePath:r,key:s,domain:null}}if(t==="pdf"){let a=this._getCachedIndex();for(let s of a){let i=(s.pdf_path||"").match(/\[\[([^\]]+)\]\]/);if((i?i[1]:s.pdf_path)===r)return{mode:"paper",filePath:r,key:s.zotero_key,domain:null}}}let n=this._extractZoteroKeyFromPath(r);return n?{mode:"paper",filePath:r,key:n,domain:null}:{mode:"global",filePath:r,key:null,domain:null}}_detectAndSwitch(){let e=this._resolveModeForFile(this.app.workspace.getActiveFile());this._currentDomain=e.domain||null,this._currentPaperKey=e.key||null,this._currentPaperEntry=e.key?this._findEntry(e.key):null,this._switchMode(e.mode,e.filePath)}_switchMode(e,t){if(this._currentMode===e&&this._currentFilePath===t){this._refreshCurrentMode();return}if(this._currentMode=e,this._currentFilePath=t,this._techDetailsExpanded=!1,!!this._contentEl)switch(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader(e),e){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}_renderGlobalMode(){var J,G,ee,Q,re,Pe,ye;if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-global-view"});this._driftBannerEl=e.createEl("div",{cls:"paperforge-drift-banner"}),this._driftBannerEl.style.display="none";let t=this._getCachedIndex(),r=t.length,n=0,a=0,s=0;for(let B of t)B.has_pdf&&n++,B.ocr_status==="done"&&a++,B.deep_reading_status==="done"&&s++;let i=e.createEl("div",{cls:"paperforge-library-snapshot"});i.createEl("div",{cls:"paperforge-section-label",text:"Library Snapshot"});let l=i.createEl("div",{cls:"paperforge-snapshot-pills"}),c=[{value:r,label:"papers"},{value:n,label:"PDFs ready"},{value:a,label:"OCR done"},{value:s,label:"deep-read done"}];for(let B of c){let j=l.createEl("div",{cls:"paperforge-snapshot-pill"});j.createEl("span",{cls:"paperforge-snapshot-value",text:String(B.value)}),j.createEl("span",{cls:"paperforge-snapshot-label",text:" "+B.label})}let d=e.createEl("div",{cls:"paperforge-system-status"});d.createEl("div",{cls:"paperforge-section-label",text:"System Status"});let f=d.createEl("div",{cls:"paperforge-status-grid"}),p=this.app.plugins.plugins.paperforge,m=((J=p==null?void 0:p.manifest)==null?void 0:J.version)||"?",y=this._paperforgeVersion;if(!y)try{let B=this.app.vault.adapter.basePath,{path:j,extraArgs:ie=[]}=N(B,(G=p==null?void 0:p.settings)!=null?G:null,void 0,void 0),Y=(0,_e.execFileSync)(j,[...ie,"-c","import paperforge; print(paperforge.__version__)"],{cwd:B,timeout:5e3,encoding:"utf-8",windowsHide:!0}).trim();Y&&(y=Y.startsWith("v")?Y:"v"+Y,this._paperforgeVersion=y)}catch(B){}y=y||"\u2014";let x=y==="v"+m;this._renderSystemStatusRow(f,"Runtime",x?"healthy":"mismatch",x?"v"+m:"plugin v"+m+" \u2260 CLI "+y);let _=this._loadIndex(),b=_&&_.items&&_.items.length>0;this._renderSystemStatusRow(f,"Index",b?"healthy":"missing",b?_.items.length+" entries":"formal-library.json not found");let E=((ee=p==null?void 0:p.settings)==null?void 0:ee.system_dir)||"System",k=this.app.vault.adapter.basePath,g=!1,v="No exports found";try{let B=Le.join(k,E,"PaperForge","exports");if(he.existsSync(B)){let j=he.readdirSync(B).filter(ie=>ie.endsWith(".json"));g=j.length>0,v=g?j.length+" export(s)":"No JSON exports"}}catch(B){}this._renderSystemStatusRow(f,"Zotero Export",g?"healthy":"missing",v);let w=!!((Q=p==null?void 0:p.settings)!=null&&Q.paddleocr_api_key);if(!w)try{let B=((re=p==null?void 0:p.settings)==null?void 0:re.system_dir)||"System",j=Le.join(k,B,"PaperForge",".env");if(he.existsSync(j)){let Y=he.readFileSync(j,"utf-8").match(/^PADDLEOCR_API_TOKEN\s*=\s*(.+)$/m);w=!!(Y&&Y[1]&&Y[1].trim())}}catch(B){}w||(w=!!(process.env.PADDLEOCR_API_TOKEN||process.env.PADDLEOCR_API_KEY||process.env.OCR_TOKEN)),this._renderSystemStatusRow(f,"OCR Token",w?"configured":"missing",w?"Configured":"Not set");let T=!1,P="",L=this.app.vault.adapter.basePath,O=Te(L);T=ft(L),P=O&&((Pe=O.summary)==null?void 0:Pe.reason)||O&&((ye=O.summary)==null?void 0:ye.status)||"Unknown",this._renderSystemStatusRow(f,"Memory Layer",T?"healthy":"fail",P);let z=!x&&y!=="\u2014";if(z||!b||!g||!w){let B=e.createEl("div",{cls:"paperforge-issue-summary"});B.createEl("div",{cls:"paperforge-section-label",text:"\u9700\u8981\u5904\u7406"});let j=B.createEl("div",{cls:"paperforge-issue-list"});z&&j.createEl("div",{cls:"paperforge-issue-item",text:"Runtime version mismatch"}),b||j.createEl("div",{cls:"paperforge-issue-item",text:"Index missing or corrupted"}),g||j.createEl("div",{cls:"paperforge-issue-item",text:"No Zotero export found"}),w||j.createEl("div",{cls:"paperforge-issue-item",text:"PaddleOCR API key not configured"});let ie=B.createEl("div",{cls:"paperforge-issue-actions"}),Y=ie.createEl("button",{cls:"paperforge-contextual-btn"});Y.createEl("span",{text:"Run Doctor"}),Y.addEventListener("click",()=>{let Ce=se.find(We=>We.id==="paperforge-doctor");Ce&&this._runAction(Ce,Y)});let fe=ie.createEl("button",{cls:"paperforge-contextual-btn"});fe.createEl("span",{text:"Repair Issues"}),fe.addEventListener("click",()=>{let Ce=se.find(We=>We.id==="paperforge-repair");Ce&&this._runAction(Ce,fe)})}let D=e.createEl("div",{cls:"paperforge-global-actions"});D.createEl("div",{cls:"paperforge-section-label",text:"Start Working"});let S=D.createEl("div",{cls:"paperforge-global-actions-row"}),M=S.createEl("button",{cls:"paperforge-contextual-btn primary"});M.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4C1}"}),M.createEl("span",{text:"Open Literature Hub"}),M.addEventListener("click",()=>{var ie;let B=((ie=p==null?void 0:p.settings)==null?void 0:ie.base_dir)||"Bases",j=this.app.vault.getAbstractFileByPath(B);if(j){let Y=null;if(j.children&&(Y=j.children.find(fe=>fe.extension==="base")),Y){let fe=this.app.workspace.getLeaf(!1);fe&&fe.openFile(Y)}else new I.Notice("[!!] No .base file found in "+B,6e3)}else new I.Notice("[!!] Base directory not found: "+B,6e3)});let C=S.createEl("button",{cls:"paperforge-contextual-btn"});C.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),C.createEl("span",{text:"Sync Library"}),C.addEventListener("click",()=>{let B=se.find(j=>j.id==="paperforge-sync");B&&this._runAction(B,C)});let F=S.createEl("button",{cls:"paperforge-contextual-btn"});F.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),F.createEl("span",{text:"Run OCR"}),F.addEventListener("click",()=>{let B=se.find(j=>j.id==="paperforge-ocr");B&&this._runAction(B,F)});let A=S.createEl("button",{cls:"paperforge-contextual-btn warn"});A.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),A.createEl("span",{text:"Redo OCR"}),A.addEventListener("click",()=>{let B=se.find(j=>j.id==="paperforge-ocr-redo");B&&this._runAction(B,A)})}_renderSystemStatusRow(e,t,r,n){let a=e.createEl("div",{cls:"paperforge-status-row"});a.createEl("span",{cls:"paperforge-status-dot"}).addClass(r==="healthy"||r==="configured"?"ok":"fail"),a.createEl("span",{cls:"paperforge-status-label",text:t}),a.createEl("span",{cls:"paperforge-status-detail",text:n||""})}_renderPaperMode(){let e=this._currentPaperEntry,t=this._currentPaperKey;if(!this._contentEl)return;if(!t){this._renderEmptyState(this._contentEl,"No paper data available.");return}if(!e){this._contentEl.createEl("div",{cls:"paperforge-content-placeholder",text:'Paper "'+t+'" not found in canonical index. Sync first.'});return}let r=this._contentEl.createEl("div",{cls:"paperforge-paper-view"}),n=r.createEl("div",{cls:"paperforge-paper-header"});n.createEl("div",{cls:"paperforge-paper-title pf-copy",text:e.title||"Untitled"}).addEventListener("click",()=>{navigator.clipboard.writeText(e.title||""),new I.Notice("Title copied")});let s=n.createEl("div",{cls:"paperforge-paper-meta"});e.authors&&e.authors.length>0&&s.createEl("span",{cls:"paperforge-paper-authors",text:e.authors.join(", ")}),e.year&&s.createEl("span",{cls:"paperforge-paper-year",text:String(e.year)});let i=r.createEl("div",{cls:"paperforge-status-strip"}),l=i.createEl("div",{cls:"paperforge-status-strip-left"}),c=i.createEl("div",{cls:"paperforge-status-strip-right"}),d=[{key:"pdf",label:"PDF",ok:e.has_pdf===!0},{key:"ocr",label:"OCR",ok:e.ocr_status==="done",pending:["pending","queued","processing"].includes(e.ocr_status||""),fail:["failed","blocked","done_incomplete","nopdf"].includes(e.ocr_status||"")},{key:"deep",label:"\u7CBE\u8BFB",ok:e.deep_reading_status==="done"}];for(let p of d){let m=l.createEl("span",{cls:"paperforge-status-pill"}),y="pending";p.ok?y="ok":p.fail?y="fail":p.pending&&(y="pending"),m.addClass(y);let x=p.ok?"\u2713":p.fail?"\u2717":"\u25CB";m.createEl("span",{cls:"paperforge-status-pill-icon",text:x}),m.createEl("span",{text:" "+p.label})}if(e.pdf_path){let p=c.createEl("button",{cls:"paperforge-contextual-btn"});p.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4C4}"}),p.createEl("span",{text:"\u6253\u5F00 PDF"}),p.addEventListener("click",()=>{let m=e.pdf_path.match(/\[\[([^\]]+)\]\]/),y=m?m[1]:e.pdf_path;this.app.vault.getAbstractFileByPath(y)?this.app.workspace.openLinkText(y,""):new I.Notice("[!!] PDF not found: "+y,6e3)})}if(e.fulltext_path){let p=c.createEl("button",{cls:"paperforge-contextual-btn"});p.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u{1F4DD}"}),p.createEl("span",{text:"\u6253\u5F00\u5168\u6587"}),p.addEventListener("click",()=>this._openFulltext(e.fulltext_path))}let f=c.createEl("button",{cls:"paperforge-contextual-btn"});if(f.createEl("span",{text:o("version_panel_title")}),f.addEventListener("click",()=>{this._switchToVersionMode(t)}),this._renderPaperOverviewCard(r,e),e.next_step==="ready"&&e.deep_reading_status==="done"){let p=r.createEl("div",{cls:"paperforge-complete-row"});p.createEl("span",{text:"\u2713"}),p.createEl("span",{text:"\u5DF2\u5B8C\u6210\uFF0C\u53EF\u76F4\u63A5\u4F7F\u7528"})}else this._renderNextStepCard(r,e,t);this._renderRecentDiscussionCard(r,e),this._renderPaperTechnicalDetails(r,e)}_renderPaperOverviewCard(e,t){let r=e.createEl("div",{cls:"paperforge-paper-overview"});r.createEl("div",{cls:"paperforge-paper-overview-header"}).createEl("span",{cls:"paperforge-paper-overview-title",text:"\u6587\u7AE0\u6982\u89C8"});let a=r.createEl("div",{cls:"paperforge-paper-overview-body"}),s=a.createEl("div",{cls:"paperforge-paper-overview-excerpt",text:"\u52A0\u8F7D\u4E2D..."});if(t.note_path){let i=this.app.vault.getAbstractFileByPath(t.note_path);i?this.app.vault.read(i).then(l=>{let c=this._extractOverviewFromNote(l);if(c){let d=c.length>200?c.slice(0,200)+"...":c;if(s.setText(d),c.length>200){let f=a.createEl("div",{cls:"paperforge-expand-container"}),p=f.createEl("button",{cls:"paperforge-expand-icon",title:"\u5C55\u5F00/\u6536\u8D77"});p.innerHTML='';let m=!1;f.addEventListener("click",()=>{s.setText(m?d:c),p.innerHTML=m?'':'',m=!m})}}else s.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8\u3002\u8FD0\u884C /pf-deep \u5F00\u59CB\u7CBE\u8BFB\u3002")}).catch(()=>{s.setText("\u65E0\u6CD5\u8BFB\u53D6\u7B14\u8BB0\u5185\u5BB9")}):s.setText("\u7B14\u8BB0\u6587\u4EF6\u4E0D\u5B58\u5728")}else s.setText("\u5C1A\u672A\u751F\u6210\u6587\u7AE0\u6982\u89C8")}_extractOverviewFromNote(e){if(!e)return null;let t=e.indexOf("## \u{1F50D} \u7CBE\u8BFB");if(t===-1)return null;let r=e.slice(t),n=["**\u4E00\u53E5\u8BDD\u603B\u89C8:**","**\u4E00\u53E5\u8BDD\u603B\u89C8**","**\u6587\u7AE0\u6458\u8981:**","**\u6587\u7AE0\u6458\u8981**"];for(let i of n){let l=r.indexOf(i);if(l!==-1){let c=r.slice(l+i.length),d=["**5 Cs","**Figure","**\u8BC1\u636E","### Pass 2","## "],f=c.length;for(let y of d){let x=c.indexOf(y);x!==-1&&x300?s.slice(0,300)+"...":s}_renderRecentDiscussionCard(e,t){let r=e.createEl("div",{cls:"paperforge-discussion-card"});if(r.style.display="none",!t.note_path)return;let n=t.note_path.lastIndexOf("/"),s=(n!==-1?t.note_path.substring(0,n):".")+"/ai/discussion.md";this.app.vault.adapter.exists(s).then(l=>{if(l)return this.app.vault.adapter.read(s)}).then(async l=>{if(!l)return;let i=this._parseDiscussionMD(l);if(!i||i.length===0)return;r.style.display="block",r.createEl("div",{cls:"paperforge-discussion-header"}).createEl("span",{cls:"paperforge-discussion-title",text:"\u6700\u8FD1\u8BA8\u8BBA"});for(let g of i){let p=r.createEl("div",{cls:"paperforge-discussion-item"}),f=p.createEl("div",{cls:"paperforge-discussion-q"});f.createEl("span",{cls:"paperforge-discussion-q-label",text:"\u63D0\u95EE\uFF1A"}),f.createEl("span",{cls:"paperforge-discussion-q-text",text:g.question});let y=p.createEl("div",{cls:"paperforge-discussion-a"}),b=!1;if(g.answer&&g.answer.length>500&&(b=!0,y.classList.add("paperforge-discussion-a-collapsed")),await B.MarkdownRenderer.render(this.app,g.answer||"",y,s,this),b){let m=!1;p.style.cursor="pointer",p.addEventListener("click",()=>{m=!m,y.classList.toggle("paperforge-discussion-a-collapsed",!m),y.classList.toggle("paperforge-discussion-a-expanded",m)})}}r.createEl("a",{cls:"paperforge-discussion-viewall",text:"\u67E5\u770B\u5168\u90E8\u8BA8\u8BBA \u2192"}).addEventListener("click",g=>{g.preventDefault(),this.app.vault.getAbstractFileByPath(s)?this.app.workspace.openLinkText(s,""):new B.Notice("\u8BA8\u8BBA\u6587\u4EF6\u5C1A\u672A\u751F\u6210")})}).catch(l=>{console.error("PaperForge: discussion.md read error",s,l.message)})}_parseDiscussionMD(e){let t=e.split(/\n## /).slice(1);if(t.length===0)return null;let r=t[t.length-1],n=[],a=r.split(/\*\*\u95EE\u9898:\*\*/).slice(1);for(let s of a){let l=s.match(/\*\*\u89E3\u7B54:\*\*/);if(!l)continue;let i=s.substring(0,l.index).trim(),c=s.substring(l.index+3+4).trim();n.push({question:i,answer:c})}return n.slice(-3)}_renderPaperTechnicalDetails(e,t){let r=this._currentPaperKey,n=e.createEl("div",{cls:"paperforge-technical-details"}),a=n.createEl("button",{cls:"paperforge-technical-details-toggle"}),s=n.createEl("div",{cls:"paperforge-technical-details-body"});s.style.display="none",this._techDetailsExpanded?(s.style.display="block",a.setText("\u6280\u672F\u8BE6\u60C5 \u25BE")):a.setText("\u6280\u672F\u8BE6\u60C5 \u25B8"),a.addEventListener("click",()=>{let p=s.style.display!=="none";s.style.display=p?"none":"block",a.setText(p?"\u6280\u672F\u8BE6\u60C5 \u25B8":"\u6280\u672F\u8BE6\u60C5 \u25BE"),this._techDetailsExpanded=!p});let l=s.createEl("div",{cls:"paperforge-workflow-toggles"}),i=[{key:"do_ocr",label:"OCR",hint:"\u52A0\u5165 OCR"},{key:"analyze",label:"\u7CBE\u8BFB",hint:"\u6807\u8BB0\u7CBE\u8BFB"}];for(let p of i){let f=l.createEl("label",{cls:"paperforge-workflow-toggle"}),y=f.createEl("input",{type:"checkbox",cls:"paperforge-workflow-checkbox"});y.checked=t[p.key]===!0,f.createEl("span",{cls:"paperforge-workflow-toggle-label",text:p.label}),f.createEl("span",{cls:"paperforge-workflow-toggle-hint",text:p.hint}),y.addEventListener("change",async()=>{let b=t.note_path?this.app.vault.getAbstractFileByPath(t.note_path):null;if(!b){new B.Notice("[!!] Note file not found",6e3);return}let m=y.checked;await this.app.fileManager.processFrontMatter(b,x=>{x[p.key]=m}),this._patchCachedEntry(r,{[p.key]:m}),this._currentPaperEntry=Ke(this._currentPaperEntry,{[p.key]:m})})}let c=t.health||{},d=[["PDF Health",c.pdf_health||"\u2014"],["OCR Status",t.ocr_status||"\u2014"],["Asset Health",c.asset_health||"\u2014"],["Note Path",t.note_path||"\u2014"],["Fulltext Path",t.fulltext_path||"\u2014"]],g=new Set(["Note Path","Fulltext Path","Key"]);for(let[p,f]of d){let y=s.createEl("div",{cls:"paperforge-technical-row"});y.createEl("span",{cls:"paperforge-technical-label",text:p});let b=y.createEl("span",{cls:"paperforge-technical-value",text:String(f)});g.has(p)&&f&&f!=="\u2014"&&(b.addClass("pf-copy"),b.addEventListener("click",()=>{navigator.clipboard.writeText(f),new B.Notice(p+" copied")}))}}_renderNextStepCard(e,t,r){var i,c;let n=t.next_step||"ready",a={sync:{label:"Sync Needed",text:"This paper needs to be synced from Zotero. Click to run sync.",cmd:"sync",icon:"\u21BB"},ocr:{label:"OCR Needed",text:"Fulltext is missing but PDF is present. Click to run OCR.",cmd:"ocr",icon:"\u229E"},repair:{label:"Repair Needed",text:"State divergence or path errors detected. Click to repair.",cmd:"repair",icon:"\u21BA"},"rebuild index":{label:"Rebuild Needed",text:"Index may be stale. Click to run sync to rebuild.",cmd:"sync",icon:"\u21BB"},"/pf-deep":{label:"Ready for Deep Reading",text:"Fulltext is ready. Copy /pf-deep command and run in your agent.",cmd:null,icon:"\u{1F50D}"},ready:{label:"All Set",text:"This paper is fully processed and ready for use.",cmd:"ready",icon:"\u2713"}},s=a[n]||a.ready,l=e.createEl("div",{cls:"paperforge-next-step-card"});if(n==="ready"&&l.addClass("ready"),l.createEl("div",{cls:"paperforge-next-step-label",text:"Recommended Next Step"}),l.createEl("div",{cls:"paperforge-next-step-text",text:s.text}),s.cmd&&s.cmd!=="ready"){let d=l.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:s.icon+" "+s.label}),d.addEventListener("click",()=>{let g=Y.find(p=>p.cmd===s.cmd);g&&this._runAction(g,d)})}else if(n==="/pf-deep"){let d=l.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:"\u{1F4CB} "+o("copy_pf_deep_cmd")}),d.addEventListener("click",()=>{let b="/pf-deep "+r;navigator.clipboard.writeText(b).then(()=>{d.setText("\u2713 "+o("copied")),new B.Notice(b+" copied")}).catch(()=>{new B.Notice("[!!] Clipboard write failed",6e3)})});let g=((c=(i=this.app.plugins.plugins.paperforge)==null?void 0:i.settings)==null?void 0:c.agent_platform)||"opencode",f={opencode:"OpenCode",claude:"Claude Code",cursor:"Cursor",github_copilot:"GitHub Copilot",windsurf:"Windsurf",codex:"Codex",gemini:"Gemini CLI",cline:"Cline"}[g]||g;l.createEl("div",{cls:"paperforge-agent-platform-label"}).setText(o("run_in_agent").replace("{0}",f))}else n==="ready"&&l.createEl("button",{cls:"paperforge-next-step-trigger"}).createEl("span",{text:"\u2713 "+s.label})}_openFulltext(e){if(!e){new B.Notice("[!!] No fulltext path available for this paper",6e3);return}let t=this.app.vault.getAbstractFileByPath(e);t?this.app.workspace.openLinkText(t.path,""):new B.Notice("[!!] Fulltext file not found: "+e,6e3)}_renderCollectionMode(){let e=this._currentDomain||"Unknown",t=this._filterByDomain(e);if(t.length===0){this._renderGlobalMode();return}if(!this._contentEl)return;let r=this._contentEl.createEl("div",{cls:"paperforge-collection-view"}),n=t.length,a=0,s=0,l=0,i=0,c=0,d=0,g=0;for(let _ of t){_.has_pdf&&a++,_.ocr_status==="done"&&s++,_.ocr_status==="done"&&_.analyze===!0&&l++,_.deep_reading_status==="done"&&i++;let v=_.ocr_status||"";v==="pending"||v==="queued"?c++:v==="processing"?d++:(v==="failed"||v==="blocked"||v==="done_incomplete"||v==="nopdf")&&g++}r.createEl("div",{cls:"paperforge-collection-header"}).createEl("div",{cls:"paperforge-collection-title",text:e});let f=r.createEl("div",{cls:"paperforge-workflow-overview"});f.createEl("div",{cls:"paperforge-section-label",text:"Workflow Overview"});let y=f.createEl("div",{cls:"paperforge-workflow-funnel"}),b=[{value:n,label:"Total"},{value:a,label:"PDF Ready"},{value:s,label:"OCR Done"},{value:i,label:"Deep Read"}];for(let _=0;_0){let _=r.createEl("div",{cls:"paperforge-ocr-section"}),v=_.createEl("div",{cls:"paperforge-collection-ocr-header"});v.createEl("h4",{cls:"paperforge-ocr-title",text:"OCR Pipeline"});let k=v.createEl("span",{cls:"paperforge-ocr-badge idle"});d>0?(k.addClass("active"),k.setText("Processing")):c>0?k.setText("Pending"):(k.addClass("idle"),k.setText("Idle"));let S=_.createEl("div",{cls:"paperforge-progress-track"});d>0&&S.addClass("paperforge-processing");let P=c+d+s+g,A=[{cls:"pending",count:c},{cls:"active",count:d},{cls:"done",count:s},{cls:"failed",count:g}];for(let z of A)if(z.count>0){let O=(z.count/P*100).toFixed(1);S.createEl("div",{cls:`paperforge-progress-seg ${z.cls}`,attr:{style:`width:${O}%`}})}let T=_.createEl("div",{cls:"paperforge-ocr-counts"}),I=[{cls:"pending",value:c,label:"Pending"},{cls:"active",value:d,label:"Processing"},{cls:"done",value:s,label:"Done"},{cls:"failed",value:g,label:"Attention"}];for(let z of I){let O=T.createEl("div",{cls:"paperforge-ocr-count"});O.createEl("div",{cls:"paperforge-ocr-count-value",text:z.value.toString()}),O.createEl("div",{cls:"paperforge-ocr-count-label",text:z.label})}}let m=r.createEl("div",{cls:"paperforge-collection-actions"}),x=m.createEl("button",{cls:"paperforge-contextual-btn primary"});x.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),x.createEl("span",{text:"Run OCR"}),x.addEventListener("click",()=>{let _=Y.find(v=>v.id==="paperforge-ocr");_&&this._runAction(_,x)});let w=m.createEl("button",{cls:"paperforge-contextual-btn"});w.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),w.createEl("span",{text:"Sync Library"}),w.addEventListener("click",()=>{let _=Y.find(v=>v.id==="paperforge-sync");_&&this._runAction(_,w)});let E=m.createEl("button",{cls:"paperforge-contextual-btn warn"});E.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),E.createEl("span",{text:"Redo OCR"}),E.addEventListener("click",()=>{let _=Y.find(v=>v.id==="paperforge-ocr-redo");_&&this._runAction(_,E)}),this.renderSearchSection(r)}_refreshCurrentMode(){if(!(!this._currentMode||!this._contentEl)){this._contentEl.empty(),this._contentEl.addClass("switching"),this._invalidateIndex(),this._currentPaperEntry=this._currentPaperKey?this._findEntry(this._currentPaperKey):null,this._renderModeHeader(this._currentMode);try{switch(this._currentMode){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}finally{setTimeout(()=>{this._contentEl&&this._contentEl.removeClass("switching")},50)}}}_switchToVersionMode(e){let r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){new B.Notice("Cannot determine vault path");return}this._versionPapers=tt(n),this._versionFilter="",this._currentMode="versions",this._currentFilePath=null,this._techDetailsExpanded=!1,this._contentEl&&(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader("versions"),this._renderVersionMode())}_renderVersionMode(){if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-version-panel"}),r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){e.createEl("div",{cls:"paperforge-status-error",text:"Could not determine vault path"});return}(!this._versionPapers||this._versionPapers.length===0)&&(this._versionPapers=tt(n));let a=e.createEl("div",{cls:"paperforge-version-left"}),s=e.createEl("div",{cls:"paperforge-version-right"}),l=a.createEl("input",{cls:"paperforge-version-filter",attr:{type:"text",placeholder:o("version_filter_placeholder")}});l.value=this._versionFilter;let i=a.createEl("div",{cls:"paperforge-version-paper-list"}),c=()=>{i.empty();let x=this._versionFilter.toLowerCase(),w=this._versionPapers?this._versionPapers.filter(_=>!x||_.key.toLowerCase().includes(x)||_.title.toLowerCase().includes(x)):[];if(w.length===0){i.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let E=i.createEl("div",{cls:"paperforge-meta",text:o("version_papers_count").replace("{n}",String(w.length))});for(let _ of w){let v=i.createEl("div",{cls:"paperforge-version-paper-item"}),k=v.createEl("span",{cls:"paperforge-version-paper-title",text:_.title}),S=v.createEl("span",{cls:"paperforge-version-paper-versions",text:_.versions.map(P=>P.label).join(" ")});v.addEventListener("click",()=>{i.querySelectorAll(".paperforge-version-paper-item.selected").forEach(P=>P.removeClass("selected")),v.addClass("selected"),g(_)})}};l.addEventListener("input",()=>{this._versionFilter=l.value,c()});let d=s.createEl("div",{cls:"paperforge-version-timeline-area"}),g=x=>{if(d.empty(),d.createEl("div",{cls:"paperforge-version-timeline-header"}).createEl("span",{cls:"pf-title",text:x.title}),x.versions.length===0){d.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let E=d.createEl("div",{cls:"paperforge-version-timeline"});for(let _ of x.versions){let v=_.label===x.currentLabel,k=E.createEl("div",{cls:"paperforge-version-entry"+(v?" paperforge-version-current":"")}),S=k.createEl("div",{cls:"paperforge-version-dot"}),P=k.createEl("div",{cls:"paperforge-version-content"}),A=P.createEl("div",{cls:"paperforge-version-label-row"});A.createEl("span",{cls:"paperforge-version-label",text:_.label}),v&&A.createEl("span",{cls:"paperforge-version-current-tag",text:o("version_current")});let T=_.created_at?_.created_at.slice(0,10):"";P.createEl("div",{cls:"paperforge-meta",text:T+" \u2014 "+_.source});let I=_.fulltext_size?_.fulltext_size>1024?(_.fulltext_size/1024).toFixed(0)+"KB":_.fulltext_size+"B":"";I&&P.createEl("div",{cls:"paperforge-meta",text:I});let z=P.createEl("div",{cls:"paperforge-version-actions"});z.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_btn")}).addEventListener("click",()=>{Ct(n,x.key,_.label)?new B.Notice(o("version_restore_done").replace("{label}",_.label)):new B.Notice("Restore failed",6e3)}),x.versions.length>1&&!v&&z.createEl("button",{cls:"pf-btn-secondary",text:o("version_compare_btn")}).addEventListener("click",()=>{f(x,_.label,x.currentLabel)})}},p=s.createEl("div",{cls:"paperforge-version-compare"});p.style.display="none";let f=(x,w,E)=>{let _=Ft(n,x.key,w,E);p.style.display="block",p.empty();let v=p.createEl("div",{cls:"paperforge-version-compare-header"});if(v.createEl("span",{cls:"pf-title",text:o("version_compare_title").replace("{vA}",w).replace("{vB}",E)}),v.createEl("span",{cls:"paperforge-meta",text:o("version_compare_paragraphs").replace("{n}",String(_.length))}),_.length===0){p.createEl("div",{cls:"paperforge-meta",text:"No changes"});return}let k=p.createEl("div",{cls:"paperforge-version-diff-list"});for(let S of _){let P=k.createEl("div",{cls:"paperforge-version-diff-row"}),A=S.type==="added"?"[+]":S.type==="removed"?"[-]":"[~]",T=S.heading||"paragraph "+(S.paragraphIndex+1);P.createEl("span",{cls:"paperforge-version-diff-label",text:A+" "+T}),S.oldText&&P.createEl("pre",{cls:"paperforge-version-diff-old",text:S.oldText.slice(0,200)}),S.newText&&P.createEl("pre",{cls:"paperforge-version-diff-new",text:S.newText.slice(0,200)})}},y=e.createEl("div",{cls:"paperforge-version-actions-bar"}),b=y.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_selected")}),m=y.createEl("button",{cls:"pf-btn-secondary",text:o("version_clear_old").replace("{size}","")});c()}renderSearchSection(e){this._searchContainer=e.createEl("div",{cls:"paperforge-search-section"}),this._searchContainer.createEl("div",{cls:"paperforge-search-header"}).createEl("span",{cls:"pf-label",text:"Search"});let r=this._searchContainer.createEl("div",{cls:"paperforge-search-input-row"}),n=r.createEl("span",{cls:"paperforge-search-mode",text:"M"});this._searchInput=r.createEl("input",{cls:"paperforge-search-input",attr:{type:"text",placeholder:"Search papers... (@ for deep search)"}}),this._searchResultsEl=this._searchContainer.createEl("div",{cls:"paperforge-search-results"}),this._searchInput.addEventListener("input",()=>{var s;let a=((s=this._searchInput)==null?void 0:s.value)||"";a.startsWith("@")&&!a.startsWith("@ ")?(n.setText("@"),n.addClass("deep")):(n.setText("M"),n.removeClass("deep")),clearTimeout(this._searchTimer),!a.startsWith("@")&&a.trim()&&(this._searchTimer=setTimeout(()=>{this.executeSearch()},200))}),this._searchInput.addEventListener("keydown",a=>{a.key==="Enter"&&(a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0),this.executeSearch())})}async executeSearch(){if(!this._searchInput||!this._searchResultsEl)return;let e=this._searchInput.value.trim();if(!e)return;let t=e.startsWith("@"),r=t?e.slice(1).trim():e;if(!r)return;let n=t?"retrieve":"search",a=this.app.vault.adapter,s="";if(a&&typeof a=="object"&&"basePath"in a){let b=a.basePath;s=typeof b=="string"?b:""}if(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-loading",text:"Searching..."}),!s){this._renderSearchError("Could not determine vault path");return}let l=null,c=this.app.plugins;if(c&&typeof c=="object"&&"plugins"in c){let b=c.plugins;if(b&&typeof b=="object"&&"paperforge"in b){let m=b.paperforge;m&&typeof m=="object"&&"settings"in m&&(l=m.settings)}}let{path:d,extraArgs:g=[]}=L(s,l,void 0,void 0),p=n==="retrieve"?["--deep"]:[],f=(0,fe.spawn)(d,[...g,"-m","paperforge",n,r,...p,"--json"],{cwd:s,timeout:3e4}),y=[];f.stdout.on("data",b=>{y.push(b.toString("utf-8"))}),f.stderr.on("data",()=>{}),f.on("close",b=>{if(b!==0){this._renderSearchError(`Search failed (exit ${b})`);return}let m=y.join(""),x=m.indexOf("{"),w=m.lastIndexOf("}"),E="";if(x!==-1&&w>x)E=m.slice(x,w+1);else{let _=m.indexOf("["),v=m.lastIndexOf("]");_!==-1&&v>_&&(E=m.slice(_,v+1))}if(!E){this._renderSearchError("No JSON output from CLI");return}try{let _=JSON.parse(E),v=[];if(_&&typeof _=="object"&&"data"in _){let k=_.data;if(k&&typeof k=="object"){let S=k;"matches"in S&&Array.isArray(S.matches)&&(v=S.matches)}}this.renderSearchResults(v,t)}catch(_){let v=_ instanceof Error?_.message:String(_);this._renderSearchError("Failed to parse results: "+v)}}),f.on("error",b=>{this._renderSearchError("Process error: "+b.message)})}renderSearchResults(e,t){if(!this._searchResultsEl)return;if(this._searchResultsEl.empty(),e.length===0){this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty",text:"No results found."});return}let r=this._searchResultsEl.createEl("div",{cls:"paperforge-search-results-header"});r.createEl("span",{text:`${e.length} result${e.length!==1?"s":""}`}),r.createEl("span",{cls:"paperforge-search-mode",text:t?"@":"M"});for(let n of e){if(!n||typeof n!="object")continue;let a=n,s=this._searchResultsEl.createEl("div",{cls:"paperforge-search-result-card",attr:{role:"button"}}),l=typeof a.title=="string"?a.title:typeof a.file_name=="string"?a.file_name:"(untitled)";s.createEl("div",{cls:"paperforge-search-result-title",text:l});let i=typeof a.zotero_key=="string"?a.zotero_key:"",c=typeof a.main_note_path=="string"&&a.main_note_path?a.main_note_path:null,d=typeof a.note_path=="string"&&a.note_path?a.note_path:null,g=c||d;if(!g&&i){let y=this._getCachedIndex().find(b=>b!==null&&typeof b=="object"&&"zotero_key"in b&&b.zotero_key===i);if(y&&typeof y=="object"){let b=y;g=typeof b.main_note_path=="string"&&b.main_note_path?b.main_note_path:typeof b.note_path=="string"&&b.note_path?b.note_path:null}}g?s.addEventListener("click",f=>{let y=f.ctrlKey||f.metaKey;this.app.workspace.openLinkText(g,"",y)}):s.addEventListener("click",()=>{new B.Notice("[!!] Note not found: "+(i||"unknown"),6e3)});let p=s.createEl("div",{cls:"paperforge-search-result-meta"});if(typeof a.first_author=="string"&&a.first_author&&p.createEl("span",{cls:"paperforge-search-result-author",text:a.first_author}),typeof a.journal=="string"&&a.journal&&p.createEl("span",{cls:"paperforge-search-result-journal",text:a.journal}),a.score!==void 0){let f=a.score,y=typeof f=="number"?f.toFixed(3):String(f);p.createEl("span",{cls:"paperforge-search-result-score",text:"Score: "+y})}if(typeof a.domain=="string"&&a.domain&&s.createEl("span",{cls:"paperforge-search-result-tag",text:a.domain}),typeof a.abstract=="string"&&a.abstract){let f=a.abstract;s.createEl("div",{cls:"paperforge-search-result-abstract",text:f.length>200?f.slice(0,200)+"...":f})}if(t&&typeof a.text=="string"&&a.text){let f=a.text;s.createEl("div",{cls:"paperforge-search-result-source",text:f.length>300?f.slice(0,300)+"...":f})}}}_renderSearchError(e){this._searchResultsEl&&(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-error",text:e}))}_runAction(e,t){var p,f;if(e.disabled){new B.Notice(`[i] ${e.disabledMsg||"This action is not yet available."}`,6e3);return}if(t.classList.contains("running"))return;t.addClass("running");let r=this.app.vault.adapter.basePath;this._showMessage("Processing...","running");let n=Array.isArray(e.args)?[...e.args]:[];if(e.needsKey){let y=this.app.workspace.getActiveFile(),b=null;if(y){let m=this.app.metadataCache.getFileCache(y);if(m&&m.frontmatter&&m.frontmatter.zotero_key?b=m.frontmatter.zotero_key:b=this._extractZoteroKeyFromPath(y.path),b)n=[...n,b];else if(m&&m.frontmatter){this._showMessage("[!!] No zotero_key in active note frontmatter","error"),new B.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}else{this._showMessage("[!!] No frontmatter in active note","error"),new B.Notice("[!!] The active note has no frontmatter with a zotero_key",6e3),t.removeClass("running");return}}else{this._showMessage("[!!] No active note open","error"),new B.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}}e.needsFilter&&(n=[...n,"--all"]);let a=e.needsFilter?6e4:e.needsKey?3e4:6e5,{path:s,extraArgs:l=[]}=L(r,(f=(p=this.app.plugins.plugins.paperforge)==null?void 0:p.settings)!=null?f:null,void 0,void 0),i=(0,fe.spawn)(s,[...l,"-m","paperforge",e.cmd,...n],{cwd:r,timeout:a}),c=[],d=Date.now(),g=setInterval(()=>this._fetchStats(!0),4e3);i.stdout.on("data",y=>{let b=y.toString("utf-8").split(` -`).filter(Boolean);for(let m of b){let x=m.trim();x&&(c.push(x),this._showMessage(c.slice(-8).join(` -`),"running"))}}),i.stderr.on("data",y=>{let b=y.toString("utf-8").split(` -`).filter(Boolean);for(let m of b){if(m.includes("\r")||m.includes("%")||m.includes("\u2588"))continue;let x=m.trim();x&&!x.match(/^\d+%|^\|/)&&(c.push(x),this._showMessage(c.slice(-8).join(` -`),"running"))}}),i.on("close",y=>{clearInterval(g),t.removeClass("running");let b=((Date.now()-d)/1e3).toFixed(1);if(y!==0){let m=c.slice(-3).join(" | ")||"exit code "+y;(e.cmd==="repair"||e.cmd==="ocr")&&y===1?(this._showMessage("[WARN] "+m,"running"),new B.Notice("[WARN] "+e.cmd+" partial: "+m,8e3),this._fetchStats(!0)):(this._showMessage("[!!] "+m,"error"),new B.Notice("[!!] "+e.cmd+" failed: "+m,8e3))}else if(e.needsKey||e.needsFilter){let m=c.join(` -`);if(m.trim())try{JSON.parse(m),navigator.clipboard.writeText(m).then(()=>{let x=`${b}s \u2014 ${m.length} chars copied`;this._showMessage("[OK] "+e.title+": "+x,"ok"),new B.Notice("[OK] "+e.okMsg+" \u2014 "+m.length+" chars")}).catch(x=>{this._showMessage("[!!] Clipboard write failed: "+x.message,"error"),new B.Notice("[!!] Clipboard error",6e3)})}catch(x){this._showMessage("[!!] Invalid JSON from "+e.title,"error"),new B.Notice("[!!] "+e.title+" returned invalid JSON: "+x.message.slice(0,100),8e3)}else this._showMessage("[!!] No output from context command","error"),new B.Notice("[!!] Context command returned empty output",8e3);this._fetchStats(!0)}else{let x=c.filter(E=>E.match(/updated \d+/)).pop()||c[c.length-1]||"",w=`${b}s \u2014 ${x}`;this._showMessage("[OK] "+e.title+": "+w,"ok"),new B.Notice("[OK] "+e.okMsg),this._contentEl&&this._contentEl.removeClass("switching"),this._cachedStats=null;try{this._fetchStats(!1)}catch(E){console.log("[PF] fetchStats error:",E)}console.log("[PF] close cmd="+e.cmd+" id="+e.id),e.cmd==="sync"&&Ne(this.app,this.app.plugins.plugins.paperforge,r)}}),i.on("error",y=>{t.removeClass("running"),this._contentEl&&this._contentEl.removeClass("switching"),this._showMessage("[!!] "+y.message,"error"),new B.Notice("[!!] Cannot start: "+y.message,8e3)})}_showMessage(e,t){this._messageEl&&(this._messageEl.setText(e),this._messageEl.className=`paperforge-message msg-${t}`)}_renderModeHeader(e){if(!this._modeContextEl)return;this._modeContextEl.empty();let t=this._modeContextEl.createEl("span",{cls:"paperforge-mode-badge"}),r="";switch(e){case"global":t.addClass("global"),t.setText("Global"),this._headerTitle&&this._headerTitle.setText("PaperForge");break;case"paper":t.addClass("paper"),t.setText("Paper"),this._headerTitle&&this._headerTitle.setText("Paper"),this._currentPaperEntry&&this._currentPaperEntry.title?r=this._currentPaperEntry.title:this._currentPaperKey?(r=this._currentPaperKey,this._modeContextEl.createEl("span",{cls:"paperforge-mode-warning",text:"Not found in index"})):r="Unknown paper";break;case"collection":t.addClass("collection"),t.setText("Collection"),this._headerTitle&&this._headerTitle.setText("Collection"),r=this._currentDomain||"Unknown Domain";break;case"versions":t.addClass("versions"),t.setText(o("version_panel_title")),this._headerTitle&&this._headerTitle.setText(o("version_panel_title"));break}r&&this._modeContextEl.createEl("span",{cls:"paperforge-mode-name",text:r})}_setupEventSubscriptions(){let e=this.app.workspace.on("active-leaf-change",()=>{this._leafChangeTimer&&clearTimeout(this._leafChangeTimer),this._leafChangeTimer=setTimeout(()=>{let r=this._resolveModeForFile(this.app.workspace.getActiveFile()),n=r.mode,a=r.filePath;this._currentMode===n&&this._currentFilePath===a||this._detectAndSwitch()},300)});this._modeSubscribers.push({event:"active-leaf-change",ref:e});let t=this.app.vault.on("modify",r=>{r&&r.path&&r.path.endsWith("formal-library.json")&&(this._invalidateIndex(),this._refreshCurrentMode())});this._modeSubscribers.push({event:"modify",ref:t})}static async open(e){let t=e.app.workspace.getLeavesOfType(_e);if(t.length>0){e.app.workspace.revealLeaf(t[0]);return}let r=e.app.workspace.getRightLeaf(!1);r&&(await r.setViewState({type:_e,active:!0}),e.app.workspace.revealLeaf(r))}};var He=class extends K.Plugin{constructor(){super(...arguments);this._lastExportMtime=0;this._lastOcrMtimes={};this._autoSyncRunning=!1;this._lastSyncTime=null;this._pollTimer=null;this._embedProcess=null;this._embedProgress={current:0,total:0,key:""};this._embedStderr="";this._memoryStatusText=null}async onload(){await this.loadSettings(),this.saveSettings(),at(this.app),this.registerView(_e,t=>new Ee(t));try{(0,K.addIcon)(Ce,st)}catch(t){}this.addRibbonIcon(Ce,"PaperForge Dashboard",()=>Ee.open(this)),Y.find(t=>t.id==="paperforge-ocr-redo")&&this.addRibbonIcon("reset","PaperForge: Redo OCR",()=>{let t=this.app.vault.adapter.basePath;new K.Notice("PaperForge: Redo OCR starting...");let{path:r,extraArgs:n}=L(t,this.settings,void 0,void 0);(0,ie.execFile)(r,[...n,"-m","paperforge","ocr","redo"],{cwd:t,timeout:6e5},(a,s,l)=>{if(a){new K.Notice("PaperForge: Redo OCR failed");return}new K.Notice("PaperForge: Redo OCR done")})}),this.addSettingTab(new je(this.app,this)),this.addCommand({id:"paperforge-status-panel",name:`PaperForge: ${o("guide_open")}`,callback:()=>Ee.open(this)});for(let t of Y)this.addCommand({id:t.id,name:`PaperForge: ${t.title}`,callback:()=>{if(t.disabled){new K.Notice(`[i] ${t.disabledMsg||"This action is not yet available."}`,6e3);return}let r=this.app.vault.adapter.basePath;new K.Notice(`PaperForge: running ${t.cmd}...`);let{path:n,extraArgs:a=[]}=L(r,this.settings,void 0,void 0),s=Array.isArray(t.args)?[...t.args]:[];(0,ie.execFile)(n,[...a,"-m","paperforge",t.cmd,...s],{cwd:r,timeout:3e5},(l,i,c)=>{if(l){new K.Notice(`[!!] ${t.cmd} failed: ${(c||l.message).slice(0,120)}`,8e3);return}new K.Notice(`[OK] ${t.okMsg||i.trim().split(` -`)[0].slice(0,80)}`)})}});this.settings.auto_update_on_startup===!0&&this.settings.setup_complete&&setTimeout(()=>this._autoUpdate(),3e3),this._startFilePolling(),this._firstLaunchSnapshotMigration(),this._checkReleaseNotes()}_firstLaunchSnapshotMigration(){let e=this.app.vault.adapter.basePath;if(!e)return;let r=Q(e).memoryStatePath;if(!H.existsSync(r)){let n=L(e,this.settings,void 0,void 0);[["runtime-health","--json"],["memory","status","--json"],["embed","status","--json"]].forEach(s=>{let l=[...n.extraArgs,"-m","paperforge","--vault",e,...s];(0,ie.execFile)(n.path,l,{cwd:e,timeout:6e4,windowsHide:!0},()=>{})})}}_autoUpdate(){let e=this.app.vault.adapter.basePath,{path:t,extraArgs:r=[]}=L(e,this.settings,void 0,void 0),n=this.manifest.version,a=`paperforge==${n}`,s=`git+https://github.com/LLLin000/PaperForge.git@${n}`,l=(i,c)=>{(0,ie.spawn)(t,[...r,"-m","pip","install","--upgrade",i],{cwd:e,timeout:12e4,env:me()}).on("close",g=>c(g===0))};(0,ie.execFile)(t,[...r,"-c","import paperforge; print(paperforge.__version__)"],{cwd:e,timeout:1e4},(i,c)=>{let d=p=>{console.log(`[PaperForge] Auto-update: trying PyPI (paperforge==${n})`),l(a,f=>{if(f){console.log("[PaperForge] Auto-update: installed via PyPI"),new K.Notice(`[OK] PaperForge CLI ${p}`,5e3);return}console.warn("[PaperForge] Auto-update: PyPI failed, falling back to git..."),l(s,y=>{y&&(console.log("[PaperForge] Auto-update: installed via git"),new K.Notice(`[OK] PaperForge CLI ${p} (via git)`,5e3))})})};if(i){d("installed");return}let g=c.trim();g!==n&&d(`${g} -> ${n}`)})}_startFilePolling(){let e=this.app.vault.adapter.basePath;this._pollTimer=setInterval(()=>{this._checkExports(e),this._checkOcr(e)},12e4)}_checkExports(e){if(this._autoSyncRunning)return;let t=Q(e).exportsDir;if(!H.existsSync(t))return;let r=0;try{H.readdirSync(t).forEach(n=>{if(!n.endsWith(".json"))return;let a=H.statSync(ke.join(t,n));a.mtimeMs>r&&(r=a.mtimeMs)})}catch(n){return}r>this._lastExportMtime&&(this._lastExportMtime=r,this._autoSync(e))}_autoSync(e){if(this._autoSyncRunning)return;this._autoSyncRunning=!0;let t=L(e,this.settings,void 0,void 0);if(!t.path){this._autoSyncRunning=!1;return}let r=`"${t.path}" -m paperforge --vault "${e}" sync`;(0,ie.exec)(r,{timeout:12e4,encoding:"utf-8"},(n,a,s)=>{this._autoSyncRunning=!1,this._memoryStatusText=null,n||(this._lastSyncTime=new Date().toLocaleTimeString());try{let l=Q(e).exportsDir,i=0;H.readdirSync(l).forEach(c=>{c.endsWith(".json")&&(i=Math.max(i,H.statSync(ke.join(l,c)).mtimeMs))}),this._lastExportMtime=i}catch(l){}})}_checkOcr(e){if(this._autoSyncRunning)return;let t=Q(e).ocrDir;if(H.existsSync(t))try{H.readdirSync(t,{withFileTypes:!0}).forEach(r=>{if(!r.isDirectory())return;let n=ke.join(t,r.name,"meta.json");if(!H.existsSync(n))return;let a=H.statSync(n),s=this._lastOcrMtimes[r.name]||0;if(a.mtimeMs<=s||(this._lastOcrMtimes[r.name]=a.mtimeMs,this._autoSyncRunning))return;this._autoSyncRunning=!0;let l=L(e,this.settings,void 0,void 0);if(!l.path){this._autoSyncRunning=!1;return}let i=`"${l.path}" -m paperforge --vault "${e}" sync`;(0,ie.exec)(i,{timeout:3e4,encoding:"utf-8"},()=>{this._autoSyncRunning=!1,this._memoryStatusText=null})})}catch(r){}}readPaperforgeJson(){let e=this.app.vault.adapter.basePath,t=ke.join(e,"paperforge.json"),r={system_dir:"System",resources_dir:"Resources",literature_dir:"Literature",base_dir:"Bases"};try{if(!H.existsSync(t))return r;let n=H.readFileSync(t,"utf-8"),a=JSON.parse(n),s=a.vault_config||{};return{system_dir:s.system_dir||a.system_dir||r.system_dir,resources_dir:s.resources_dir||a.resources_dir||r.resources_dir,literature_dir:s.literature_dir||a.literature_dir||r.literature_dir,base_dir:s.base_dir||a.base_dir||r.base_dir}}catch(n){return console.warn("PaperForge: Failed to read paperforge.json, using defaults",n),r}}savePaperforgeJson(e){let t=this.app.vault.adapter.basePath,r=ke.join(t,"paperforge.json"),n={};try{H.existsSync(r)&&(n=JSON.parse(H.readFileSync(r,"utf-8")))}catch(s){console.warn("PaperForge: Failed to read paperforge.json for update",s)}(!n.vault_config||typeof n.vault_config!="object")&&(n.vault_config={});let a=["system_dir","resources_dir","literature_dir","base_dir"];for(let s of a)e[s]!==void 0&&(n.vault_config[s]=e[s]);n.schema_version||(n.schema_version="2");for(let s of a)delete n[s];try{if(H.writeFileSync(r,JSON.stringify(n,null,2),"utf-8"),this.settings){let s=this.readPaperforgeJson();this.settings.system_dir=s.system_dir,this.settings.resources_dir=s.resources_dir,this.settings.literature_dir=s.literature_dir,this.settings.base_dir=s.base_dir}}catch(s){console.error("PaperForge: Failed to write paperforge.json",s),new K.Notice("PaperForge: Failed to save configuration to paperforge.json")}}onunload(){this._pollTimer&&clearInterval(this._pollTimer),this.app.workspace.detachLeavesOfType(_e)}async loadSettings(){this.settings=Object.assign({},Fe,await this.loadData()),this.settings.features&&Fe.features&&(this.settings.features=Object.assign({},Fe.features,this.settings.features||{})),this.settings.frozen_skills||(this.settings.frozen_skills={});let e=this.readPaperforgeJson();if(this.settings.system_dir=e.system_dir,this.settings.resources_dir=e.resources_dir,this.settings.literature_dir=e.literature_dir,this.settings.base_dir=e.base_dir,this.settings.python_path&&this.settings.python_path.trim()){let t=this.settings.python_path.trim();H.existsSync(t)?this.settings._python_path_stale=!1:(console.warn(`PaperForge: Saved python_path "${t}" no longer exists - showing stale warning`),this.settings._python_path_stale=!0)}}async saveSettings(){let e={};for(let t of Object.keys(Fe))t in this.settings&&(e[t]=this.settings[t]);await this.saveData(e)}_checkReleaseNotes(){let e=this.manifest.version;if(this.settings.last_seen_version===e)return;let a=(qe().versions||[]).find(l=>l.version===e);class s extends K.Modal{constructor(i,c){super(i),this._entry=c}onOpen(){let{contentEl:i}=this;if(i.createEl("h2",{text:`PaperForge v${e} \u66F4\u65B0\u8BF4\u660E`}),this._entry){if(i.createEl("p",{text:this._entry.title,cls:"paperforge-modal-subtitle"}),this._entry.breaking_or_migration&&this._entry.breaking_or_migration.length>0){i.createEl("h4",{text:"\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F"});for(let c of this._entry.breaking_or_migration)i.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.new_features&&this._entry.new_features.length>0){i.createEl("h4",{text:"\u65B0\u529F\u80FD"});for(let c of this._entry.new_features)i.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.fixes&&this._entry.fixes.length>0){i.createEl("h4",{text:"\u4FEE\u590D"});for(let c of this._entry.fixes)i.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.recommended_actions&&this._entry.recommended_actions.length>0){let c=i.createEl("div",{cls:"paperforge-release-recommended"});c.createEl("h4",{text:"\u5EFA\u8BAE\u64CD\u4F5C",cls:""}),c.style.marginBottom="8px";for(let d of this._entry.recommended_actions)c.createEl("p",{text:`\u2022 ${d}`,cls:"paperforge-release-item-bold"})}}else i.createEl("p",{text:"\u7248\u672C\u5DF2\u66F4\u65B0\u81F3 v"+e+"\uFF0C\u8BF7\u524D\u5F80\u8BBE\u7F6E \u2192 \u66F4\u65B0\u4E0E\u624B\u518C \u67E5\u770B\u5B8C\u6574\u66F4\u65B0\u8BB0\u5F55\u3002"});new K.Setting(i).addButton(c=>c.setButtonText("\u77E5\u9053\u4E86").setCta().onClick(()=>{this.close()}))}onClose(){let{contentEl:i}=this;i.empty()}}new s(this.app,a).open(),this.settings.last_seen_version=e,this.saveSettings()}}; +`)[0].trim();return!s||s.startsWith("###")||s.startsWith("##")?null:s.length>300?s.slice(0,300)+"...":s}_renderRecentDiscussionCard(e,t){let r=e.createEl("div",{cls:"paperforge-discussion-card"});if(r.style.display="none",!t.note_path)return;let n=t.note_path.lastIndexOf("/"),s=(n!==-1?t.note_path.substring(0,n):".")+"/ai/discussion.md";this.app.vault.adapter.exists(s).then(i=>{if(i)return this.app.vault.adapter.read(s)}).then(async i=>{if(!i)return;let l=this._parseDiscussionMD(i);if(!l||l.length===0)return;r.style.display="block",r.createEl("div",{cls:"paperforge-discussion-header"}).createEl("span",{cls:"paperforge-discussion-title",text:"\u6700\u8FD1\u8BA8\u8BBA"});for(let f of l){let p=r.createEl("div",{cls:"paperforge-discussion-item"}),m=p.createEl("div",{cls:"paperforge-discussion-q"});m.createEl("span",{cls:"paperforge-discussion-q-label",text:"\u63D0\u95EE\uFF1A"}),m.createEl("span",{cls:"paperforge-discussion-q-text",text:f.question});let y=p.createEl("div",{cls:"paperforge-discussion-a"}),x=!1;if(f.answer&&f.answer.length>500&&(x=!0,y.classList.add("paperforge-discussion-a-collapsed")),await I.MarkdownRenderer.render(this.app,f.answer||"",y,s,this),x){let _=!1;p.style.cursor="pointer",p.addEventListener("click",()=>{_=!_,y.classList.toggle("paperforge-discussion-a-collapsed",!_),y.classList.toggle("paperforge-discussion-a-expanded",_)})}}r.createEl("a",{cls:"paperforge-discussion-viewall",text:"\u67E5\u770B\u5168\u90E8\u8BA8\u8BBA \u2192"}).addEventListener("click",f=>{f.preventDefault(),this.app.vault.getAbstractFileByPath(s)?this.app.workspace.openLinkText(s,""):new I.Notice("\u8BA8\u8BBA\u6587\u4EF6\u5C1A\u672A\u751F\u6210")})}).catch(i=>{console.error("PaperForge: discussion.md read error",s,i.message)})}_parseDiscussionMD(e){let t=e.split(/\n## /).slice(1);if(t.length===0)return null;let r=t[t.length-1],n=[],a=r.split(/\*\*\u95EE\u9898:\*\*/).slice(1);for(let s of a){let i=s.match(/\*\*\u89E3\u7B54:\*\*/);if(!i)continue;let l=s.substring(0,i.index).trim(),c=s.substring(i.index+3+4).trim();n.push({question:l,answer:c})}return n.slice(-3)}_renderPaperTechnicalDetails(e,t){let r=this._currentPaperKey,n=e.createEl("div",{cls:"paperforge-technical-details"}),a=n.createEl("button",{cls:"paperforge-technical-details-toggle"}),s=n.createEl("div",{cls:"paperforge-technical-details-body"});s.style.display="none",this._techDetailsExpanded?(s.style.display="block",a.setText("\u6280\u672F\u8BE6\u60C5 \u25BE")):a.setText("\u6280\u672F\u8BE6\u60C5 \u25B8"),a.addEventListener("click",()=>{let p=s.style.display!=="none";s.style.display=p?"none":"block",a.setText(p?"\u6280\u672F\u8BE6\u60C5 \u25B8":"\u6280\u672F\u8BE6\u60C5 \u25BE"),this._techDetailsExpanded=!p});let i=s.createEl("div",{cls:"paperforge-workflow-toggles"}),l=[{key:"do_ocr",label:"OCR",hint:"\u52A0\u5165 OCR"},{key:"analyze",label:"\u7CBE\u8BFB",hint:"\u6807\u8BB0\u7CBE\u8BFB"}];for(let p of l){let m=i.createEl("label",{cls:"paperforge-workflow-toggle"}),y=m.createEl("input",{type:"checkbox",cls:"paperforge-workflow-checkbox"});y.checked=t[p.key]===!0,m.createEl("span",{cls:"paperforge-workflow-toggle-label",text:p.label}),m.createEl("span",{cls:"paperforge-workflow-toggle-hint",text:p.hint}),y.addEventListener("change",async()=>{let x=t.note_path?this.app.vault.getAbstractFileByPath(t.note_path):null;if(!x){new I.Notice("[!!] Note file not found",6e3);return}let _=y.checked;await this.app.fileManager.processFrontMatter(x,b=>{b[p.key]=_}),this._patchCachedEntry(r,{[p.key]:_}),this._currentPaperEntry=Ze(this._currentPaperEntry,{[p.key]:_})})}let c=t.health||{},d=[["PDF Health",c.pdf_health||"\u2014"],["OCR Status",t.ocr_status||"\u2014"],["Asset Health",c.asset_health||"\u2014"],["Note Path",t.note_path||"\u2014"],["Fulltext Path",t.fulltext_path||"\u2014"]],f=new Set(["Note Path","Fulltext Path","Key"]);for(let[p,m]of d){let y=s.createEl("div",{cls:"paperforge-technical-row"});y.createEl("span",{cls:"paperforge-technical-label",text:p});let x=y.createEl("span",{cls:"paperforge-technical-value",text:String(m)});f.has(p)&&m&&m!=="\u2014"&&(x.addClass("pf-copy"),x.addEventListener("click",()=>{navigator.clipboard.writeText(m),new I.Notice(p+" copied")}))}}_renderNextStepCard(e,t,r){var l,c;let n=t.next_step||"ready",a={sync:{label:"Sync Needed",text:"This paper needs to be synced from Zotero. Click to run sync.",cmd:"sync",icon:"\u21BB"},ocr:{label:"OCR Needed",text:"Fulltext is missing but PDF is present. Click to run OCR.",cmd:"ocr",icon:"\u229E"},repair:{label:"Repair Needed",text:"State divergence or path errors detected. Click to repair.",cmd:"repair",icon:"\u21BA"},"rebuild index":{label:"Rebuild Needed",text:"Index may be stale. Click to run sync to rebuild.",cmd:"sync",icon:"\u21BB"},"/pf-deep":{label:"Ready for Deep Reading",text:"Fulltext is ready. Copy /pf-deep command and run in your agent.",cmd:null,icon:"\u{1F50D}"},ready:{label:"All Set",text:"This paper is fully processed and ready for use.",cmd:"ready",icon:"\u2713"}},s=a[n]||a.ready,i=e.createEl("div",{cls:"paperforge-next-step-card"});if(n==="ready"&&i.addClass("ready"),i.createEl("div",{cls:"paperforge-next-step-label",text:"Recommended Next Step"}),i.createEl("div",{cls:"paperforge-next-step-text",text:s.text}),s.cmd&&s.cmd!=="ready"){let d=i.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:s.icon+" "+s.label}),d.addEventListener("click",()=>{let f=se.find(p=>p.cmd===s.cmd);f&&this._runAction(f,d)})}else if(n==="/pf-deep"){let d=i.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:"\u{1F4CB} "+o("copy_pf_deep_cmd")}),d.addEventListener("click",()=>{let x="/pf-deep "+r;navigator.clipboard.writeText(x).then(()=>{d.setText("\u2713 "+o("copied")),new I.Notice(x+" copied")}).catch(()=>{new I.Notice("[!!] Clipboard write failed",6e3)})});let f=((c=(l=this.app.plugins.plugins.paperforge)==null?void 0:l.settings)==null?void 0:c.agent_platform)||"opencode",m={opencode:"OpenCode",claude:"Claude Code",cursor:"Cursor",github_copilot:"GitHub Copilot",windsurf:"Windsurf",codex:"Codex",gemini:"Gemini CLI",cline:"Cline"}[f]||f;i.createEl("div",{cls:"paperforge-agent-platform-label"}).setText(o("run_in_agent").replace("{0}",m))}else n==="ready"&&i.createEl("button",{cls:"paperforge-next-step-trigger"}).createEl("span",{text:"\u2713 "+s.label})}_openFulltext(e){if(!e){new I.Notice("[!!] No fulltext path available for this paper",6e3);return}let t=this.app.vault.getAbstractFileByPath(e);t?this.app.workspace.openLinkText(t.path,""):new I.Notice("[!!] Fulltext file not found: "+e,6e3)}_renderCollectionMode(){let e=this._currentDomain||"Unknown",t=this._filterByDomain(e);if(t.length===0){this._renderGlobalMode();return}if(!this._contentEl)return;let r=this._contentEl.createEl("div",{cls:"paperforge-collection-view"}),n=t.length,a=0,s=0,i=0,l=0,c=0,d=0,f=0;for(let g of t){g.has_pdf&&a++,g.ocr_status==="done"&&s++,g.ocr_status==="done"&&g.analyze===!0&&i++,g.deep_reading_status==="done"&&l++;let v=g.ocr_status||"";v==="pending"||v==="queued"?c++:v==="processing"?d++:(v==="failed"||v==="blocked"||v==="done_incomplete"||v==="nopdf")&&f++}r.createEl("div",{cls:"paperforge-collection-header"}).createEl("div",{cls:"paperforge-collection-title",text:e});let m=r.createEl("div",{cls:"paperforge-workflow-overview"});m.createEl("div",{cls:"paperforge-section-label",text:"Workflow Overview"});let y=m.createEl("div",{cls:"paperforge-workflow-funnel"}),x=[{value:n,label:"Total"},{value:a,label:"PDF Ready"},{value:s,label:"OCR Done"},{value:l,label:"Deep Read"}];for(let g=0;g0){let g=r.createEl("div",{cls:"paperforge-ocr-section"}),v=g.createEl("div",{cls:"paperforge-collection-ocr-header"});v.createEl("h4",{cls:"paperforge-ocr-title",text:"OCR Pipeline"});let w=v.createEl("span",{cls:"paperforge-ocr-badge idle"});d>0?(w.addClass("active"),w.setText("Processing")):c>0?w.setText("Pending"):(w.addClass("idle"),w.setText("Idle"));let T=g.createEl("div",{cls:"paperforge-progress-track"});d>0&&T.addClass("paperforge-processing");let P=c+d+s+f,L=[{cls:"pending",count:c},{cls:"active",count:d},{cls:"done",count:s},{cls:"failed",count:f}];for(let q of L)if(q.count>0){let D=(q.count/P*100).toFixed(1);T.createEl("div",{cls:`paperforge-progress-seg ${q.cls}`,attr:{style:`width:${D}%`}})}let O=g.createEl("div",{cls:"paperforge-ocr-counts"}),z=[{cls:"pending",value:c,label:"Pending"},{cls:"active",value:d,label:"Processing"},{cls:"done",value:s,label:"Done"},{cls:"failed",value:f,label:"Attention"}];for(let q of z){let D=O.createEl("div",{cls:"paperforge-ocr-count"});D.createEl("div",{cls:"paperforge-ocr-count-value",text:q.value.toString()}),D.createEl("div",{cls:"paperforge-ocr-count-label",text:q.label})}}let _=r.createEl("div",{cls:"paperforge-collection-actions"}),b=_.createEl("button",{cls:"paperforge-contextual-btn primary"});b.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),b.createEl("span",{text:"Run OCR"}),b.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-ocr");g&&this._runAction(g,b)});let E=_.createEl("button",{cls:"paperforge-contextual-btn"});E.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),E.createEl("span",{text:"Sync Library"}),E.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-sync");g&&this._runAction(g,E)});let k=_.createEl("button",{cls:"paperforge-contextual-btn warn"});k.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),k.createEl("span",{text:"Redo OCR"}),k.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-ocr-redo");g&&this._runAction(g,k)}),this.renderSearchSection(r)}_refreshCurrentMode(){if(!(!this._currentMode||!this._contentEl)){this._contentEl.empty(),this._contentEl.addClass("switching"),this._invalidateIndex(),this._currentPaperEntry=this._currentPaperKey?this._findEntry(this._currentPaperKey):null,this._renderModeHeader(this._currentMode);try{switch(this._currentMode){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}finally{setTimeout(()=>{this._contentEl&&this._contentEl.removeClass("switching")},50)}}}_switchToVersionMode(e){let r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){new I.Notice("Cannot determine vault path");return}this._versionPapers=nt(n),this._versionFilter="",this._currentMode="versions",this._currentFilePath=null,this._techDetailsExpanded=!1,this._contentEl&&(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader("versions"),this._renderVersionMode())}_renderVersionMode(){if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-version-panel"}),r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){e.createEl("div",{cls:"paperforge-status-error",text:"Could not determine vault path"});return}(!this._versionPapers||this._versionPapers.length===0)&&(this._versionPapers=nt(n));let a=e.createEl("div",{cls:"paperforge-version-left"}),s=e.createEl("div",{cls:"paperforge-version-right"}),i=a.createEl("input",{cls:"paperforge-version-filter",attr:{type:"text",placeholder:o("version_filter_placeholder")}});i.value=this._versionFilter;let l=a.createEl("div",{cls:"paperforge-version-paper-list"}),c=()=>{l.empty();let b=this._versionFilter.toLowerCase(),E=this._versionPapers?this._versionPapers.filter(g=>!b||g.key.toLowerCase().includes(b)||g.title.toLowerCase().includes(b)):[];if(E.length===0){l.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let k=l.createEl("div",{cls:"paperforge-meta",text:o("version_papers_count").replace("{n}",String(E.length))});for(let g of E){let v=l.createEl("div",{cls:"paperforge-version-paper-item"}),w=v.createEl("span",{cls:"paperforge-version-paper-title",text:g.title}),T=v.createEl("span",{cls:"paperforge-version-paper-versions",text:g.versions.map(P=>P.label).join(" ")});v.addEventListener("click",()=>{l.querySelectorAll(".paperforge-version-paper-item.selected").forEach(P=>P.removeClass("selected")),v.addClass("selected"),f(g)})}};i.addEventListener("input",()=>{this._versionFilter=i.value,c()});let d=s.createEl("div",{cls:"paperforge-version-timeline-area"}),f=b=>{if(d.empty(),d.createEl("div",{cls:"paperforge-version-timeline-header"}).createEl("span",{cls:"pf-title",text:b.title}),b.versions.length===0){d.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let k=d.createEl("div",{cls:"paperforge-version-timeline"});for(let g of b.versions){let v=g.label===b.currentLabel,w=k.createEl("div",{cls:"paperforge-version-entry"+(v?" paperforge-version-current":"")}),T=w.createEl("div",{cls:"paperforge-version-dot"}),P=w.createEl("div",{cls:"paperforge-version-content"}),L=P.createEl("div",{cls:"paperforge-version-label-row"});L.createEl("span",{cls:"paperforge-version-label",text:g.label}),v&&L.createEl("span",{cls:"paperforge-version-current-tag",text:o("version_current")});let O=g.created_at?g.created_at.slice(0,10):"";P.createEl("div",{cls:"paperforge-meta",text:O+" \u2014 "+g.source});let z=g.fulltext_size?g.fulltext_size>1024?(g.fulltext_size/1024).toFixed(0)+"KB":g.fulltext_size+"B":"";z&&P.createEl("div",{cls:"paperforge-meta",text:z});let q=P.createEl("div",{cls:"paperforge-version-actions"});q.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_btn")}).addEventListener("click",()=>{Rt(n,b.key,g.label)?new I.Notice(o("version_restore_done").replace("{label}",g.label)):new I.Notice("Restore failed",6e3)}),b.versions.length>1&&!v&&q.createEl("button",{cls:"pf-btn-secondary",text:o("version_compare_btn")}).addEventListener("click",()=>{m(b,g.label,b.currentLabel)})}},p=s.createEl("div",{cls:"paperforge-version-compare"});p.style.display="none";let m=(b,E,k)=>{let g=Tt(n,b.key,E,k);p.style.display="block",p.empty();let v=p.createEl("div",{cls:"paperforge-version-compare-header"});if(v.createEl("span",{cls:"pf-title",text:o("version_compare_title").replace("{vA}",E).replace("{vB}",k)}),v.createEl("span",{cls:"paperforge-meta",text:o("version_compare_paragraphs").replace("{n}",String(g.length))}),g.length===0){p.createEl("div",{cls:"paperforge-meta",text:"No changes"});return}let w=p.createEl("div",{cls:"paperforge-version-diff-list"});for(let T of g){let P=w.createEl("div",{cls:"paperforge-version-diff-row"}),L=T.type==="added"?"[+]":T.type==="removed"?"[-]":"[~]",O=T.heading||"paragraph "+(T.paragraphIndex+1);P.createEl("span",{cls:"paperforge-version-diff-label",text:L+" "+O}),T.oldText&&P.createEl("pre",{cls:"paperforge-version-diff-old",text:T.oldText.slice(0,200)}),T.newText&&P.createEl("pre",{cls:"paperforge-version-diff-new",text:T.newText.slice(0,200)})}},y=e.createEl("div",{cls:"paperforge-version-actions-bar"}),x=y.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_selected")}),_=y.createEl("button",{cls:"pf-btn-secondary",text:o("version_clear_old").replace("{size}","")});c()}renderSearchSection(e){this._searchContainer=e.createEl("div",{cls:"paperforge-search-section"}),this._searchContainer.createEl("div",{cls:"paperforge-search-header"}).createEl("span",{cls:"pf-label",text:"Search"});let r=this._searchContainer.createEl("div",{cls:"paperforge-search-input-row"}),n=r.createEl("span",{cls:"paperforge-search-mode",text:"M"});this._searchInput=r.createEl("input",{cls:"paperforge-search-input",attr:{type:"text",placeholder:"Search papers... (@ for deep search)"}}),this._searchResultsEl=this._searchContainer.createEl("div",{cls:"paperforge-search-results"}),this._searchInput.placeholder=o("retrieval_search_placeholder"),this._searchInput.addEventListener("input",()=>{var s;let a=((s=this._searchInput)==null?void 0:s.value)||"";if(a.startsWith("@")&&!a.startsWith("@ ")?(this._searchMode="@",n.setText("@"),n.addClass("deep"),this._searchInput&&(this._searchInput.placeholder=o("retrieval_search_placeholder_deep"))):(this._searchMode="M",n.setText("M"),n.removeClass("deep"),this._searchInput&&(this._searchInput.placeholder=o("retrieval_search_placeholder"))),clearTimeout(this._searchTimer),!a.trim()){this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();return}a.startsWith("@")||(this._searchTimer=setTimeout(()=>{this.executeSearch()},200))}),this._searchInput.addEventListener("keydown",a=>{var s,i;if(a.key==="Escape"){a.preventDefault(),this._searchInput&&(this._searchInput.value="",this._searchInput.blur()),this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();return}if(a.key==="ArrowDown"||a.key==="ArrowUp"){if(this._searchState!=="results"||!((s=this._searchResults)!=null&&s.length))return;a.preventDefault();let l=this._searchResults.length;a.key==="ArrowDown"?this._searchActiveIndex=Math.min(this._searchActiveIndex+1,l-1):this._searchActiveIndex=Math.max(this._searchActiveIndex-1,-1);let c=(i=this._searchResultsEl)==null?void 0:i.querySelectorAll(".paperforge-search-result-card");c&&c.forEach((d,f)=>{f===this._searchActiveIndex?(d.setAttribute("aria-selected","true"),d.classList.add("active")):(d.setAttribute("aria-selected","false"),d.classList.remove("active"))});return}if(a.key==="Enter"&&a.ctrlKey){a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0);let l=this._searchMode;this._searchMode="@",this.executeSearch(),this._searchMode=l;return}a.key==="Enter"&&(a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0),this.executeSearch())})}_renderSearchState(){if(!this._searchResultsEl)return;switch(this._searchResultsEl.empty(),this._searchResultsEl.removeAttribute("role"),this._searchResultsEl.removeAttribute("aria-live"),this._searchInput&&(this._searchInput.disabled=!1),this._searchState){case"idle":break;case"searching":{let t=this._searchMode==="@";this._searchResultsEl.createEl("div",{cls:"paperforge-search-loading",text:t?o("retrieval_searching_deep"):o("retrieval_searching_metadata")}),this._searchResultsEl.setAttr("aria-live","polite"),t&&this._searchInput&&(this._searchInput.disabled=!0);break}case"results":{this._searchResultsEl.setAttr("role","listbox"),this._searchResultsEl.setAttr("aria-live","polite"),this._searchResults&&this._renderSearchResultsList(this._searchResults,this._searchMode==="@"),setTimeout(()=>{var r;let t=(r=this._searchResultsEl)==null?void 0:r.querySelector(".paperforge-search-result-card");t&&t instanceof HTMLElement&&t.focus()},100);break}case"empty":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty"});t.setAttr("role","alert"),t.createEl("div",{text:o("retrieval_empty")}),t.createEl("div",{cls:"paperforge-search-empty-tips",text:o("retrieval_empty_tips")});break}case"vectors-not-built":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_vectors_not_built")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_vectors_not_built_desc")});let r=t.createEl("button",{cls:"pf-btn-link",text:o("retrieval_open_vector_settings")});r.addEventListener("click",()=>{let n=this.app.setting;if(n&&typeof n=="object"){let a=n.openTab;typeof a=="function"&&a.call(n,"paperforge")}}),setTimeout(()=>{r.focus()},100);break}case"backend-unavailable":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("error-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_backend_unavailable")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_backend_unavailable_desc")});let r=t.createEl("div",{cls:"paperforge-search-state-actions"}),n=r.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_run_doctor")});n.addEventListener("click",()=>{let s=this.app.vault.adapter.basePath;if(typeof s=="string"){let{path:i,extraArgs:l=[]}=N(s,null,void 0,void 0);(0,_e.spawn)(i,[...l,"-m","paperforge","doctor"],{cwd:s,stdio:"inherit"})}}),r.createEl("button",{cls:"pf-btn-secondary",text:o("retrieval_retry")}).addEventListener("click",()=>{this.executeSearch()}),setTimeout(()=>{n.focus()},100);break}case"timeout":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_timeout_title")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_timeout_desc")});let r=t.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_retry")});r.addEventListener("click",()=>{this.executeSearch()}),setTimeout(()=>{r.focus()},100);break}case"model-changed":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_model_changed")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_model_changed_desc")});let r=t.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_rebuild_vectors")});r.addEventListener("click",()=>{let n=this.app.setting;if(n&&typeof n=="object"){let a=n.openTab;typeof a=="function"&&a.call(n,"paperforge")}}),setTimeout(()=>{r.focus()},100);break}default:{this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",text:o("retrieval_internal_error"),attr:{role:"alert"}}).addClass("error-soft"),setTimeout(()=>{this._searchInput&&this._searchInput.focus()},100);break}}}async executeSearch(){if(!this._searchInput||!this._searchResultsEl)return;let e=this._searchInput.value.trim();if(!e)return;let t=this._searchMode==="@"||e.startsWith("@"),r=t?e.replace(/^@\s*/,"").trim():e;if(!r)return;let n=t?"retrieve":"search";this._searchState="searching",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();let a=this.app.vault.adapter,s="";if(a&&typeof a=="object"&&"basePath"in a){let x=a.basePath;s=typeof x=="string"?x:""}if(!s){this._searchState="backend-unavailable",this._renderSearchState();return}let i=null,c=this.app.plugins;if(c&&typeof c=="object"&&"plugins"in c){let x=c.plugins;if(x&&typeof x=="object"&&"paperforge"in x){let _=x.paperforge;_&&typeof _=="object"&&"settings"in _&&(i=_.settings)}}let{path:d,extraArgs:f=[]}=N(s,i,void 0,void 0),p=n==="retrieve"?["--deep"]:[],m=(0,_e.spawn)(d,[...f,"-m","paperforge",n,r,...p,"--json"],{cwd:s,timeout:3e4}),y=[];m.stdout.on("data",x=>{y.push(x.toString("utf-8"))}),m.stderr.on("data",()=>{}),m.on("close",x=>{if(x!==0){let g=Xe(String(x));this._searchState=this._mapErrorToSearchState(g.type),this._renderSearchState();return}let _=y.join(""),b=_.indexOf("{"),E=_.lastIndexOf("}"),k="";if(b!==-1&&E>b)k=_.slice(b,E+1);else{let g=_.indexOf("["),v=_.lastIndexOf("]");g!==-1&&v>g&&(k=_.slice(g,v+1))}if(!k){this._searchState="internal-error",this._renderSearchState();return}try{let g=JSON.parse(k),v=[];if(g&&typeof g=="object"&&"data"in g){let w=g.data;if(w&&typeof w=="object"){let T=w;"matches"in T&&Array.isArray(T.matches)&&(v=T.matches)}}this._searchResults=v,this._searchState=v.length>0?"results":"empty",this._renderSearchState()}catch(g){let v=g instanceof Error?g.message:String(g);this._searchState="internal-error",this._renderSearchState()}}),m.on("error",x=>{let _=x.code;if(typeof _=="string"){let b=Xe(_);this._searchState=this._mapErrorToSearchState(b.type)}else this._searchState="backend-unavailable";this._renderSearchState()})}_mapErrorToSearchState(e){switch(e){case"vectors_not_built":return"vectors-not-built";case"vectors_corrupted":return"vectors-not-built";case"backend_unavailable":return"backend-unavailable";case"model_changed":return"model-changed";case"timeout":return"timeout";case"no_python":case"python_missing":case"import_failed":case"version_mismatch":return"backend-unavailable";default:return"backend-unavailable"}}_renderSearchResultsList(e,t){if(!this._searchResultsEl)return;if(this._searchResultsEl.setAttr("aria-live","polite"),e.length===0){this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty",text:"No results found."});return}let r=this._searchResultsEl.createEl("div",{cls:"paperforge-search-results-header"});r.createEl("span",{text:o("retrieval_results_count").replace("{n}",String(e.length)).replace("{s}",e.length!==1?"s":"")}).setAttr("aria-live","polite"),r.createEl("span",{cls:"paperforge-search-mode",text:t?"@":"M"});for(let a=0;aE!==null&&typeof E=="object"&&"zotero_key"in E&&E.zotero_key===f);if(b&&typeof b=="object"){let E=b;y=typeof E.main_note_path=="string"&&E.main_note_path?E.main_note_path:typeof E.note_path=="string"&&E.note_path?E.note_path:null}}y?c.addEventListener("click",_=>{let b=_.ctrlKey||_.metaKey;this.app.workspace.openLinkText(y,"",b)}):c.addEventListener("click",()=>{new I.Notice("[!!] Note not found: "+(f||"unknown"),6e3)}),c.addEventListener("keydown",_=>{if(_.key==="Enter"&&y){_.preventDefault();let b=_.ctrlKey||_.metaKey;this.app.workspace.openLinkText(y,"",b)}});let x=c.createEl("div",{cls:"paperforge-search-result-meta"});if(typeof i.first_author=="string"&&i.first_author&&x.createEl("span",{cls:"paperforge-search-result-author",text:i.first_author}),typeof i.journal=="string"&&i.journal&&x.createEl("span",{cls:"paperforge-search-result-journal",text:i.journal}),i.score!==void 0){let _=i.score,b=typeof _=="number"?_.toFixed(3):String(_);x.createEl("span",{cls:"paperforge-search-result-score",text:"Score: "+b})}if(typeof i.domain=="string"&&i.domain&&c.createEl("span",{cls:"paperforge-search-result-tag",text:i.domain}),typeof i.abstract=="string"&&i.abstract){let _=i.abstract;c.createEl("div",{cls:"paperforge-search-result-abstract",text:_.length>200?_.slice(0,200)+"...":_})}if(t&&typeof i.text=="string"&&i.text){let _=i.text;c.createEl("div",{cls:"paperforge-search-result-source",text:_.length>300?_.slice(0,300)+"...":_})}}}_renderSearchError(e){this._searchResultsEl&&(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-error",text:e}))}_runAction(e,t){var p,m;if(e.disabled){new I.Notice(`[i] ${e.disabledMsg||"This action is not yet available."}`,6e3);return}if(t.classList.contains("running"))return;t.addClass("running");let r=this.app.vault.adapter.basePath;this._showMessage("Processing...","running");let n=Array.isArray(e.args)?[...e.args]:[];if(e.needsKey){let y=this.app.workspace.getActiveFile(),x=null;if(y){let _=this.app.metadataCache.getFileCache(y);if(_&&_.frontmatter&&_.frontmatter.zotero_key?x=_.frontmatter.zotero_key:x=this._extractZoteroKeyFromPath(y.path),x)n=[...n,x];else if(_&&_.frontmatter){this._showMessage("[!!] No zotero_key in active note frontmatter","error"),new I.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}else{this._showMessage("[!!] No frontmatter in active note","error"),new I.Notice("[!!] The active note has no frontmatter with a zotero_key",6e3),t.removeClass("running");return}}else{this._showMessage("[!!] No active note open","error"),new I.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}}e.needsFilter&&(n=[...n,"--all"]);let a=e.needsFilter?6e4:e.needsKey?3e4:6e5,{path:s,extraArgs:i=[]}=N(r,(m=(p=this.app.plugins.plugins.paperforge)==null?void 0:p.settings)!=null?m:null,void 0,void 0),l=(0,_e.spawn)(s,[...i,"-m","paperforge",e.cmd,...n],{cwd:r,timeout:a}),c=[],d=Date.now(),f=setInterval(()=>this._fetchStats(!0),4e3);l.stdout.on("data",y=>{let x=y.toString("utf-8").split(` +`).filter(Boolean);for(let _ of x){let b=_.trim();b&&(c.push(b),this._showMessage(c.slice(-8).join(` +`),"running"))}}),l.stderr.on("data",y=>{let x=y.toString("utf-8").split(` +`).filter(Boolean);for(let _ of x){if(_.includes("\r")||_.includes("%")||_.includes("\u2588"))continue;let b=_.trim();b&&!b.match(/^\d+%|^\|/)&&(c.push(b),this._showMessage(c.slice(-8).join(` +`),"running"))}}),l.on("close",y=>{clearInterval(f),t.removeClass("running");let x=((Date.now()-d)/1e3).toFixed(1);if(y!==0){let _=c.slice(-3).join(" | ")||"exit code "+y;(e.cmd==="repair"||e.cmd==="ocr")&&y===1?(this._showMessage("[WARN] "+_,"running"),new I.Notice("[WARN] "+e.cmd+" partial: "+_,8e3),this._fetchStats(!0)):(this._showMessage("[!!] "+_,"error"),new I.Notice("[!!] "+e.cmd+" failed: "+_,8e3))}else if(e.needsKey||e.needsFilter){let _=c.join(` +`);if(_.trim())try{JSON.parse(_),navigator.clipboard.writeText(_).then(()=>{let b=`${x}s \u2014 ${_.length} chars copied`;this._showMessage("[OK] "+e.title+": "+b,"ok"),new I.Notice("[OK] "+e.okMsg+" \u2014 "+_.length+" chars")}).catch(b=>{this._showMessage("[!!] Clipboard write failed: "+b.message,"error"),new I.Notice("[!!] Clipboard error",6e3)})}catch(b){this._showMessage("[!!] Invalid JSON from "+e.title,"error"),new I.Notice("[!!] "+e.title+" returned invalid JSON: "+b.message.slice(0,100),8e3)}else this._showMessage("[!!] No output from context command","error"),new I.Notice("[!!] Context command returned empty output",8e3);this._fetchStats(!0)}else{let b=c.filter(k=>k.match(/updated \d+/)).pop()||c[c.length-1]||"",E=`${x}s \u2014 ${b}`;this._showMessage("[OK] "+e.title+": "+E,"ok"),new I.Notice("[OK] "+e.okMsg),this._contentEl&&this._contentEl.removeClass("switching"),this._cachedStats=null;try{this._fetchStats(!1)}catch(k){console.log("[PF] fetchStats error:",k)}console.log("[PF] close cmd="+e.cmd+" id="+e.id),e.cmd==="sync"&&ze(this.app,this.app.plugins.plugins.paperforge,r)}}),l.on("error",y=>{t.removeClass("running"),this._contentEl&&this._contentEl.removeClass("switching"),this._showMessage("[!!] "+y.message,"error"),new I.Notice("[!!] Cannot start: "+y.message,8e3)})}_showMessage(e,t){this._messageEl&&(this._messageEl.setText(e),this._messageEl.className=`paperforge-message msg-${t}`)}_renderModeHeader(e){if(!this._modeContextEl)return;this._modeContextEl.empty();let t=this._modeContextEl.createEl("span",{cls:"paperforge-mode-badge"}),r="";switch(e){case"global":t.addClass("global"),t.setText("Global"),this._headerTitle&&this._headerTitle.setText("PaperForge");break;case"paper":t.addClass("paper"),t.setText("Paper"),this._headerTitle&&this._headerTitle.setText("Paper"),this._currentPaperEntry&&this._currentPaperEntry.title?r=this._currentPaperEntry.title:this._currentPaperKey?(r=this._currentPaperKey,this._modeContextEl.createEl("span",{cls:"paperforge-mode-warning",text:"Not found in index"})):r="Unknown paper";break;case"collection":t.addClass("collection"),t.setText("Collection"),this._headerTitle&&this._headerTitle.setText("Collection"),r=this._currentDomain||"Unknown Domain";break;case"versions":t.addClass("versions"),t.setText(o("version_panel_title")),this._headerTitle&&this._headerTitle.setText(o("version_panel_title"));break}r&&this._modeContextEl.createEl("span",{cls:"paperforge-mode-name",text:r})}_setupEventSubscriptions(){let e=this.app.workspace.on("active-leaf-change",()=>{this._leafChangeTimer&&clearTimeout(this._leafChangeTimer),this._leafChangeTimer=setTimeout(()=>{let r=this._resolveModeForFile(this.app.workspace.getActiveFile()),n=r.mode,a=r.filePath;this._currentMode===n&&this._currentFilePath===a||this._detectAndSwitch()},300)});this._modeSubscribers.push({event:"active-leaf-change",ref:e});let t=this.app.vault.on("modify",r=>{r&&r.path&&r.path.endsWith("formal-library.json")&&(this._invalidateIndex(),this._refreshCurrentMode())});this._modeSubscribers.push({event:"modify",ref:t})}static async open(e){let t=e.app.workspace.getLeavesOfType(ve);if(t.length>0){e.app.workspace.revealLeaf(t[0]);return}let r=e.app.workspace.getRightLeaf(!1);r&&(await r.setViewState({type:ve,active:!0}),e.app.workspace.revealLeaf(r))}};var Ke=class extends U.Plugin{constructor(){super(...arguments);this._lastExportMtime=0;this._lastOcrMtimes={};this._autoSyncRunning=!1;this._lastSyncTime=null;this._pollTimer=null;this._embedProcess=null;this._embedProgress={current:0,total:0,key:""};this._embedStderr="";this._memoryStatusText=null}async onload(){await this.loadSettings(),this.saveSettings(),lt(this.app),this.registerView(ve,t=>new we(t));try{(0,U.addIcon)(Fe,it)}catch(t){}this.addRibbonIcon(Fe,"PaperForge Dashboard",()=>we.open(this)),se.find(t=>t.id==="paperforge-ocr-redo")&&this.addRibbonIcon("reset","PaperForge: Redo OCR",()=>{let t=this.app.vault.adapter.basePath;new U.Notice("PaperForge: Redo OCR starting...");let{path:r,extraArgs:n}=N(t,this.settings,void 0,void 0);(0,pe.execFile)(r,[...n,"-m","paperforge","ocr","redo"],{cwd:t,timeout:6e5},(a,s,i)=>{if(a){new U.Notice("PaperForge: Redo OCR failed");return}new U.Notice("PaperForge: Redo OCR done")})}),this.addSettingTab(new He(this.app,this)),this.addCommand({id:"paperforge-status-panel",name:`PaperForge: ${o("guide_open")}`,callback:()=>we.open(this)});for(let t of se)this.addCommand({id:t.id,name:`PaperForge: ${t.title}`,callback:()=>{if(t.disabled){new U.Notice(`[i] ${t.disabledMsg||"This action is not yet available."}`,6e3);return}let r=this.app.vault.adapter.basePath;new U.Notice(`PaperForge: running ${t.cmd}...`);let{path:n,extraArgs:a=[]}=N(r,this.settings,void 0,void 0),s=Array.isArray(t.args)?[...t.args]:[];(0,pe.execFile)(n,[...a,"-m","paperforge",t.cmd,...s],{cwd:r,timeout:3e5},(i,l,c)=>{if(i){new U.Notice(`[!!] ${t.cmd} failed: ${(c||i.message).slice(0,120)}`,8e3);return}new U.Notice(`[OK] ${t.okMsg||l.trim().split(` +`)[0].slice(0,80)}`)})}});this.settings.auto_update_on_startup===!0&&this.settings.setup_complete&&setTimeout(()=>this._autoUpdate(),3e3),this._startFilePolling(),this._firstLaunchSnapshotMigration(),this._checkReleaseNotes()}_firstLaunchSnapshotMigration(){let e=this.app.vault.adapter.basePath;if(!e)return;let r=ne(e).memoryStatePath;if(!W.existsSync(r)){let n=N(e,this.settings,void 0,void 0);[["runtime-health","--json"],["memory","status","--json"],["embed","status","--json"]].forEach(s=>{let i=[...n.extraArgs,"-m","paperforge","--vault",e,...s];(0,pe.execFile)(n.path,i,{cwd:e,timeout:6e4,windowsHide:!0},()=>{})})}}_autoUpdate(){let e=this.app.vault.adapter.basePath,{path:t,extraArgs:r=[]}=N(e,this.settings,void 0,void 0),n=this.manifest.version,a=`paperforge==${n}`,s=`git+https://github.com/LLLin000/PaperForge.git@${n}`,i=(l,c)=>{(0,pe.spawn)(t,[...r,"-m","pip","install","--upgrade",l],{cwd:e,timeout:12e4,env:be()}).on("close",f=>c(f===0))};(0,pe.execFile)(t,[...r,"-c","import paperforge; print(paperforge.__version__)"],{cwd:e,timeout:1e4},(l,c)=>{let d=p=>{console.log(`[PaperForge] Auto-update: trying PyPI (paperforge==${n})`),i(a,m=>{if(m){console.log("[PaperForge] Auto-update: installed via PyPI"),new U.Notice(`[OK] PaperForge CLI ${p}`,5e3);return}console.warn("[PaperForge] Auto-update: PyPI failed, falling back to git..."),i(s,y=>{y&&(console.log("[PaperForge] Auto-update: installed via git"),new U.Notice(`[OK] PaperForge CLI ${p} (via git)`,5e3))})})};if(l){d("installed");return}let f=c.trim();f!==n&&d(`${f} -> ${n}`)})}_startFilePolling(){let e=this.app.vault.adapter.basePath;this._pollTimer=setInterval(()=>{this._checkExports(e),this._checkOcr(e)},12e4)}_checkExports(e){if(this._autoSyncRunning)return;let t=ne(e).exportsDir;if(!W.existsSync(t))return;let r=0;try{W.readdirSync(t).forEach(n=>{if(!n.endsWith(".json"))return;let a=W.statSync(Se.join(t,n));a.mtimeMs>r&&(r=a.mtimeMs)})}catch(n){return}r>this._lastExportMtime&&(this._lastExportMtime=r,this._autoSync(e))}_autoSync(e){if(this._autoSyncRunning)return;this._autoSyncRunning=!0;let t=N(e,this.settings,void 0,void 0);if(!t.path){this._autoSyncRunning=!1;return}let r=`"${t.path}" -m paperforge --vault "${e}" sync`;(0,pe.exec)(r,{timeout:12e4,encoding:"utf-8"},(n,a,s)=>{this._autoSyncRunning=!1,this._memoryStatusText=null,n||(this._lastSyncTime=new Date().toLocaleTimeString());try{let i=ne(e).exportsDir,l=0;W.readdirSync(i).forEach(c=>{c.endsWith(".json")&&(l=Math.max(l,W.statSync(Se.join(i,c)).mtimeMs))}),this._lastExportMtime=l}catch(i){}})}_checkOcr(e){if(this._autoSyncRunning)return;let t=ne(e).ocrDir;if(W.existsSync(t))try{W.readdirSync(t,{withFileTypes:!0}).forEach(r=>{if(!r.isDirectory())return;let n=Se.join(t,r.name,"meta.json");if(!W.existsSync(n))return;let a=W.statSync(n),s=this._lastOcrMtimes[r.name]||0;if(a.mtimeMs<=s||(this._lastOcrMtimes[r.name]=a.mtimeMs,this._autoSyncRunning))return;this._autoSyncRunning=!0;let i=N(e,this.settings,void 0,void 0);if(!i.path){this._autoSyncRunning=!1;return}let l=`"${i.path}" -m paperforge --vault "${e}" sync`;(0,pe.exec)(l,{timeout:3e4,encoding:"utf-8"},()=>{this._autoSyncRunning=!1,this._memoryStatusText=null})})}catch(r){}}readPaperforgeJson(){let e=this.app.vault.adapter.basePath,t=Se.join(e,"paperforge.json"),r={system_dir:"System",resources_dir:"Resources",literature_dir:"Literature",base_dir:"Bases"};try{if(!W.existsSync(t))return r;let n=W.readFileSync(t,"utf-8"),a=JSON.parse(n),s=a.vault_config||{};return{system_dir:s.system_dir||a.system_dir||r.system_dir,resources_dir:s.resources_dir||a.resources_dir||r.resources_dir,literature_dir:s.literature_dir||a.literature_dir||r.literature_dir,base_dir:s.base_dir||a.base_dir||r.base_dir}}catch(n){return console.warn("PaperForge: Failed to read paperforge.json, using defaults",n),r}}savePaperforgeJson(e){let t=this.app.vault.adapter.basePath,r=Se.join(t,"paperforge.json"),n={};try{W.existsSync(r)&&(n=JSON.parse(W.readFileSync(r,"utf-8")))}catch(s){console.warn("PaperForge: Failed to read paperforge.json for update",s)}(!n.vault_config||typeof n.vault_config!="object")&&(n.vault_config={});let a=["system_dir","resources_dir","literature_dir","base_dir"];for(let s of a)e[s]!==void 0&&(n.vault_config[s]=e[s]);n.schema_version||(n.schema_version="2");for(let s of a)delete n[s];try{if(W.writeFileSync(r,JSON.stringify(n,null,2),"utf-8"),this.settings){let s=this.readPaperforgeJson();this.settings.system_dir=s.system_dir,this.settings.resources_dir=s.resources_dir,this.settings.literature_dir=s.literature_dir,this.settings.base_dir=s.base_dir}}catch(s){console.error("PaperForge: Failed to write paperforge.json",s),new U.Notice("PaperForge: Failed to save configuration to paperforge.json")}}onunload(){this._pollTimer&&clearInterval(this._pollTimer),this.app.workspace.detachLeavesOfType(ve)}async loadSettings(){this.settings=Object.assign({},Re,await this.loadData()),this.settings.features&&Re.features&&(this.settings.features=Object.assign({},Re.features,this.settings.features||{})),this.settings.frozen_skills||(this.settings.frozen_skills={});let e=this.readPaperforgeJson();if(this.settings.system_dir=e.system_dir,this.settings.resources_dir=e.resources_dir,this.settings.literature_dir=e.literature_dir,this.settings.base_dir=e.base_dir,this.settings.python_path&&this.settings.python_path.trim()){let t=this.settings.python_path.trim();W.existsSync(t)?this.settings._python_path_stale=!1:(console.warn(`PaperForge: Saved python_path "${t}" no longer exists - showing stale warning`),this.settings._python_path_stale=!0)}}async saveSettings(){let e={};for(let t of Object.keys(Re))t in this.settings&&(e[t]=this.settings[t]);await this.saveData(e)}_checkReleaseNotes(){let e=this.manifest.version;if(this.settings.last_seen_version===e)return;let a=(Je().versions||[]).find(i=>i.version===e);class s extends U.Modal{constructor(l,c){super(l),this._entry=c}onOpen(){let{contentEl:l}=this;if(l.createEl("h2",{text:`PaperForge v${e} \u66F4\u65B0\u8BF4\u660E`}),this._entry){if(l.createEl("p",{text:this._entry.title,cls:"paperforge-modal-subtitle"}),this._entry.breaking_or_migration&&this._entry.breaking_or_migration.length>0){l.createEl("h4",{text:"\u884C\u4E3A\u53D8\u66F4 / \u8FC1\u79FB\u6CE8\u610F"});for(let c of this._entry.breaking_or_migration)l.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.new_features&&this._entry.new_features.length>0){l.createEl("h4",{text:"\u65B0\u529F\u80FD"});for(let c of this._entry.new_features)l.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.fixes&&this._entry.fixes.length>0){l.createEl("h4",{text:"\u4FEE\u590D"});for(let c of this._entry.fixes)l.createEl("p",{text:`\u2022 ${c}`,cls:"paperforge-modal-item"})}if(this._entry.recommended_actions&&this._entry.recommended_actions.length>0){let c=l.createEl("div",{cls:"paperforge-release-recommended"});c.createEl("h4",{text:"\u5EFA\u8BAE\u64CD\u4F5C",cls:""}),c.style.marginBottom="8px";for(let d of this._entry.recommended_actions)c.createEl("p",{text:`\u2022 ${d}`,cls:"paperforge-release-item-bold"})}}else l.createEl("p",{text:"\u7248\u672C\u5DF2\u66F4\u65B0\u81F3 v"+e+"\uFF0C\u8BF7\u524D\u5F80\u8BBE\u7F6E \u2192 \u66F4\u65B0\u4E0E\u624B\u518C \u67E5\u770B\u5B8C\u6574\u66F4\u65B0\u8BB0\u5F55\u3002"});new U.Setting(l).addButton(c=>c.setButtonText("\u77E5\u9053\u4E86").setCta().onClick(()=>{this.close()}))}onClose(){let{contentEl:l}=this;l.empty()}}new s(this.app,a).open(),this.settings.last_seen_version=e,this.saveSettings()}}; From 9f8f73ba174387d87e02d66c8ac48c181a027e09 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:13:46 +0800 Subject: [PATCH 15/21] fix: remove shadowing local imports of get_memory_db_path and get_connection --- paperforge/commands/embed.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index c1eb97d1..e77c46b3 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -263,11 +263,7 @@ def run(args: argparse.Namespace) -> int: mark_vector_build_state(vault, status="idle", current=0, pid=0) resume = False # 门二:no vec0 rows → fresh build(不是 error) - from paperforge.memory.db import ( - ensure_vec_extension, - get_connection, - get_memory_db_path, - ) + from paperforge.memory.db import ensure_vec_extension from paperforge.memory.schema import ensure_schema _db_path = get_memory_db_path(vault) @@ -404,11 +400,7 @@ def run(args: argparse.Namespace) -> int: if body_units: try: - from paperforge.memory.db import ( - ensure_vec_extension, - get_connection, - get_memory_db_path, - ) + from paperforge.memory.db import ensure_vec_extension from paperforge.memory.schema import ensure_schema db_path = get_memory_db_path(vault) @@ -433,11 +425,7 @@ def run(args: argparse.Namespace) -> int: if object_units: try: - from paperforge.memory.db import ( - ensure_vec_extension, - get_connection, - get_memory_db_path, - ) + from paperforge.memory.db import ensure_vec_extension from paperforge.memory.schema import ensure_schema db_path = get_memory_db_path(vault) @@ -487,7 +475,7 @@ def run(args: argparse.Namespace) -> int: if resume: try: - from paperforge.memory.db import ensure_vec_extension, get_connection, get_memory_db_path + from paperforge.memory.db import ensure_vec_extension from paperforge.memory.schema import ensure_schema db_path = get_memory_db_path(vault) From 3cb3fd75a4db0d40515706c848ff507a3583605a Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:15:09 +0800 Subject: [PATCH 16/21] fix: force rebuild drops tables before ensure_schema recreates them --- paperforge/commands/embed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index e77c46b3..3d4609f1 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -303,10 +303,10 @@ def run(args: argparse.Namespace) -> int: from paperforge.memory.db import ensure_vec_extension from paperforge.memory.schema import ensure_schema ensure_vec_extension(_conn) - ensure_schema(_conn) for _t in ("vec_fulltext", "vec_body", "vec_objects", "vec_fulltext_meta", "vec_body_meta", "vec_objects_meta"): _conn.execute(f'DROP TABLE IF EXISTS "{_t}"') + ensure_schema(_conn) _conn.commit() except Exception: pass From 1eb4d80f8de95b95606723afe0192681305eb01e Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:16:38 +0800 Subject: [PATCH 17/21] fix: create vec0 companion meta tables unconditionally in ensure_schema --- paperforge/memory/schema.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/paperforge/memory/schema.py b/paperforge/memory/schema.py index d619b352..ecf4d17b 100644 --- a/paperforge/memory/schema.py +++ b/paperforge/memory/schema.py @@ -306,6 +306,12 @@ def ensure_schema(conn: sqlite3.Connection) -> None: conn.execute(CREATE_READING_LOG) conn.execute(CREATE_PROJECT_LOG) + + # vec0 companion meta and build_state — created unconditionally so force-rebuild works + conn.execute(CREATE_VEC_FULLTEXT_META) + conn.execute(CREATE_VEC_BODY_META) + conn.execute(CREATE_VEC_OBJECTS_META) + conn.execute(CREATE_BUILD_STATE) # Migration: derived tables are rebuildable, drop and recreate when shape changes current_version = get_schema_version(conn) if current_version < 3: @@ -335,10 +341,6 @@ def ensure_schema(conn: sqlite3.Connection) -> None: conn.execute(CREATE_VEC_OBJECTS) except sqlite3.OperationalError: logger.warning("sqlite-vec extension not available, skipping vector virtual tables") - conn.execute(CREATE_VEC_FULLTEXT_META) - conn.execute(CREATE_VEC_BODY_META) - conn.execute(CREATE_VEC_OBJECTS_META) - conn.execute(CREATE_BUILD_STATE) if current_version < 6: logger.info( From 2dab3d11ad5cf5ca9b30a34213509631b9f54878 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:28:49 +0800 Subject: [PATCH 18/21] fix: health probe uses detect_embedding_dim instead of hardcoded 1536 --- paperforge/embedding/status.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/paperforge/embedding/status.py b/paperforge/embedding/status.py index 7ca0befe..829c62cb 100644 --- a/paperforge/embedding/status.py +++ b/paperforge/embedding/status.py @@ -6,7 +6,8 @@ from pathlib import Path from paperforge.embedding._config import get_api_model from paperforge.memory.db import ensure_vec_extension, get_connection, get_memory_db_path -from paperforge.memory.schema import VEC_EMBEDDING_DIM, ensure_schema +from paperforge.embedding.dim_detect import detect_embedding_dim +from paperforge.memory.schema import ensure_schema logger = logging.getLogger(__name__) @@ -38,7 +39,7 @@ def get_embed_status(vault: Path) -> dict: # -- vec0 k-NN health probe -- total_meta = chunk_count + body_chunk_count + object_chunk_count if total_meta > 0: - zero_vec = [0.0] * VEC_EMBEDDING_DIM + zero_vec = [0.0] * detect_embedding_dim(vault) zero_json = _json.dumps(zero_vec) for vec_table, meta_count in [ ("vec_fulltext", chunk_count), From 537e8e36ed43177ca74521ab77a0d9312128b0ee Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:31:42 +0800 Subject: [PATCH 19/21] fix: add --vault flag to search/retrieve spawn --- paperforge/plugin/src/views/dashboard.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paperforge/plugin/src/views/dashboard.ts b/paperforge/plugin/src/views/dashboard.ts index aa2d0820..b5fcde47 100644 --- a/paperforge/plugin/src/views/dashboard.ts +++ b/paperforge/plugin/src/views/dashboard.ts @@ -2788,7 +2788,7 @@ export class PaperForgeStatusView extends ItemView { const deepFlag = mode === "retrieve" ? ["--deep"] : []; const child = spawn( pythonExe, - [...pyExtra, "-m", "paperforge", mode, query, ...deepFlag, "--json"], + [...pyExtra, "-m", "paperforge", "--vault", vaultPath, mode, query, ...deepFlag, "--json"], { cwd: vaultPath, timeout: 30000 } ); From 460412d42312dd8b422a7280bb26a05e5587fe6f Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:39:25 +0800 Subject: [PATCH 20/21] fix: isVectorReady checks total_chunks instead of fulltext-only chunk_count --- paperforge/plugin/main.js | 2 +- paperforge/plugin/src/services/memory-state.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/paperforge/plugin/main.js b/paperforge/plugin/main.js index b963af93..442a9f26 100644 --- a/paperforge/plugin/main.js +++ b/paperforge/plugin/main.js @@ -45,7 +45,7 @@ Make sure paperforge is installed and in your PATH.`});return}try{let y=JSON.par `);p!==-1&&p300?s.slice(0,300)+"...":s}_renderRecentDiscussionCard(e,t){let r=e.createEl("div",{cls:"paperforge-discussion-card"});if(r.style.display="none",!t.note_path)return;let n=t.note_path.lastIndexOf("/"),s=(n!==-1?t.note_path.substring(0,n):".")+"/ai/discussion.md";this.app.vault.adapter.exists(s).then(i=>{if(i)return this.app.vault.adapter.read(s)}).then(async i=>{if(!i)return;let l=this._parseDiscussionMD(i);if(!l||l.length===0)return;r.style.display="block",r.createEl("div",{cls:"paperforge-discussion-header"}).createEl("span",{cls:"paperforge-discussion-title",text:"\u6700\u8FD1\u8BA8\u8BBA"});for(let f of l){let p=r.createEl("div",{cls:"paperforge-discussion-item"}),m=p.createEl("div",{cls:"paperforge-discussion-q"});m.createEl("span",{cls:"paperforge-discussion-q-label",text:"\u63D0\u95EE\uFF1A"}),m.createEl("span",{cls:"paperforge-discussion-q-text",text:f.question});let y=p.createEl("div",{cls:"paperforge-discussion-a"}),x=!1;if(f.answer&&f.answer.length>500&&(x=!0,y.classList.add("paperforge-discussion-a-collapsed")),await I.MarkdownRenderer.render(this.app,f.answer||"",y,s,this),x){let _=!1;p.style.cursor="pointer",p.addEventListener("click",()=>{_=!_,y.classList.toggle("paperforge-discussion-a-collapsed",!_),y.classList.toggle("paperforge-discussion-a-expanded",_)})}}r.createEl("a",{cls:"paperforge-discussion-viewall",text:"\u67E5\u770B\u5168\u90E8\u8BA8\u8BBA \u2192"}).addEventListener("click",f=>{f.preventDefault(),this.app.vault.getAbstractFileByPath(s)?this.app.workspace.openLinkText(s,""):new I.Notice("\u8BA8\u8BBA\u6587\u4EF6\u5C1A\u672A\u751F\u6210")})}).catch(i=>{console.error("PaperForge: discussion.md read error",s,i.message)})}_parseDiscussionMD(e){let t=e.split(/\n## /).slice(1);if(t.length===0)return null;let r=t[t.length-1],n=[],a=r.split(/\*\*\u95EE\u9898:\*\*/).slice(1);for(let s of a){let i=s.match(/\*\*\u89E3\u7B54:\*\*/);if(!i)continue;let l=s.substring(0,i.index).trim(),c=s.substring(i.index+3+4).trim();n.push({question:l,answer:c})}return n.slice(-3)}_renderPaperTechnicalDetails(e,t){let r=this._currentPaperKey,n=e.createEl("div",{cls:"paperforge-technical-details"}),a=n.createEl("button",{cls:"paperforge-technical-details-toggle"}),s=n.createEl("div",{cls:"paperforge-technical-details-body"});s.style.display="none",this._techDetailsExpanded?(s.style.display="block",a.setText("\u6280\u672F\u8BE6\u60C5 \u25BE")):a.setText("\u6280\u672F\u8BE6\u60C5 \u25B8"),a.addEventListener("click",()=>{let p=s.style.display!=="none";s.style.display=p?"none":"block",a.setText(p?"\u6280\u672F\u8BE6\u60C5 \u25B8":"\u6280\u672F\u8BE6\u60C5 \u25BE"),this._techDetailsExpanded=!p});let i=s.createEl("div",{cls:"paperforge-workflow-toggles"}),l=[{key:"do_ocr",label:"OCR",hint:"\u52A0\u5165 OCR"},{key:"analyze",label:"\u7CBE\u8BFB",hint:"\u6807\u8BB0\u7CBE\u8BFB"}];for(let p of l){let m=i.createEl("label",{cls:"paperforge-workflow-toggle"}),y=m.createEl("input",{type:"checkbox",cls:"paperforge-workflow-checkbox"});y.checked=t[p.key]===!0,m.createEl("span",{cls:"paperforge-workflow-toggle-label",text:p.label}),m.createEl("span",{cls:"paperforge-workflow-toggle-hint",text:p.hint}),y.addEventListener("change",async()=>{let x=t.note_path?this.app.vault.getAbstractFileByPath(t.note_path):null;if(!x){new I.Notice("[!!] Note file not found",6e3);return}let _=y.checked;await this.app.fileManager.processFrontMatter(x,b=>{b[p.key]=_}),this._patchCachedEntry(r,{[p.key]:_}),this._currentPaperEntry=Ze(this._currentPaperEntry,{[p.key]:_})})}let c=t.health||{},d=[["PDF Health",c.pdf_health||"\u2014"],["OCR Status",t.ocr_status||"\u2014"],["Asset Health",c.asset_health||"\u2014"],["Note Path",t.note_path||"\u2014"],["Fulltext Path",t.fulltext_path||"\u2014"]],f=new Set(["Note Path","Fulltext Path","Key"]);for(let[p,m]of d){let y=s.createEl("div",{cls:"paperforge-technical-row"});y.createEl("span",{cls:"paperforge-technical-label",text:p});let x=y.createEl("span",{cls:"paperforge-technical-value",text:String(m)});f.has(p)&&m&&m!=="\u2014"&&(x.addClass("pf-copy"),x.addEventListener("click",()=>{navigator.clipboard.writeText(m),new I.Notice(p+" copied")}))}}_renderNextStepCard(e,t,r){var l,c;let n=t.next_step||"ready",a={sync:{label:"Sync Needed",text:"This paper needs to be synced from Zotero. Click to run sync.",cmd:"sync",icon:"\u21BB"},ocr:{label:"OCR Needed",text:"Fulltext is missing but PDF is present. Click to run OCR.",cmd:"ocr",icon:"\u229E"},repair:{label:"Repair Needed",text:"State divergence or path errors detected. Click to repair.",cmd:"repair",icon:"\u21BA"},"rebuild index":{label:"Rebuild Needed",text:"Index may be stale. Click to run sync to rebuild.",cmd:"sync",icon:"\u21BB"},"/pf-deep":{label:"Ready for Deep Reading",text:"Fulltext is ready. Copy /pf-deep command and run in your agent.",cmd:null,icon:"\u{1F50D}"},ready:{label:"All Set",text:"This paper is fully processed and ready for use.",cmd:"ready",icon:"\u2713"}},s=a[n]||a.ready,i=e.createEl("div",{cls:"paperforge-next-step-card"});if(n==="ready"&&i.addClass("ready"),i.createEl("div",{cls:"paperforge-next-step-label",text:"Recommended Next Step"}),i.createEl("div",{cls:"paperforge-next-step-text",text:s.text}),s.cmd&&s.cmd!=="ready"){let d=i.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:s.icon+" "+s.label}),d.addEventListener("click",()=>{let f=se.find(p=>p.cmd===s.cmd);f&&this._runAction(f,d)})}else if(n==="/pf-deep"){let d=i.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:"\u{1F4CB} "+o("copy_pf_deep_cmd")}),d.addEventListener("click",()=>{let x="/pf-deep "+r;navigator.clipboard.writeText(x).then(()=>{d.setText("\u2713 "+o("copied")),new I.Notice(x+" copied")}).catch(()=>{new I.Notice("[!!] Clipboard write failed",6e3)})});let f=((c=(l=this.app.plugins.plugins.paperforge)==null?void 0:l.settings)==null?void 0:c.agent_platform)||"opencode",m={opencode:"OpenCode",claude:"Claude Code",cursor:"Cursor",github_copilot:"GitHub Copilot",windsurf:"Windsurf",codex:"Codex",gemini:"Gemini CLI",cline:"Cline"}[f]||f;i.createEl("div",{cls:"paperforge-agent-platform-label"}).setText(o("run_in_agent").replace("{0}",m))}else n==="ready"&&i.createEl("button",{cls:"paperforge-next-step-trigger"}).createEl("span",{text:"\u2713 "+s.label})}_openFulltext(e){if(!e){new I.Notice("[!!] No fulltext path available for this paper",6e3);return}let t=this.app.vault.getAbstractFileByPath(e);t?this.app.workspace.openLinkText(t.path,""):new I.Notice("[!!] Fulltext file not found: "+e,6e3)}_renderCollectionMode(){let e=this._currentDomain||"Unknown",t=this._filterByDomain(e);if(t.length===0){this._renderGlobalMode();return}if(!this._contentEl)return;let r=this._contentEl.createEl("div",{cls:"paperforge-collection-view"}),n=t.length,a=0,s=0,i=0,l=0,c=0,d=0,f=0;for(let g of t){g.has_pdf&&a++,g.ocr_status==="done"&&s++,g.ocr_status==="done"&&g.analyze===!0&&i++,g.deep_reading_status==="done"&&l++;let v=g.ocr_status||"";v==="pending"||v==="queued"?c++:v==="processing"?d++:(v==="failed"||v==="blocked"||v==="done_incomplete"||v==="nopdf")&&f++}r.createEl("div",{cls:"paperforge-collection-header"}).createEl("div",{cls:"paperforge-collection-title",text:e});let m=r.createEl("div",{cls:"paperforge-workflow-overview"});m.createEl("div",{cls:"paperforge-section-label",text:"Workflow Overview"});let y=m.createEl("div",{cls:"paperforge-workflow-funnel"}),x=[{value:n,label:"Total"},{value:a,label:"PDF Ready"},{value:s,label:"OCR Done"},{value:l,label:"Deep Read"}];for(let g=0;g0){let g=r.createEl("div",{cls:"paperforge-ocr-section"}),v=g.createEl("div",{cls:"paperforge-collection-ocr-header"});v.createEl("h4",{cls:"paperforge-ocr-title",text:"OCR Pipeline"});let w=v.createEl("span",{cls:"paperforge-ocr-badge idle"});d>0?(w.addClass("active"),w.setText("Processing")):c>0?w.setText("Pending"):(w.addClass("idle"),w.setText("Idle"));let T=g.createEl("div",{cls:"paperforge-progress-track"});d>0&&T.addClass("paperforge-processing");let P=c+d+s+f,L=[{cls:"pending",count:c},{cls:"active",count:d},{cls:"done",count:s},{cls:"failed",count:f}];for(let q of L)if(q.count>0){let D=(q.count/P*100).toFixed(1);T.createEl("div",{cls:`paperforge-progress-seg ${q.cls}`,attr:{style:`width:${D}%`}})}let O=g.createEl("div",{cls:"paperforge-ocr-counts"}),z=[{cls:"pending",value:c,label:"Pending"},{cls:"active",value:d,label:"Processing"},{cls:"done",value:s,label:"Done"},{cls:"failed",value:f,label:"Attention"}];for(let q of z){let D=O.createEl("div",{cls:"paperforge-ocr-count"});D.createEl("div",{cls:"paperforge-ocr-count-value",text:q.value.toString()}),D.createEl("div",{cls:"paperforge-ocr-count-label",text:q.label})}}let _=r.createEl("div",{cls:"paperforge-collection-actions"}),b=_.createEl("button",{cls:"paperforge-contextual-btn primary"});b.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),b.createEl("span",{text:"Run OCR"}),b.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-ocr");g&&this._runAction(g,b)});let E=_.createEl("button",{cls:"paperforge-contextual-btn"});E.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),E.createEl("span",{text:"Sync Library"}),E.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-sync");g&&this._runAction(g,E)});let k=_.createEl("button",{cls:"paperforge-contextual-btn warn"});k.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),k.createEl("span",{text:"Redo OCR"}),k.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-ocr-redo");g&&this._runAction(g,k)}),this.renderSearchSection(r)}_refreshCurrentMode(){if(!(!this._currentMode||!this._contentEl)){this._contentEl.empty(),this._contentEl.addClass("switching"),this._invalidateIndex(),this._currentPaperEntry=this._currentPaperKey?this._findEntry(this._currentPaperKey):null,this._renderModeHeader(this._currentMode);try{switch(this._currentMode){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}finally{setTimeout(()=>{this._contentEl&&this._contentEl.removeClass("switching")},50)}}}_switchToVersionMode(e){let r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){new I.Notice("Cannot determine vault path");return}this._versionPapers=nt(n),this._versionFilter="",this._currentMode="versions",this._currentFilePath=null,this._techDetailsExpanded=!1,this._contentEl&&(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader("versions"),this._renderVersionMode())}_renderVersionMode(){if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-version-panel"}),r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){e.createEl("div",{cls:"paperforge-status-error",text:"Could not determine vault path"});return}(!this._versionPapers||this._versionPapers.length===0)&&(this._versionPapers=nt(n));let a=e.createEl("div",{cls:"paperforge-version-left"}),s=e.createEl("div",{cls:"paperforge-version-right"}),i=a.createEl("input",{cls:"paperforge-version-filter",attr:{type:"text",placeholder:o("version_filter_placeholder")}});i.value=this._versionFilter;let l=a.createEl("div",{cls:"paperforge-version-paper-list"}),c=()=>{l.empty();let b=this._versionFilter.toLowerCase(),E=this._versionPapers?this._versionPapers.filter(g=>!b||g.key.toLowerCase().includes(b)||g.title.toLowerCase().includes(b)):[];if(E.length===0){l.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let k=l.createEl("div",{cls:"paperforge-meta",text:o("version_papers_count").replace("{n}",String(E.length))});for(let g of E){let v=l.createEl("div",{cls:"paperforge-version-paper-item"}),w=v.createEl("span",{cls:"paperforge-version-paper-title",text:g.title}),T=v.createEl("span",{cls:"paperforge-version-paper-versions",text:g.versions.map(P=>P.label).join(" ")});v.addEventListener("click",()=>{l.querySelectorAll(".paperforge-version-paper-item.selected").forEach(P=>P.removeClass("selected")),v.addClass("selected"),f(g)})}};i.addEventListener("input",()=>{this._versionFilter=i.value,c()});let d=s.createEl("div",{cls:"paperforge-version-timeline-area"}),f=b=>{if(d.empty(),d.createEl("div",{cls:"paperforge-version-timeline-header"}).createEl("span",{cls:"pf-title",text:b.title}),b.versions.length===0){d.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let k=d.createEl("div",{cls:"paperforge-version-timeline"});for(let g of b.versions){let v=g.label===b.currentLabel,w=k.createEl("div",{cls:"paperforge-version-entry"+(v?" paperforge-version-current":"")}),T=w.createEl("div",{cls:"paperforge-version-dot"}),P=w.createEl("div",{cls:"paperforge-version-content"}),L=P.createEl("div",{cls:"paperforge-version-label-row"});L.createEl("span",{cls:"paperforge-version-label",text:g.label}),v&&L.createEl("span",{cls:"paperforge-version-current-tag",text:o("version_current")});let O=g.created_at?g.created_at.slice(0,10):"";P.createEl("div",{cls:"paperforge-meta",text:O+" \u2014 "+g.source});let z=g.fulltext_size?g.fulltext_size>1024?(g.fulltext_size/1024).toFixed(0)+"KB":g.fulltext_size+"B":"";z&&P.createEl("div",{cls:"paperforge-meta",text:z});let q=P.createEl("div",{cls:"paperforge-version-actions"});q.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_btn")}).addEventListener("click",()=>{Rt(n,b.key,g.label)?new I.Notice(o("version_restore_done").replace("{label}",g.label)):new I.Notice("Restore failed",6e3)}),b.versions.length>1&&!v&&q.createEl("button",{cls:"pf-btn-secondary",text:o("version_compare_btn")}).addEventListener("click",()=>{m(b,g.label,b.currentLabel)})}},p=s.createEl("div",{cls:"paperforge-version-compare"});p.style.display="none";let m=(b,E,k)=>{let g=Tt(n,b.key,E,k);p.style.display="block",p.empty();let v=p.createEl("div",{cls:"paperforge-version-compare-header"});if(v.createEl("span",{cls:"pf-title",text:o("version_compare_title").replace("{vA}",E).replace("{vB}",k)}),v.createEl("span",{cls:"paperforge-meta",text:o("version_compare_paragraphs").replace("{n}",String(g.length))}),g.length===0){p.createEl("div",{cls:"paperforge-meta",text:"No changes"});return}let w=p.createEl("div",{cls:"paperforge-version-diff-list"});for(let T of g){let P=w.createEl("div",{cls:"paperforge-version-diff-row"}),L=T.type==="added"?"[+]":T.type==="removed"?"[-]":"[~]",O=T.heading||"paragraph "+(T.paragraphIndex+1);P.createEl("span",{cls:"paperforge-version-diff-label",text:L+" "+O}),T.oldText&&P.createEl("pre",{cls:"paperforge-version-diff-old",text:T.oldText.slice(0,200)}),T.newText&&P.createEl("pre",{cls:"paperforge-version-diff-new",text:T.newText.slice(0,200)})}},y=e.createEl("div",{cls:"paperforge-version-actions-bar"}),x=y.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_selected")}),_=y.createEl("button",{cls:"pf-btn-secondary",text:o("version_clear_old").replace("{size}","")});c()}renderSearchSection(e){this._searchContainer=e.createEl("div",{cls:"paperforge-search-section"}),this._searchContainer.createEl("div",{cls:"paperforge-search-header"}).createEl("span",{cls:"pf-label",text:"Search"});let r=this._searchContainer.createEl("div",{cls:"paperforge-search-input-row"}),n=r.createEl("span",{cls:"paperforge-search-mode",text:"M"});this._searchInput=r.createEl("input",{cls:"paperforge-search-input",attr:{type:"text",placeholder:"Search papers... (@ for deep search)"}}),this._searchResultsEl=this._searchContainer.createEl("div",{cls:"paperforge-search-results"}),this._searchInput.placeholder=o("retrieval_search_placeholder"),this._searchInput.addEventListener("input",()=>{var s;let a=((s=this._searchInput)==null?void 0:s.value)||"";if(a.startsWith("@")&&!a.startsWith("@ ")?(this._searchMode="@",n.setText("@"),n.addClass("deep"),this._searchInput&&(this._searchInput.placeholder=o("retrieval_search_placeholder_deep"))):(this._searchMode="M",n.setText("M"),n.removeClass("deep"),this._searchInput&&(this._searchInput.placeholder=o("retrieval_search_placeholder"))),clearTimeout(this._searchTimer),!a.trim()){this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();return}a.startsWith("@")||(this._searchTimer=setTimeout(()=>{this.executeSearch()},200))}),this._searchInput.addEventListener("keydown",a=>{var s,i;if(a.key==="Escape"){a.preventDefault(),this._searchInput&&(this._searchInput.value="",this._searchInput.blur()),this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();return}if(a.key==="ArrowDown"||a.key==="ArrowUp"){if(this._searchState!=="results"||!((s=this._searchResults)!=null&&s.length))return;a.preventDefault();let l=this._searchResults.length;a.key==="ArrowDown"?this._searchActiveIndex=Math.min(this._searchActiveIndex+1,l-1):this._searchActiveIndex=Math.max(this._searchActiveIndex-1,-1);let c=(i=this._searchResultsEl)==null?void 0:i.querySelectorAll(".paperforge-search-result-card");c&&c.forEach((d,f)=>{f===this._searchActiveIndex?(d.setAttribute("aria-selected","true"),d.classList.add("active")):(d.setAttribute("aria-selected","false"),d.classList.remove("active"))});return}if(a.key==="Enter"&&a.ctrlKey){a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0);let l=this._searchMode;this._searchMode="@",this.executeSearch(),this._searchMode=l;return}a.key==="Enter"&&(a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0),this.executeSearch())})}_renderSearchState(){if(!this._searchResultsEl)return;switch(this._searchResultsEl.empty(),this._searchResultsEl.removeAttribute("role"),this._searchResultsEl.removeAttribute("aria-live"),this._searchInput&&(this._searchInput.disabled=!1),this._searchState){case"idle":break;case"searching":{let t=this._searchMode==="@";this._searchResultsEl.createEl("div",{cls:"paperforge-search-loading",text:t?o("retrieval_searching_deep"):o("retrieval_searching_metadata")}),this._searchResultsEl.setAttr("aria-live","polite"),t&&this._searchInput&&(this._searchInput.disabled=!0);break}case"results":{this._searchResultsEl.setAttr("role","listbox"),this._searchResultsEl.setAttr("aria-live","polite"),this._searchResults&&this._renderSearchResultsList(this._searchResults,this._searchMode==="@"),setTimeout(()=>{var r;let t=(r=this._searchResultsEl)==null?void 0:r.querySelector(".paperforge-search-result-card");t&&t instanceof HTMLElement&&t.focus()},100);break}case"empty":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty"});t.setAttr("role","alert"),t.createEl("div",{text:o("retrieval_empty")}),t.createEl("div",{cls:"paperforge-search-empty-tips",text:o("retrieval_empty_tips")});break}case"vectors-not-built":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_vectors_not_built")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_vectors_not_built_desc")});let r=t.createEl("button",{cls:"pf-btn-link",text:o("retrieval_open_vector_settings")});r.addEventListener("click",()=>{let n=this.app.setting;if(n&&typeof n=="object"){let a=n.openTab;typeof a=="function"&&a.call(n,"paperforge")}}),setTimeout(()=>{r.focus()},100);break}case"backend-unavailable":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("error-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_backend_unavailable")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_backend_unavailable_desc")});let r=t.createEl("div",{cls:"paperforge-search-state-actions"}),n=r.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_run_doctor")});n.addEventListener("click",()=>{let s=this.app.vault.adapter.basePath;if(typeof s=="string"){let{path:i,extraArgs:l=[]}=N(s,null,void 0,void 0);(0,_e.spawn)(i,[...l,"-m","paperforge","doctor"],{cwd:s,stdio:"inherit"})}}),r.createEl("button",{cls:"pf-btn-secondary",text:o("retrieval_retry")}).addEventListener("click",()=>{this.executeSearch()}),setTimeout(()=>{n.focus()},100);break}case"timeout":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_timeout_title")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_timeout_desc")});let r=t.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_retry")});r.addEventListener("click",()=>{this.executeSearch()}),setTimeout(()=>{r.focus()},100);break}case"model-changed":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_model_changed")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_model_changed_desc")});let r=t.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_rebuild_vectors")});r.addEventListener("click",()=>{let n=this.app.setting;if(n&&typeof n=="object"){let a=n.openTab;typeof a=="function"&&a.call(n,"paperforge")}}),setTimeout(()=>{r.focus()},100);break}default:{this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",text:o("retrieval_internal_error"),attr:{role:"alert"}}).addClass("error-soft"),setTimeout(()=>{this._searchInput&&this._searchInput.focus()},100);break}}}async executeSearch(){if(!this._searchInput||!this._searchResultsEl)return;let e=this._searchInput.value.trim();if(!e)return;let t=this._searchMode==="@"||e.startsWith("@"),r=t?e.replace(/^@\s*/,"").trim():e;if(!r)return;let n=t?"retrieve":"search";this._searchState="searching",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();let a=this.app.vault.adapter,s="";if(a&&typeof a=="object"&&"basePath"in a){let x=a.basePath;s=typeof x=="string"?x:""}if(!s){this._searchState="backend-unavailable",this._renderSearchState();return}let i=null,c=this.app.plugins;if(c&&typeof c=="object"&&"plugins"in c){let x=c.plugins;if(x&&typeof x=="object"&&"paperforge"in x){let _=x.paperforge;_&&typeof _=="object"&&"settings"in _&&(i=_.settings)}}let{path:d,extraArgs:f=[]}=N(s,i,void 0,void 0),p=n==="retrieve"?["--deep"]:[],m=(0,_e.spawn)(d,[...f,"-m","paperforge",n,r,...p,"--json"],{cwd:s,timeout:3e4}),y=[];m.stdout.on("data",x=>{y.push(x.toString("utf-8"))}),m.stderr.on("data",()=>{}),m.on("close",x=>{if(x!==0){let g=Xe(String(x));this._searchState=this._mapErrorToSearchState(g.type),this._renderSearchState();return}let _=y.join(""),b=_.indexOf("{"),E=_.lastIndexOf("}"),k="";if(b!==-1&&E>b)k=_.slice(b,E+1);else{let g=_.indexOf("["),v=_.lastIndexOf("]");g!==-1&&v>g&&(k=_.slice(g,v+1))}if(!k){this._searchState="internal-error",this._renderSearchState();return}try{let g=JSON.parse(k),v=[];if(g&&typeof g=="object"&&"data"in g){let w=g.data;if(w&&typeof w=="object"){let T=w;"matches"in T&&Array.isArray(T.matches)&&(v=T.matches)}}this._searchResults=v,this._searchState=v.length>0?"results":"empty",this._renderSearchState()}catch(g){let v=g instanceof Error?g.message:String(g);this._searchState="internal-error",this._renderSearchState()}}),m.on("error",x=>{let _=x.code;if(typeof _=="string"){let b=Xe(_);this._searchState=this._mapErrorToSearchState(b.type)}else this._searchState="backend-unavailable";this._renderSearchState()})}_mapErrorToSearchState(e){switch(e){case"vectors_not_built":return"vectors-not-built";case"vectors_corrupted":return"vectors-not-built";case"backend_unavailable":return"backend-unavailable";case"model_changed":return"model-changed";case"timeout":return"timeout";case"no_python":case"python_missing":case"import_failed":case"version_mismatch":return"backend-unavailable";default:return"backend-unavailable"}}_renderSearchResultsList(e,t){if(!this._searchResultsEl)return;if(this._searchResultsEl.setAttr("aria-live","polite"),e.length===0){this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty",text:"No results found."});return}let r=this._searchResultsEl.createEl("div",{cls:"paperforge-search-results-header"});r.createEl("span",{text:o("retrieval_results_count").replace("{n}",String(e.length)).replace("{s}",e.length!==1?"s":"")}).setAttr("aria-live","polite"),r.createEl("span",{cls:"paperforge-search-mode",text:t?"@":"M"});for(let a=0;aE!==null&&typeof E=="object"&&"zotero_key"in E&&E.zotero_key===f);if(b&&typeof b=="object"){let E=b;y=typeof E.main_note_path=="string"&&E.main_note_path?E.main_note_path:typeof E.note_path=="string"&&E.note_path?E.note_path:null}}y?c.addEventListener("click",_=>{let b=_.ctrlKey||_.metaKey;this.app.workspace.openLinkText(y,"",b)}):c.addEventListener("click",()=>{new I.Notice("[!!] Note not found: "+(f||"unknown"),6e3)}),c.addEventListener("keydown",_=>{if(_.key==="Enter"&&y){_.preventDefault();let b=_.ctrlKey||_.metaKey;this.app.workspace.openLinkText(y,"",b)}});let x=c.createEl("div",{cls:"paperforge-search-result-meta"});if(typeof i.first_author=="string"&&i.first_author&&x.createEl("span",{cls:"paperforge-search-result-author",text:i.first_author}),typeof i.journal=="string"&&i.journal&&x.createEl("span",{cls:"paperforge-search-result-journal",text:i.journal}),i.score!==void 0){let _=i.score,b=typeof _=="number"?_.toFixed(3):String(_);x.createEl("span",{cls:"paperforge-search-result-score",text:"Score: "+b})}if(typeof i.domain=="string"&&i.domain&&c.createEl("span",{cls:"paperforge-search-result-tag",text:i.domain}),typeof i.abstract=="string"&&i.abstract){let _=i.abstract;c.createEl("div",{cls:"paperforge-search-result-abstract",text:_.length>200?_.slice(0,200)+"...":_})}if(t&&typeof i.text=="string"&&i.text){let _=i.text;c.createEl("div",{cls:"paperforge-search-result-source",text:_.length>300?_.slice(0,300)+"...":_})}}}_renderSearchError(e){this._searchResultsEl&&(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-error",text:e}))}_runAction(e,t){var p,m;if(e.disabled){new I.Notice(`[i] ${e.disabledMsg||"This action is not yet available."}`,6e3);return}if(t.classList.contains("running"))return;t.addClass("running");let r=this.app.vault.adapter.basePath;this._showMessage("Processing...","running");let n=Array.isArray(e.args)?[...e.args]:[];if(e.needsKey){let y=this.app.workspace.getActiveFile(),x=null;if(y){let _=this.app.metadataCache.getFileCache(y);if(_&&_.frontmatter&&_.frontmatter.zotero_key?x=_.frontmatter.zotero_key:x=this._extractZoteroKeyFromPath(y.path),x)n=[...n,x];else if(_&&_.frontmatter){this._showMessage("[!!] No zotero_key in active note frontmatter","error"),new I.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}else{this._showMessage("[!!] No frontmatter in active note","error"),new I.Notice("[!!] The active note has no frontmatter with a zotero_key",6e3),t.removeClass("running");return}}else{this._showMessage("[!!] No active note open","error"),new I.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}}e.needsFilter&&(n=[...n,"--all"]);let a=e.needsFilter?6e4:e.needsKey?3e4:6e5,{path:s,extraArgs:i=[]}=N(r,(m=(p=this.app.plugins.plugins.paperforge)==null?void 0:p.settings)!=null?m:null,void 0,void 0),l=(0,_e.spawn)(s,[...i,"-m","paperforge",e.cmd,...n],{cwd:r,timeout:a}),c=[],d=Date.now(),f=setInterval(()=>this._fetchStats(!0),4e3);l.stdout.on("data",y=>{let x=y.toString("utf-8").split(` +`)[0].trim();return!s||s.startsWith("###")||s.startsWith("##")?null:s.length>300?s.slice(0,300)+"...":s}_renderRecentDiscussionCard(e,t){let r=e.createEl("div",{cls:"paperforge-discussion-card"});if(r.style.display="none",!t.note_path)return;let n=t.note_path.lastIndexOf("/"),s=(n!==-1?t.note_path.substring(0,n):".")+"/ai/discussion.md";this.app.vault.adapter.exists(s).then(i=>{if(i)return this.app.vault.adapter.read(s)}).then(async i=>{if(!i)return;let l=this._parseDiscussionMD(i);if(!l||l.length===0)return;r.style.display="block",r.createEl("div",{cls:"paperforge-discussion-header"}).createEl("span",{cls:"paperforge-discussion-title",text:"\u6700\u8FD1\u8BA8\u8BBA"});for(let f of l){let p=r.createEl("div",{cls:"paperforge-discussion-item"}),m=p.createEl("div",{cls:"paperforge-discussion-q"});m.createEl("span",{cls:"paperforge-discussion-q-label",text:"\u63D0\u95EE\uFF1A"}),m.createEl("span",{cls:"paperforge-discussion-q-text",text:f.question});let y=p.createEl("div",{cls:"paperforge-discussion-a"}),x=!1;if(f.answer&&f.answer.length>500&&(x=!0,y.classList.add("paperforge-discussion-a-collapsed")),await I.MarkdownRenderer.render(this.app,f.answer||"",y,s,this),x){let _=!1;p.style.cursor="pointer",p.addEventListener("click",()=>{_=!_,y.classList.toggle("paperforge-discussion-a-collapsed",!_),y.classList.toggle("paperforge-discussion-a-expanded",_)})}}r.createEl("a",{cls:"paperforge-discussion-viewall",text:"\u67E5\u770B\u5168\u90E8\u8BA8\u8BBA \u2192"}).addEventListener("click",f=>{f.preventDefault(),this.app.vault.getAbstractFileByPath(s)?this.app.workspace.openLinkText(s,""):new I.Notice("\u8BA8\u8BBA\u6587\u4EF6\u5C1A\u672A\u751F\u6210")})}).catch(i=>{console.error("PaperForge: discussion.md read error",s,i.message)})}_parseDiscussionMD(e){let t=e.split(/\n## /).slice(1);if(t.length===0)return null;let r=t[t.length-1],n=[],a=r.split(/\*\*\u95EE\u9898:\*\*/).slice(1);for(let s of a){let i=s.match(/\*\*\u89E3\u7B54:\*\*/);if(!i)continue;let l=s.substring(0,i.index).trim(),c=s.substring(i.index+3+4).trim();n.push({question:l,answer:c})}return n.slice(-3)}_renderPaperTechnicalDetails(e,t){let r=this._currentPaperKey,n=e.createEl("div",{cls:"paperforge-technical-details"}),a=n.createEl("button",{cls:"paperforge-technical-details-toggle"}),s=n.createEl("div",{cls:"paperforge-technical-details-body"});s.style.display="none",this._techDetailsExpanded?(s.style.display="block",a.setText("\u6280\u672F\u8BE6\u60C5 \u25BE")):a.setText("\u6280\u672F\u8BE6\u60C5 \u25B8"),a.addEventListener("click",()=>{let p=s.style.display!=="none";s.style.display=p?"none":"block",a.setText(p?"\u6280\u672F\u8BE6\u60C5 \u25B8":"\u6280\u672F\u8BE6\u60C5 \u25BE"),this._techDetailsExpanded=!p});let i=s.createEl("div",{cls:"paperforge-workflow-toggles"}),l=[{key:"do_ocr",label:"OCR",hint:"\u52A0\u5165 OCR"},{key:"analyze",label:"\u7CBE\u8BFB",hint:"\u6807\u8BB0\u7CBE\u8BFB"}];for(let p of l){let m=i.createEl("label",{cls:"paperforge-workflow-toggle"}),y=m.createEl("input",{type:"checkbox",cls:"paperforge-workflow-checkbox"});y.checked=t[p.key]===!0,m.createEl("span",{cls:"paperforge-workflow-toggle-label",text:p.label}),m.createEl("span",{cls:"paperforge-workflow-toggle-hint",text:p.hint}),y.addEventListener("change",async()=>{let x=t.note_path?this.app.vault.getAbstractFileByPath(t.note_path):null;if(!x){new I.Notice("[!!] Note file not found",6e3);return}let _=y.checked;await this.app.fileManager.processFrontMatter(x,b=>{b[p.key]=_}),this._patchCachedEntry(r,{[p.key]:_}),this._currentPaperEntry=Ze(this._currentPaperEntry,{[p.key]:_})})}let c=t.health||{},d=[["PDF Health",c.pdf_health||"\u2014"],["OCR Status",t.ocr_status||"\u2014"],["Asset Health",c.asset_health||"\u2014"],["Note Path",t.note_path||"\u2014"],["Fulltext Path",t.fulltext_path||"\u2014"]],f=new Set(["Note Path","Fulltext Path","Key"]);for(let[p,m]of d){let y=s.createEl("div",{cls:"paperforge-technical-row"});y.createEl("span",{cls:"paperforge-technical-label",text:p});let x=y.createEl("span",{cls:"paperforge-technical-value",text:String(m)});f.has(p)&&m&&m!=="\u2014"&&(x.addClass("pf-copy"),x.addEventListener("click",()=>{navigator.clipboard.writeText(m),new I.Notice(p+" copied")}))}}_renderNextStepCard(e,t,r){var l,c;let n=t.next_step||"ready",a={sync:{label:"Sync Needed",text:"This paper needs to be synced from Zotero. Click to run sync.",cmd:"sync",icon:"\u21BB"},ocr:{label:"OCR Needed",text:"Fulltext is missing but PDF is present. Click to run OCR.",cmd:"ocr",icon:"\u229E"},repair:{label:"Repair Needed",text:"State divergence or path errors detected. Click to repair.",cmd:"repair",icon:"\u21BA"},"rebuild index":{label:"Rebuild Needed",text:"Index may be stale. Click to run sync to rebuild.",cmd:"sync",icon:"\u21BB"},"/pf-deep":{label:"Ready for Deep Reading",text:"Fulltext is ready. Copy /pf-deep command and run in your agent.",cmd:null,icon:"\u{1F50D}"},ready:{label:"All Set",text:"This paper is fully processed and ready for use.",cmd:"ready",icon:"\u2713"}},s=a[n]||a.ready,i=e.createEl("div",{cls:"paperforge-next-step-card"});if(n==="ready"&&i.addClass("ready"),i.createEl("div",{cls:"paperforge-next-step-label",text:"Recommended Next Step"}),i.createEl("div",{cls:"paperforge-next-step-text",text:s.text}),s.cmd&&s.cmd!=="ready"){let d=i.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:s.icon+" "+s.label}),d.addEventListener("click",()=>{let f=se.find(p=>p.cmd===s.cmd);f&&this._runAction(f,d)})}else if(n==="/pf-deep"){let d=i.createEl("button",{cls:"paperforge-next-step-trigger"});d.createEl("span",{text:"\u{1F4CB} "+o("copy_pf_deep_cmd")}),d.addEventListener("click",()=>{let x="/pf-deep "+r;navigator.clipboard.writeText(x).then(()=>{d.setText("\u2713 "+o("copied")),new I.Notice(x+" copied")}).catch(()=>{new I.Notice("[!!] Clipboard write failed",6e3)})});let f=((c=(l=this.app.plugins.plugins.paperforge)==null?void 0:l.settings)==null?void 0:c.agent_platform)||"opencode",m={opencode:"OpenCode",claude:"Claude Code",cursor:"Cursor",github_copilot:"GitHub Copilot",windsurf:"Windsurf",codex:"Codex",gemini:"Gemini CLI",cline:"Cline"}[f]||f;i.createEl("div",{cls:"paperforge-agent-platform-label"}).setText(o("run_in_agent").replace("{0}",m))}else n==="ready"&&i.createEl("button",{cls:"paperforge-next-step-trigger"}).createEl("span",{text:"\u2713 "+s.label})}_openFulltext(e){if(!e){new I.Notice("[!!] No fulltext path available for this paper",6e3);return}let t=this.app.vault.getAbstractFileByPath(e);t?this.app.workspace.openLinkText(t.path,""):new I.Notice("[!!] Fulltext file not found: "+e,6e3)}_renderCollectionMode(){let e=this._currentDomain||"Unknown",t=this._filterByDomain(e);if(t.length===0){this._renderGlobalMode();return}if(!this._contentEl)return;let r=this._contentEl.createEl("div",{cls:"paperforge-collection-view"}),n=t.length,a=0,s=0,i=0,l=0,c=0,d=0,f=0;for(let g of t){g.has_pdf&&a++,g.ocr_status==="done"&&s++,g.ocr_status==="done"&&g.analyze===!0&&i++,g.deep_reading_status==="done"&&l++;let v=g.ocr_status||"";v==="pending"||v==="queued"?c++:v==="processing"?d++:(v==="failed"||v==="blocked"||v==="done_incomplete"||v==="nopdf")&&f++}r.createEl("div",{cls:"paperforge-collection-header"}).createEl("div",{cls:"paperforge-collection-title",text:e});let m=r.createEl("div",{cls:"paperforge-workflow-overview"});m.createEl("div",{cls:"paperforge-section-label",text:"Workflow Overview"});let y=m.createEl("div",{cls:"paperforge-workflow-funnel"}),x=[{value:n,label:"Total"},{value:a,label:"PDF Ready"},{value:s,label:"OCR Done"},{value:l,label:"Deep Read"}];for(let g=0;g0){let g=r.createEl("div",{cls:"paperforge-ocr-section"}),v=g.createEl("div",{cls:"paperforge-collection-ocr-header"});v.createEl("h4",{cls:"paperforge-ocr-title",text:"OCR Pipeline"});let w=v.createEl("span",{cls:"paperforge-ocr-badge idle"});d>0?(w.addClass("active"),w.setText("Processing")):c>0?w.setText("Pending"):(w.addClass("idle"),w.setText("Idle"));let T=g.createEl("div",{cls:"paperforge-progress-track"});d>0&&T.addClass("paperforge-processing");let P=c+d+s+f,L=[{cls:"pending",count:c},{cls:"active",count:d},{cls:"done",count:s},{cls:"failed",count:f}];for(let q of L)if(q.count>0){let D=(q.count/P*100).toFixed(1);T.createEl("div",{cls:`paperforge-progress-seg ${q.cls}`,attr:{style:`width:${D}%`}})}let O=g.createEl("div",{cls:"paperforge-ocr-counts"}),z=[{cls:"pending",value:c,label:"Pending"},{cls:"active",value:d,label:"Processing"},{cls:"done",value:s,label:"Done"},{cls:"failed",value:f,label:"Attention"}];for(let q of z){let D=O.createEl("div",{cls:"paperforge-ocr-count"});D.createEl("div",{cls:"paperforge-ocr-count-value",text:q.value.toString()}),D.createEl("div",{cls:"paperforge-ocr-count-label",text:q.label})}}let _=r.createEl("div",{cls:"paperforge-collection-actions"}),b=_.createEl("button",{cls:"paperforge-contextual-btn primary"});b.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u229E"}),b.createEl("span",{text:"Run OCR"}),b.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-ocr");g&&this._runAction(g,b)});let E=_.createEl("button",{cls:"paperforge-contextual-btn"});E.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BB"}),E.createEl("span",{text:"Sync Library"}),E.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-sync");g&&this._runAction(g,E)});let k=_.createEl("button",{cls:"paperforge-contextual-btn warn"});k.createEl("span",{cls:"paperforge-contextual-btn-icon",text:"\u21BA"}),k.createEl("span",{text:"Redo OCR"}),k.addEventListener("click",()=>{let g=se.find(v=>v.id==="paperforge-ocr-redo");g&&this._runAction(g,k)}),this.renderSearchSection(r)}_refreshCurrentMode(){if(!(!this._currentMode||!this._contentEl)){this._contentEl.empty(),this._contentEl.addClass("switching"),this._invalidateIndex(),this._currentPaperEntry=this._currentPaperKey?this._findEntry(this._currentPaperKey):null,this._renderModeHeader(this._currentMode);try{switch(this._currentMode){case"global":this._renderGlobalMode();break;case"paper":this._renderPaperMode();break;case"collection":this._renderCollectionMode();break;case"versions":this._renderVersionMode();break}}finally{setTimeout(()=>{this._contentEl&&this._contentEl.removeClass("switching")},50)}}}_switchToVersionMode(e){let r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){new I.Notice("Cannot determine vault path");return}this._versionPapers=nt(n),this._versionFilter="",this._currentMode="versions",this._currentFilePath=null,this._techDetailsExpanded=!1,this._contentEl&&(this._contentEl.empty(),this._contentEl.removeClass("switching"),this._renderModeHeader("versions"),this._renderVersionMode())}_renderVersionMode(){if(!this._contentEl)return;let e=this._contentEl.createEl("div",{cls:"paperforge-version-panel"}),r=this.app.vault.adapter.basePath,n=typeof r=="string"?r:"";if(!n){e.createEl("div",{cls:"paperforge-status-error",text:"Could not determine vault path"});return}(!this._versionPapers||this._versionPapers.length===0)&&(this._versionPapers=nt(n));let a=e.createEl("div",{cls:"paperforge-version-left"}),s=e.createEl("div",{cls:"paperforge-version-right"}),i=a.createEl("input",{cls:"paperforge-version-filter",attr:{type:"text",placeholder:o("version_filter_placeholder")}});i.value=this._versionFilter;let l=a.createEl("div",{cls:"paperforge-version-paper-list"}),c=()=>{l.empty();let b=this._versionFilter.toLowerCase(),E=this._versionPapers?this._versionPapers.filter(g=>!b||g.key.toLowerCase().includes(b)||g.title.toLowerCase().includes(b)):[];if(E.length===0){l.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let k=l.createEl("div",{cls:"paperforge-meta",text:o("version_papers_count").replace("{n}",String(E.length))});for(let g of E){let v=l.createEl("div",{cls:"paperforge-version-paper-item"}),w=v.createEl("span",{cls:"paperforge-version-paper-title",text:g.title}),T=v.createEl("span",{cls:"paperforge-version-paper-versions",text:g.versions.map(P=>P.label).join(" ")});v.addEventListener("click",()=>{l.querySelectorAll(".paperforge-version-paper-item.selected").forEach(P=>P.removeClass("selected")),v.addClass("selected"),f(g)})}};i.addEventListener("input",()=>{this._versionFilter=i.value,c()});let d=s.createEl("div",{cls:"paperforge-version-timeline-area"}),f=b=>{if(d.empty(),d.createEl("div",{cls:"paperforge-version-timeline-header"}).createEl("span",{cls:"pf-title",text:b.title}),b.versions.length===0){d.createEl("div",{cls:"paperforge-meta",text:o("version_no_backups")});return}let k=d.createEl("div",{cls:"paperforge-version-timeline"});for(let g of b.versions){let v=g.label===b.currentLabel,w=k.createEl("div",{cls:"paperforge-version-entry"+(v?" paperforge-version-current":"")}),T=w.createEl("div",{cls:"paperforge-version-dot"}),P=w.createEl("div",{cls:"paperforge-version-content"}),L=P.createEl("div",{cls:"paperforge-version-label-row"});L.createEl("span",{cls:"paperforge-version-label",text:g.label}),v&&L.createEl("span",{cls:"paperforge-version-current-tag",text:o("version_current")});let O=g.created_at?g.created_at.slice(0,10):"";P.createEl("div",{cls:"paperforge-meta",text:O+" \u2014 "+g.source});let z=g.fulltext_size?g.fulltext_size>1024?(g.fulltext_size/1024).toFixed(0)+"KB":g.fulltext_size+"B":"";z&&P.createEl("div",{cls:"paperforge-meta",text:z});let q=P.createEl("div",{cls:"paperforge-version-actions"});q.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_btn")}).addEventListener("click",()=>{Rt(n,b.key,g.label)?new I.Notice(o("version_restore_done").replace("{label}",g.label)):new I.Notice("Restore failed",6e3)}),b.versions.length>1&&!v&&q.createEl("button",{cls:"pf-btn-secondary",text:o("version_compare_btn")}).addEventListener("click",()=>{m(b,g.label,b.currentLabel)})}},p=s.createEl("div",{cls:"paperforge-version-compare"});p.style.display="none";let m=(b,E,k)=>{let g=Tt(n,b.key,E,k);p.style.display="block",p.empty();let v=p.createEl("div",{cls:"paperforge-version-compare-header"});if(v.createEl("span",{cls:"pf-title",text:o("version_compare_title").replace("{vA}",E).replace("{vB}",k)}),v.createEl("span",{cls:"paperforge-meta",text:o("version_compare_paragraphs").replace("{n}",String(g.length))}),g.length===0){p.createEl("div",{cls:"paperforge-meta",text:"No changes"});return}let w=p.createEl("div",{cls:"paperforge-version-diff-list"});for(let T of g){let P=w.createEl("div",{cls:"paperforge-version-diff-row"}),L=T.type==="added"?"[+]":T.type==="removed"?"[-]":"[~]",O=T.heading||"paragraph "+(T.paragraphIndex+1);P.createEl("span",{cls:"paperforge-version-diff-label",text:L+" "+O}),T.oldText&&P.createEl("pre",{cls:"paperforge-version-diff-old",text:T.oldText.slice(0,200)}),T.newText&&P.createEl("pre",{cls:"paperforge-version-diff-new",text:T.newText.slice(0,200)})}},y=e.createEl("div",{cls:"paperforge-version-actions-bar"}),x=y.createEl("button",{cls:"pf-btn-primary",text:o("version_restore_selected")}),_=y.createEl("button",{cls:"pf-btn-secondary",text:o("version_clear_old").replace("{size}","")});c()}renderSearchSection(e){this._searchContainer=e.createEl("div",{cls:"paperforge-search-section"}),this._searchContainer.createEl("div",{cls:"paperforge-search-header"}).createEl("span",{cls:"pf-label",text:"Search"});let r=this._searchContainer.createEl("div",{cls:"paperforge-search-input-row"}),n=r.createEl("span",{cls:"paperforge-search-mode",text:"M"});this._searchInput=r.createEl("input",{cls:"paperforge-search-input",attr:{type:"text",placeholder:"Search papers... (@ for deep search)"}}),this._searchResultsEl=this._searchContainer.createEl("div",{cls:"paperforge-search-results"}),this._searchInput.placeholder=o("retrieval_search_placeholder"),this._searchInput.addEventListener("input",()=>{var s;let a=((s=this._searchInput)==null?void 0:s.value)||"";if(a.startsWith("@")&&!a.startsWith("@ ")?(this._searchMode="@",n.setText("@"),n.addClass("deep"),this._searchInput&&(this._searchInput.placeholder=o("retrieval_search_placeholder_deep"))):(this._searchMode="M",n.setText("M"),n.removeClass("deep"),this._searchInput&&(this._searchInput.placeholder=o("retrieval_search_placeholder"))),clearTimeout(this._searchTimer),!a.trim()){this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();return}a.startsWith("@")||(this._searchTimer=setTimeout(()=>{this.executeSearch()},200))}),this._searchInput.addEventListener("keydown",a=>{var s,i;if(a.key==="Escape"){a.preventDefault(),this._searchInput&&(this._searchInput.value="",this._searchInput.blur()),this._searchState="idle",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();return}if(a.key==="ArrowDown"||a.key==="ArrowUp"){if(this._searchState!=="results"||!((s=this._searchResults)!=null&&s.length))return;a.preventDefault();let l=this._searchResults.length;a.key==="ArrowDown"?this._searchActiveIndex=Math.min(this._searchActiveIndex+1,l-1):this._searchActiveIndex=Math.max(this._searchActiveIndex-1,-1);let c=(i=this._searchResultsEl)==null?void 0:i.querySelectorAll(".paperforge-search-result-card");c&&c.forEach((d,f)=>{f===this._searchActiveIndex?(d.setAttribute("aria-selected","true"),d.classList.add("active")):(d.setAttribute("aria-selected","false"),d.classList.remove("active"))});return}if(a.key==="Enter"&&a.ctrlKey){a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0);let l=this._searchMode;this._searchMode="@",this.executeSearch(),this._searchMode=l;return}a.key==="Enter"&&(a.preventDefault(),this._searchTimer&&(clearTimeout(this._searchTimer),this._searchTimer=void 0),this.executeSearch())})}_renderSearchState(){if(!this._searchResultsEl)return;switch(this._searchResultsEl.empty(),this._searchResultsEl.removeAttribute("role"),this._searchResultsEl.removeAttribute("aria-live"),this._searchInput&&(this._searchInput.disabled=!1),this._searchState){case"idle":break;case"searching":{let t=this._searchMode==="@";this._searchResultsEl.createEl("div",{cls:"paperforge-search-loading",text:t?o("retrieval_searching_deep"):o("retrieval_searching_metadata")}),this._searchResultsEl.setAttr("aria-live","polite"),t&&this._searchInput&&(this._searchInput.disabled=!0);break}case"results":{this._searchResultsEl.setAttr("role","listbox"),this._searchResultsEl.setAttr("aria-live","polite"),this._searchResults&&this._renderSearchResultsList(this._searchResults,this._searchMode==="@"),setTimeout(()=>{var r;let t=(r=this._searchResultsEl)==null?void 0:r.querySelector(".paperforge-search-result-card");t&&t instanceof HTMLElement&&t.focus()},100);break}case"empty":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty"});t.setAttr("role","alert"),t.createEl("div",{text:o("retrieval_empty")}),t.createEl("div",{cls:"paperforge-search-empty-tips",text:o("retrieval_empty_tips")});break}case"vectors-not-built":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_vectors_not_built")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_vectors_not_built_desc")});let r=t.createEl("button",{cls:"pf-btn-link",text:o("retrieval_open_vector_settings")});r.addEventListener("click",()=>{let n=this.app.setting;if(n&&typeof n=="object"){let a=n.openTab;typeof a=="function"&&a.call(n,"paperforge")}}),setTimeout(()=>{r.focus()},100);break}case"backend-unavailable":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("error-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_backend_unavailable")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_backend_unavailable_desc")});let r=t.createEl("div",{cls:"paperforge-search-state-actions"}),n=r.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_run_doctor")});n.addEventListener("click",()=>{let s=this.app.vault.adapter.basePath;if(typeof s=="string"){let{path:i,extraArgs:l=[]}=N(s,null,void 0,void 0);(0,_e.spawn)(i,[...l,"-m","paperforge","doctor"],{cwd:s,stdio:"inherit"})}}),r.createEl("button",{cls:"pf-btn-secondary",text:o("retrieval_retry")}).addEventListener("click",()=>{this.executeSearch()}),setTimeout(()=>{n.focus()},100);break}case"timeout":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_timeout_title")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_timeout_desc")});let r=t.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_retry")});r.addEventListener("click",()=>{this.executeSearch()}),setTimeout(()=>{r.focus()},100);break}case"model-changed":{let t=this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",attr:{role:"alert"}});t.addClass("warning-soft"),t.createEl("div",{cls:"paperforge-search-state-title",text:o("retrieval_model_changed")}),t.createEl("div",{cls:"paperforge-search-state-desc",text:o("retrieval_model_changed_desc")});let r=t.createEl("button",{cls:"pf-btn-primary",text:o("retrieval_rebuild_vectors")});r.addEventListener("click",()=>{let n=this.app.setting;if(n&&typeof n=="object"){let a=n.openTab;typeof a=="function"&&a.call(n,"paperforge")}}),setTimeout(()=>{r.focus()},100);break}default:{this._searchResultsEl.createEl("div",{cls:"paperforge-search-state-card",text:o("retrieval_internal_error"),attr:{role:"alert"}}).addClass("error-soft"),setTimeout(()=>{this._searchInput&&this._searchInput.focus()},100);break}}}async executeSearch(){if(!this._searchInput||!this._searchResultsEl)return;let e=this._searchInput.value.trim();if(!e)return;let t=this._searchMode==="@"||e.startsWith("@"),r=t?e.replace(/^@\s*/,"").trim():e;if(!r)return;let n=t?"retrieve":"search";this._searchState="searching",this._searchResults=null,this._searchActiveIndex=-1,this._renderSearchState();let a=this.app.vault.adapter,s="";if(a&&typeof a=="object"&&"basePath"in a){let x=a.basePath;s=typeof x=="string"?x:""}if(!s){this._searchState="backend-unavailable",this._renderSearchState();return}let i=null,c=this.app.plugins;if(c&&typeof c=="object"&&"plugins"in c){let x=c.plugins;if(x&&typeof x=="object"&&"paperforge"in x){let _=x.paperforge;_&&typeof _=="object"&&"settings"in _&&(i=_.settings)}}let{path:d,extraArgs:f=[]}=N(s,i,void 0,void 0),p=n==="retrieve"?["--deep"]:[],m=(0,_e.spawn)(d,[...f,"-m","paperforge","--vault",s,n,r,...p,"--json"],{cwd:s,timeout:3e4}),y=[];m.stdout.on("data",x=>{y.push(x.toString("utf-8"))}),m.stderr.on("data",()=>{}),m.on("close",x=>{if(x!==0){let g=Xe(String(x));this._searchState=this._mapErrorToSearchState(g.type),this._renderSearchState();return}let _=y.join(""),b=_.indexOf("{"),E=_.lastIndexOf("}"),k="";if(b!==-1&&E>b)k=_.slice(b,E+1);else{let g=_.indexOf("["),v=_.lastIndexOf("]");g!==-1&&v>g&&(k=_.slice(g,v+1))}if(!k){this._searchState="internal-error",this._renderSearchState();return}try{let g=JSON.parse(k),v=[];if(g&&typeof g=="object"&&"data"in g){let w=g.data;if(w&&typeof w=="object"){let T=w;"matches"in T&&Array.isArray(T.matches)&&(v=T.matches)}}this._searchResults=v,this._searchState=v.length>0?"results":"empty",this._renderSearchState()}catch(g){let v=g instanceof Error?g.message:String(g);this._searchState="internal-error",this._renderSearchState()}}),m.on("error",x=>{let _=x.code;if(typeof _=="string"){let b=Xe(_);this._searchState=this._mapErrorToSearchState(b.type)}else this._searchState="backend-unavailable";this._renderSearchState()})}_mapErrorToSearchState(e){switch(e){case"vectors_not_built":return"vectors-not-built";case"vectors_corrupted":return"vectors-not-built";case"backend_unavailable":return"backend-unavailable";case"model_changed":return"model-changed";case"timeout":return"timeout";case"no_python":case"python_missing":case"import_failed":case"version_mismatch":return"backend-unavailable";default:return"backend-unavailable"}}_renderSearchResultsList(e,t){if(!this._searchResultsEl)return;if(this._searchResultsEl.setAttr("aria-live","polite"),e.length===0){this._searchResultsEl.createEl("div",{cls:"paperforge-search-empty",text:"No results found."});return}let r=this._searchResultsEl.createEl("div",{cls:"paperforge-search-results-header"});r.createEl("span",{text:o("retrieval_results_count").replace("{n}",String(e.length)).replace("{s}",e.length!==1?"s":"")}).setAttr("aria-live","polite"),r.createEl("span",{cls:"paperforge-search-mode",text:t?"@":"M"});for(let a=0;aE!==null&&typeof E=="object"&&"zotero_key"in E&&E.zotero_key===f);if(b&&typeof b=="object"){let E=b;y=typeof E.main_note_path=="string"&&E.main_note_path?E.main_note_path:typeof E.note_path=="string"&&E.note_path?E.note_path:null}}y?c.addEventListener("click",_=>{let b=_.ctrlKey||_.metaKey;this.app.workspace.openLinkText(y,"",b)}):c.addEventListener("click",()=>{new I.Notice("[!!] Note not found: "+(f||"unknown"),6e3)}),c.addEventListener("keydown",_=>{if(_.key==="Enter"&&y){_.preventDefault();let b=_.ctrlKey||_.metaKey;this.app.workspace.openLinkText(y,"",b)}});let x=c.createEl("div",{cls:"paperforge-search-result-meta"});if(typeof i.first_author=="string"&&i.first_author&&x.createEl("span",{cls:"paperforge-search-result-author",text:i.first_author}),typeof i.journal=="string"&&i.journal&&x.createEl("span",{cls:"paperforge-search-result-journal",text:i.journal}),i.score!==void 0){let _=i.score,b=typeof _=="number"?_.toFixed(3):String(_);x.createEl("span",{cls:"paperforge-search-result-score",text:"Score: "+b})}if(typeof i.domain=="string"&&i.domain&&c.createEl("span",{cls:"paperforge-search-result-tag",text:i.domain}),typeof i.abstract=="string"&&i.abstract){let _=i.abstract;c.createEl("div",{cls:"paperforge-search-result-abstract",text:_.length>200?_.slice(0,200)+"...":_})}if(t&&typeof i.text=="string"&&i.text){let _=i.text;c.createEl("div",{cls:"paperforge-search-result-source",text:_.length>300?_.slice(0,300)+"...":_})}}}_renderSearchError(e){this._searchResultsEl&&(this._searchResultsEl.empty(),this._searchResultsEl.createEl("div",{cls:"paperforge-search-error",text:e}))}_runAction(e,t){var p,m;if(e.disabled){new I.Notice(`[i] ${e.disabledMsg||"This action is not yet available."}`,6e3);return}if(t.classList.contains("running"))return;t.addClass("running");let r=this.app.vault.adapter.basePath;this._showMessage("Processing...","running");let n=Array.isArray(e.args)?[...e.args]:[];if(e.needsKey){let y=this.app.workspace.getActiveFile(),x=null;if(y){let _=this.app.metadataCache.getFileCache(y);if(_&&_.frontmatter&&_.frontmatter.zotero_key?x=_.frontmatter.zotero_key:x=this._extractZoteroKeyFromPath(y.path),x)n=[...n,x];else if(_&&_.frontmatter){this._showMessage("[!!] No zotero_key in active note frontmatter","error"),new I.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}else{this._showMessage("[!!] No frontmatter in active note","error"),new I.Notice("[!!] The active note has no frontmatter with a zotero_key",6e3),t.removeClass("running");return}}else{this._showMessage("[!!] No active note open","error"),new I.Notice("[!!] Open a paper note with a zotero_key in its frontmatter first",6e3),t.removeClass("running");return}}e.needsFilter&&(n=[...n,"--all"]);let a=e.needsFilter?6e4:e.needsKey?3e4:6e5,{path:s,extraArgs:i=[]}=N(r,(m=(p=this.app.plugins.plugins.paperforge)==null?void 0:p.settings)!=null?m:null,void 0,void 0),l=(0,_e.spawn)(s,[...i,"-m","paperforge",e.cmd,...n],{cwd:r,timeout:a}),c=[],d=Date.now(),f=setInterval(()=>this._fetchStats(!0),4e3);l.stdout.on("data",y=>{let x=y.toString("utf-8").split(` `).filter(Boolean);for(let _ of x){let b=_.trim();b&&(c.push(b),this._showMessage(c.slice(-8).join(` `),"running"))}}),l.stderr.on("data",y=>{let x=y.toString("utf-8").split(` `).filter(Boolean);for(let _ of x){if(_.includes("\r")||_.includes("%")||_.includes("\u2588"))continue;let b=_.trim();b&&!b.match(/^\d+%|^\|/)&&(c.push(b),this._showMessage(c.slice(-8).join(` diff --git a/paperforge/plugin/src/services/memory-state.ts b/paperforge/plugin/src/services/memory-state.ts index 61aaa2a8..3240ec88 100644 --- a/paperforge/plugin/src/services/memory-state.ts +++ b/paperforge/plugin/src/services/memory-state.ts @@ -227,7 +227,9 @@ export function isVectorReady(vaultPath: string): boolean { if (!s.deps_installed) return false; if (!s.db_exists) return false; if (s.healthy === false) return false; - if (s.chunk_count === 0) return false; + // Use total_chunks (body + object + fulltext) — chunk_count alone is vec_fulltext_meta which may be empty + const total = (s.chunk_count ?? 0) + ((s.body_chunk_count as number) ?? 0) + ((s.object_chunk_count as number) ?? 0); + if (total === 0) return false; return true; } From f158c9ff801737d6ef5e2e2120ad599348ab3e0b Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 11 Jul 2026 00:52:30 +0800 Subject: [PATCH 21/21] fix: force-rebuild uses ensure_vec_tables for correct embedding dimension --- paperforge/commands/embed.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/paperforge/commands/embed.py b/paperforge/commands/embed.py index 3d4609f1..e29bb648 100644 --- a/paperforge/commands/embed.py +++ b/paperforge/commands/embed.py @@ -17,6 +17,7 @@ from paperforge.embedding import ( mark_vector_build_state, read_vector_build_state, ) +from paperforge.embedding.dim_detect import ensure_vec_tables from paperforge.embedding.builder import ( PaperEmbeddingJob, encode_paper_job, @@ -300,12 +301,12 @@ def run(args: argparse.Namespace) -> int: if _db_path.exists(): _conn = get_connection(_db_path) try: - from paperforge.memory.db import ensure_vec_extension - from paperforge.memory.schema import ensure_schema ensure_vec_extension(_conn) - for _t in ("vec_fulltext", "vec_body", "vec_objects", - "vec_fulltext_meta", "vec_body_meta", "vec_objects_meta"): + # Drop and recreate vec0 tables first with correct dimension + ensure_vec_tables(_conn, vault) + for _t in ("vec_fulltext_meta", "vec_body_meta", "vec_objects_meta"): _conn.execute(f'DROP TABLE IF EXISTS "{_t}"') + # ensure_schema recreates meta tables (vec v-tables already correct from ensure_vec_tables) ensure_schema(_conn) _conn.commit() except Exception: