remosidian 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/remosidian.mjs +1199 -264
  2. package/package.json +1 -1
@@ -675,7 +675,7 @@ module.exports = { format, parse };
675
675
 
676
676
  /***/ }),
677
677
 
678
- /***/ 3318:
678
+ /***/ 937:
679
679
  /***/ ((module) => {
680
680
 
681
681
 
@@ -745,7 +745,7 @@ module.exports = Limiter;
745
745
  const zlib = __nccwpck_require__(3106);
746
746
 
747
747
  const bufferUtil = __nccwpck_require__(9488);
748
- const Limiter = __nccwpck_require__(3318);
748
+ const Limiter = __nccwpck_require__(937);
749
749
  const { kStatusCode } = __nccwpck_require__(6996);
750
750
 
751
751
  const FastBuffer = Buffer[Symbol.species];
@@ -8020,27 +8020,6 @@ module.exports = {
8020
8020
  };
8021
8021
 
8022
8022
 
8023
- /***/ }),
8024
-
8025
- /***/ 9646:
8026
- /***/ (function(module) {
8027
-
8028
- !function(t,e){ true?module.exports=e():0}(this,(function(){"use strict";var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",c="month",f="quarter",h="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return"["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,c),s=n-i<0,u=e.clone().add(r+(s?-1:1),c);return+(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return{M:c,y:h,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:f}[t]||String(t||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},g="en",D={};D[g]=M;var p="$isDayjsObject",S=function(t){return t instanceof _||!(!t||!t[p])},w=function t(e,n,r){var i;if(!e)return g;if("string"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split("-");if(!i&&u.length>1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<O(t)},m.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!b.u(e)||e,f=b.p(t),l=function(t,e){var i=b.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return b.w(n.toDate()[t].apply(n.toDate("s"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v="set"+(this.$u?"UTC":"");switch(f){case h:return r?l(1,0):l(31,11);case c:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+"Hours",0);case u:return $(v+"Minutes",1);case s:return $(v+"Seconds",2);case i:return $(v+"Milliseconds",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,!1)},m.$set=function(t,e){var n,o=b.p(t),f="set"+(this.$u?"UTC":""),l=(n={},n[a]=f+"Date",n[d]=f+"Date",n[c]=f+"Month",n[h]=f+"FullYear",n[u]=f+"Hours",n[s]=f+"Minutes",n[i]=f+"Seconds",n[r]=f+"Milliseconds",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===c||o===h){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[b.p(t)]()},m.add=function(r,f){var d,l=this;r=Number(r);var $=b.p(f),y=function(t){var e=O(l);return b.w(e.date(e.date()+Math.round(t*r)),l)};if($===c)return this.set(c,this.$M+r);if($===h)return this.set(h,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return b.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||"YYYY-MM-DDTHH:mm:ssZ",i=b.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,c=n.months,f=n.meridiem,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},d=function(t){return b.s(s%12||12,t,"0")},$=f||function(t,e,n){var r=t<12?"AM":"PM";return n?r.toLowerCase():r};return r.replace(y,(function(t,r){return r||function(t){switch(t){case"YY":return String(e.$y).slice(-2);case"YYYY":return b.s(e.$y,4,"0");case"M":return a+1;case"MM":return b.s(a+1,2,"0");case"MMM":return h(n.monthsShort,a,c,3);case"MMMM":return h(c,a);case"D":return e.$D;case"DD":return b.s(e.$D,2,"0");case"d":return String(e.$W);case"dd":return h(n.weekdaysMin,e.$W,o,2);case"ddd":return h(n.weekdaysShort,e.$W,o,3);case"dddd":return o[e.$W];case"H":return String(s);case"HH":return b.s(s,2,"0");case"h":return d(1);case"hh":return d(2);case"a":return $(s,u,!0);case"A":return $(s,u,!1);case"m":return String(u);case"mm":return b.s(u,2,"0");case"s":return String(e.$s);case"ss":return b.s(e.$s,2,"0");case"SSS":return b.s(e.$ms,3,"0");case"Z":return i}return null}(t)||i.replace(":","")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=this,M=b.p(d),m=O(r),v=(m.utcOffset()-this.utcOffset())*e,g=this-m,D=function(){return b.m(y,m)};switch(M){case h:$=D()/12;break;case c:$=D();break;case f:$=D()/3;break;case o:$=(g-v)/6048e5;break;case a:$=(g-v)/864e5;break;case u:$=g/n;break;case s:$=g/e;break;case i:$=g/t;break;default:$=g}return l?$:b.a($)},m.daysInMonth=function(){return this.endOf(c).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=w(t,e,!0);return r&&(n.$L=r),n},m.clone=function(){return b.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),k=_.prototype;return O.prototype=k,[["$ms",r],["$s",i],["$m",s],["$H",u],["$W",a],["$M",c],["$y",h],["$D",d]].forEach((function(t){k[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),O.extend=function(t,e){return t.$i||(t(e,_,O),t.$i=!0),O},O.locale=w,O.isDayjs=S,O.unix=function(t){return O(1e3*t)},O.en=D[g],O.Ls=D,O.p={},O}));
8029
-
8030
- /***/ }),
8031
-
8032
- /***/ 564:
8033
- /***/ (function(module) {
8034
-
8035
- !function(e,t){ true?module.exports=t():0}(this,(function(){"use strict";var e="day";return function(t,i,s){var a=function(t){return t.add(4-t.isoWeekday(),e)},d=i.prototype;d.isoWeekYear=function(){return a(this).year()},d.isoWeek=function(t){if(!this.$utils().u(t))return this.add(7*(t-this.isoWeek()),e);var i,d,n,o,r=a(this),u=(i=this.isoWeekYear(),d=this.$u,n=(d?s.utc:s)().year(i).startOf("year"),o=4-n.isoWeekday(),n.isoWeekday()>4&&(o+=7),n.add(o,e));return r.diff(u,"week")+1},d.isoWeekday=function(e){return this.$utils().u(e)?this.day()||7:this.day(this.day()%7?e:e-7)};var n=d.startOf;d.startOf=function(e,t){var i=this.$utils(),s=!!i.u(t)||t;return"isoweek"===i.p(e)?s?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):n.bind(this)(e,t)}}}));
8036
-
8037
- /***/ }),
8038
-
8039
- /***/ 2149:
8040
- /***/ (function(module) {
8041
-
8042
- !function(t,n){ true?module.exports=n():0}(this,(function(){"use strict";var t="month",n="quarter";return function(e,i){var r=i.prototype;r.quarter=function(t){return this.$utils().u(t)?Math.ceil((this.month()+1)/3):this.month(this.month()%3+3*(t-1))};var s=r.add;r.add=function(e,i){return e=Number(e),this.$utils().p(i)===n?this.add(3*e,t):s.bind(this)(e,i)};var u=r.startOf;r.startOf=function(e,i){var r=this.$utils(),s=!!r.u(i)||i;if(r.p(e)===n){var o=this.quarter()-1;return s?this.month(3*o).startOf(t).startOf("day"):this.month(3*o+2).endOf(t).endOf("day")}return u.bind(this)(e,i)}}}));
8043
-
8044
8023
  /***/ }),
8045
8024
 
8046
8025
  /***/ 1635:
@@ -15218,6 +15197,7 @@ async function readJsonBody(req, maxBytes = MAX_PAIR_BODY_BYTES) {
15218
15197
  function createPairingHttpHandler(deps) {
15219
15198
  const trusted = deps.isTrustedRequest ?? isTrustedLocalRequest;
15220
15199
  const pairWindowMs = deps.pairWindowMs ?? DEFAULT_PAIR_WINDOW_MS;
15200
+ const reviewToken = deps.reviewToken?.trim() ?? '';
15221
15201
  function buildOpenPayload() {
15222
15202
  const window = deps.pairings.openWindow(pairWindowMs, deps.pairReusable === true);
15223
15203
  const target = deps.getAdvertisedConnectionTarget();
@@ -15246,19 +15226,27 @@ function createPairingHttpHandler(deps) {
15246
15226
  const handleCreate = async (req, res) => {
15247
15227
  try {
15248
15228
  const body = await readJsonBody(req);
15249
- if (body.daemonId !== deps.identity.daemonId ||
15250
- typeof body.pairNonce !== 'string' ||
15229
+ // Hosted-review fast path: a request whose pairNonce equals the shared
15230
+ // review token is honored without an in-memory window and echoes the
15231
+ // token back, so the credential survives daemon restarts/redeploys. It
15232
+ // also skips the daemonId check, so a pre-generated review QR keeps
15233
+ // working even if the hosted machine is migrated and gets a new identity.
15234
+ const isReviewPair = reviewToken !== '' && body.pairNonce === reviewToken;
15235
+ if (typeof body.pairNonce !== 'string' ||
15251
15236
  typeof body.deviceId !== 'string' ||
15252
- typeof body.deviceName !== 'string') {
15237
+ typeof body.deviceName !== 'string' ||
15238
+ (!isReviewPair && body.daemonId !== deps.identity.daemonId)) {
15253
15239
  sendJson(res, 400, { ok: false, error: 'invalid_pair_request' });
15254
15240
  return;
15255
15241
  }
15256
- const window = deps.pairings.consumeWindow(body.pairNonce);
15257
- if (!window) {
15258
- sendJson(res, 401, { ok: false, error: 'pair_window_expired' });
15259
- return;
15242
+ if (!isReviewPair) {
15243
+ const window = deps.pairings.consumeWindow(body.pairNonce);
15244
+ if (!window) {
15245
+ sendJson(res, 401, { ok: false, error: 'pair_window_expired' });
15246
+ return;
15247
+ }
15260
15248
  }
15261
- const pairToken = deps.pairings.issuePairToken(body.deviceId, body.deviceName);
15249
+ const pairToken = isReviewPair ? reviewToken : deps.pairings.issuePairToken(body.deviceId, body.deviceName);
15262
15250
  const target = deps.getAdvertisedConnectionTarget();
15263
15251
  const extras = deps.extras?.();
15264
15252
  sendJson(res, 200, {
@@ -17159,6 +17147,37 @@ function getNvmBinCandidates() {
17159
17147
  }
17160
17148
  return candidates;
17161
17149
  }
17150
+ function getFnmBinCandidates() {
17151
+ const home = (0,external_node_os_namespaceObject.homedir)();
17152
+ const roots = [
17153
+ process.env.FNM_DIR,
17154
+ (0,external_node_path_namespaceObject.join)(home, '.local', 'share', 'fnm'),
17155
+ (0,external_node_path_namespaceObject.join)(home, 'Library', 'Application Support', 'fnm'),
17156
+ (0,external_node_path_namespaceObject.join)(home, '.fnm'),
17157
+ ].filter((p) => Boolean(p));
17158
+ const candidates = [];
17159
+ const seen = new Set();
17160
+ for (const root of roots) {
17161
+ if (seen.has(root))
17162
+ continue;
17163
+ seen.add(root);
17164
+ const versionsDir = (0,external_node_path_namespaceObject.join)(root, 'node-versions');
17165
+ try {
17166
+ const versionDirs = (0,external_node_fs_namespaceObject.readdirSync)(versionsDir, { withFileTypes: true })
17167
+ .filter((entry) => entry.isDirectory())
17168
+ .map((entry) => entry.name)
17169
+ .sort(compareNodeVersionDirsDesc);
17170
+ for (const versionDir of versionDirs) {
17171
+ candidates.push((0,external_node_path_namespaceObject.join)(versionsDir, versionDir, 'installation', 'bin'));
17172
+ candidates.push((0,external_node_path_namespaceObject.join)(versionsDir, versionDir, 'bin'));
17173
+ }
17174
+ }
17175
+ catch {
17176
+ // fnm not installed at this root
17177
+ }
17178
+ }
17179
+ return candidates;
17180
+ }
17162
17181
  let cachedShellEnv = null;
17163
17182
  function loadUserShellEnv() {
17164
17183
  if (cachedShellEnv?.PATH && !isTransientPath(cachedShellEnv.PATH)) {
@@ -17211,6 +17230,7 @@ function getExpandedPath(shellEnv = loadUserShellEnv()) {
17211
17230
  (0,external_node_path_namespaceObject.join)(home, '.claude', 'bin'),
17212
17231
  pnpmHome,
17213
17232
  ...getNvmBinCandidates(),
17233
+ ...getFnmBinCandidates(),
17214
17234
  ];
17215
17235
  const current = basePath.split(external_node_path_namespaceObject.delimiter).filter(Boolean).map(stabilizeTransientDir);
17216
17236
  const seen = new Set(current);
@@ -17333,6 +17353,7 @@ function getCodexCandidates() {
17333
17353
  (0,external_node_path_namespaceObject.join)(home, '.npm-global', 'bin', 'codex'),
17334
17354
  (0,external_node_path_namespaceObject.join)(home, '.local', 'bin', 'codex'),
17335
17355
  ...getNvmBinCandidates().map((p) => (0,external_node_path_namespaceObject.join)(p, 'codex')),
17356
+ ...getFnmBinCandidates().map((p) => (0,external_node_path_namespaceObject.join)(p, 'codex')),
17336
17357
  ...pnpmHomes.map((p) => (0,external_node_path_namespaceObject.join)(p, 'codex')),
17337
17358
  ];
17338
17359
  }
@@ -18923,6 +18944,36 @@ function runFileBackedAgentTurn(input) {
18923
18944
  output += text;
18924
18945
  onDelta?.(text);
18925
18946
  };
18947
+ const emitTextSnapshot = (text) => {
18948
+ if (!text)
18949
+ return;
18950
+ if (!output) {
18951
+ emitText(text);
18952
+ return;
18953
+ }
18954
+ if (text === output || output.endsWith(text))
18955
+ return;
18956
+ if (text.startsWith(output)) {
18957
+ emitText(text.slice(output.length));
18958
+ return;
18959
+ }
18960
+ const separator = output.endsWith('\n') || text.startsWith('\n') ? '' : '\n\n';
18961
+ emitText(`${separator}${text}`);
18962
+ };
18963
+ const isCodexTextSnapshot = (record) => {
18964
+ if (!record || typeof record !== 'object' || Array.isArray(record))
18965
+ return false;
18966
+ const typedRecord = record;
18967
+ if (typedRecord.type === 'item.completed')
18968
+ return true;
18969
+ if (typedRecord.type !== 'event_msg')
18970
+ return false;
18971
+ const payload = typedRecord.payload;
18972
+ return Boolean(payload &&
18973
+ typeof payload === 'object' &&
18974
+ !Array.isArray(payload) &&
18975
+ payload.type === 'agent_message');
18976
+ };
18926
18977
  const handleStructuredRecord = (record) => {
18927
18978
  sawStructuredOutput = true;
18928
18979
  if (agent === 'claude') {
@@ -18958,12 +19009,10 @@ function runFileBackedAgentTurn(input) {
18958
19009
  const text = readCodexJsonEventText(record);
18959
19010
  if (!text)
18960
19011
  return;
18961
- const isFinalAgentMessage = record &&
18962
- typeof record === 'object' &&
18963
- !Array.isArray(record) &&
18964
- record.type === 'item.completed';
18965
- if (isFinalAgentMessage && output.length > 0)
19012
+ if (isCodexTextSnapshot(record)) {
19013
+ emitTextSnapshot(text);
18966
19014
  return;
19015
+ }
18967
19016
  emitText(text);
18968
19017
  };
18969
19018
  const consumeStructuredStdout = (chunk) => {
@@ -19585,7 +19634,7 @@ function runFileBackedPluginTurn(input, prompt, options, onDelta) {
19585
19634
  }
19586
19635
  //# sourceMappingURL=chat-plugin-runtime.js.map
19587
19636
  ;// CONCATENATED MODULE: ../remosidian-server/dist/version.js
19588
- const VERSION = '0.1.3';
19637
+ const VERSION = '0.1.4';
19589
19638
  //# sourceMappingURL=version.js.map
19590
19639
  ;// CONCATENATED MODULE: ../remosidian-server/dist/chat-runtime.js
19591
19640
 
@@ -19798,6 +19847,22 @@ function resolveAgent(config, agentOverride) {
19798
19847
  }
19799
19848
  return null;
19800
19849
  }
19850
+ /**
19851
+ * Hosted-review mock. When REMOSIDIAN_REVIEW_MOCK=1 the daemon answers chat
19852
+ * requests with a deterministic sample reply instead of spawning a local
19853
+ * Claude/Codex agent — used by the public Fly review daemon so App Store /
19854
+ * TestFlight reviewers can exercise the Ask flow without a real agent or key.
19855
+ */
19856
+ function isReviewMock() {
19857
+ return process.env.REMOSIDIAN_REVIEW_MOCK === '1';
19858
+ }
19859
+ const REVIEW_MOCK_REPLY = [
19860
+ 'This is the hosted Remosidian review demo. The app is connected to a public',
19861
+ 'read-only sample vault so reviewers can try search, file browsing, backlinks,',
19862
+ 'and the Ask flow end to end.',
19863
+ 'For review, answers are deterministic samples and no real AI agent, tools, or',
19864
+ 'commands are run on the server.',
19865
+ ].join(' ');
19801
19866
  class ChatService {
19802
19867
  vaultService;
19803
19868
  config;
@@ -19811,15 +19876,22 @@ class ChatService {
19811
19876
  this.resolved = resolveAgent(config);
19812
19877
  }
19813
19878
  get configured() {
19814
- return this.resolved !== null;
19879
+ return isReviewMock() || this.resolved !== null;
19815
19880
  }
19816
19881
  get agentName() {
19882
+ if (isReviewMock())
19883
+ return this.resolved?.agent ?? 'claude';
19817
19884
  return this.resolved?.agent ?? null;
19818
19885
  }
19819
19886
  get availableAgents() {
19887
+ if (isReviewMock())
19888
+ return ['claude'];
19820
19889
  return ['claude', 'codex'].filter((agent) => Boolean(resolveAgent(this.config, agent)));
19821
19890
  }
19822
19891
  async streamAnswer(options) {
19892
+ if (isReviewMock()) {
19893
+ return this.streamMockAnswer(options);
19894
+ }
19823
19895
  const resolved = options.agent ? resolveAgent(this.config, options.agent) : this.resolved;
19824
19896
  if (!resolved) {
19825
19897
  throw new ChatNotConfiguredError();
@@ -19873,6 +19945,60 @@ class ChatService {
19873
19945
  ...(conversationId ? { sessionId: conversationId } : {}),
19874
19946
  };
19875
19947
  }
19948
+ async streamMockAnswer(options) {
19949
+ const citations = [];
19950
+ const seen = new Set();
19951
+ for (const file of options.contextFiles ?? []) {
19952
+ if (seen.has(file))
19953
+ continue;
19954
+ seen.add(file);
19955
+ citations.push({ path: file });
19956
+ }
19957
+ options.onCitations(citations);
19958
+ const conversationId = options.sessionId ?? this.options.conversationStore?.createConversationId();
19959
+ if (this.options.conversationStore && conversationId) {
19960
+ await this.options.conversationStore.beginTurn({
19961
+ vaultId: options.vaultId,
19962
+ conversationId,
19963
+ question: options.question,
19964
+ agent: 'claude',
19965
+ });
19966
+ }
19967
+ const question = options.question.replace(/\s+/g, ' ').trim();
19968
+ const preview = question.length > 120 ? `${question.slice(0, 117)}...` : question;
19969
+ const text = preview ? `${REVIEW_MOCK_REPLY}\n\nYou asked: "${preview}"` : REVIEW_MOCK_REPLY;
19970
+ // Stream in word-ish chunks so the client renders a natural typing effect.
19971
+ for (const chunk of text.match(/\S+\s*/g) ?? [text]) {
19972
+ if (options.signal.aborted)
19973
+ break;
19974
+ options.onDelta(chunk);
19975
+ await new Promise((resolve) => setTimeout(resolve, 15));
19976
+ }
19977
+ const usage = {
19978
+ inputTokens: Math.max(1, Math.ceil(options.question.length / 4)),
19979
+ outputTokens: Math.max(1, Math.ceil(text.length / 4)),
19980
+ };
19981
+ if (this.options.conversationStore && conversationId) {
19982
+ await this.options.conversationStore.completeTurn({
19983
+ vaultId: options.vaultId,
19984
+ conversationId,
19985
+ answer: text,
19986
+ citations,
19987
+ agent: 'claude',
19988
+ usage,
19989
+ });
19990
+ }
19991
+ else {
19992
+ const history = await this.resolveSessionHistory(options);
19993
+ this.recordSessionTurn(options.sessionId, history, options.question, text);
19994
+ }
19995
+ return {
19996
+ text,
19997
+ citations,
19998
+ usage,
19999
+ ...(conversationId ? { sessionId: conversationId } : {}),
20000
+ };
20001
+ }
19876
20002
  async resolveSessionHistory(options) {
19877
20003
  if (options.history) {
19878
20004
  return options.history;
@@ -20632,7 +20758,7 @@ const _buildClaudeUsageLimitsForTesting = (/* unused pure expression or super */
20632
20758
  const _parseCodexRateLimitsForTesting = (/* unused pure expression or super */ null && (parseCodexRateLimits));
20633
20759
  //# sourceMappingURL=usage-limits.js.map
20634
20760
  ;// CONCATENATED MODULE: ../../packages/markdown-indexer/dist/es/patterns/regex.js
20635
- const TASK_REGEX = /^(\s*)([-*]|\d+\.)\s*\[([ xX-])\]\s+(.*)$/;
20761
+ const TASK_REGEX = /^(\s*)([-*]|\d+\.)\s*\[([^\]\r\n])\]\s+(.*)$/;
20636
20762
  const BULLET_REGEX = /^(\s*)([-*]|\d+\.)\s+(.+)$/;
20637
20763
  const IS_TASK_LINE = /^(\s*)(?:[-*]|\d+\.)\s+\[.\]/;
20638
20764
  const HEADING_REGEX = /^(#{1,6})\s+(.*)$/;
@@ -20907,6 +21033,287 @@ function shouldIgnoreAllTasksInFile(frontmatter) {
20907
21033
  }
20908
21034
 
20909
21035
 
21036
+ ;// CONCATENATED MODULE: ../../packages/type/dist/main.js
21037
+ /**
21038
+ * Main Plugin Type Declarations
21039
+ * Extracted from apps/obsidian-plugin/src/type.ts
21040
+ */
21041
+ var SettingTabList;
21042
+ (function (SettingTabList) {
21043
+ SettingTabList["PERIODIC"] = "Periodic";
21044
+ SettingTabList["THEME"] = "Theme";
21045
+ SettingTabList["CALENDAR"] = "Calendar";
21046
+ SettingTabList["ACTIVATION"] = "Activation";
21047
+ SettingTabList["AI"] = "AI";
21048
+ SettingTabList["AI_MODEL"] = "AI_MODEL";
21049
+ SettingTabList["AI_PROMPT"] = "AI_PROMPT";
21050
+ SettingTabList["MCP_SERVICES"] = "MCP_SERVICES";
21051
+ })(SettingTabList || (SettingTabList = {}));
21052
+ var TaskStatusType;
21053
+ (function (TaskStatusType) {
21054
+ TaskStatusType["DONE"] = "DONE";
21055
+ TaskStatusType["RECORD"] = "RECORD";
21056
+ TaskStatusType["DUE"] = "DUE";
21057
+ })(TaskStatusType || (TaskStatusType = {}));
21058
+ var LogLevel;
21059
+ (function (LogLevel) {
21060
+ LogLevel[LogLevel["info"] = 0] = "info";
21061
+ LogLevel[LogLevel["warn"] = 1] = "warn";
21062
+ LogLevel[LogLevel["error"] = 2] = "error";
21063
+ })(LogLevel || (LogLevel = {}));
21064
+ var EventViewType;
21065
+ (function (EventViewType) {
21066
+ EventViewType["DAY_GRID_DAY"] = "dayGridDay";
21067
+ EventViewType["DAY_GRID_WEEK"] = "dayGridWeek";
21068
+ EventViewType["DAY_GRID_MONTH"] = "dayGridMonth";
21069
+ EventViewType["TIME_GRID_DAY"] = "timeGridDay";
21070
+ EventViewType["TIME_GRID_WEEK"] = "timeGridWeek";
21071
+ EventViewType["NORMAL_LIST"] = "normalList";
21072
+ })(EventViewType || (EventViewType = {}));
21073
+ /**
21074
+ * 默认配置
21075
+ */
21076
+ const DEFAULT_SYNC_CONFIG = {
21077
+ retry: {
21078
+ maxAttempts: 3,
21079
+ baseDelay: 1000,
21080
+ maxDelay: 10000,
21081
+ },
21082
+ cache: {
21083
+ enabled: true,
21084
+ ttl: 5 * 60 * 1000, // 5 minutes
21085
+ },
21086
+ };
21087
+ /**
21088
+ * 默认番茄时钟设置
21089
+ */
21090
+ const main_DEFAULT_POMODORO_SETTINGS = {
21091
+ pomodoroDuration: 25,
21092
+ shortBreakDuration: 5,
21093
+ longBreakDuration: 15,
21094
+ longBreakInterval: 4,
21095
+ autoStartNextPomodoro: false,
21096
+ autoStartBreak: false,
21097
+ autoFocusCount: 0,
21098
+ continueAfterComplete: false,
21099
+ pomodoroNotification: true,
21100
+ pomodoroSound: true,
21101
+ autoRecordToDaily: true,
21102
+ };
21103
+ /**
21104
+ * 默认番茄时钟数据
21105
+ */
21106
+ const DEFAULT_POMODORO_DATA = {
21107
+ version: 1,
21108
+ records: [],
21109
+ };
21110
+
21111
+ ;// CONCATENATED MODULE: ../../packages/type/dist/extension.js
21112
+ /**
21113
+ * Extension (Browser Extension) Type Declarations
21114
+ * Extracted from apps/chrome-extension/src/types/messaging.ts
21115
+ */
21116
+ // Port Names
21117
+ const PORT_NAMES = {
21118
+ CONTENT_PORT: 'CONTENT_PORT',
21119
+ UI_PORT: 'UI_PORT',
21120
+ };
21121
+
21122
+ ;// CONCATENATED MODULE: ../../packages/type/dist/task-status.js
21123
+ const LEGACY_TWO_STATE_TASK_STATUS_DEFINITIONS = [
21124
+ { marker: ' ', name: 'Todo', type: 'TODO', next: 'x' },
21125
+ { marker: 'x', name: 'Done', type: 'DONE', next: ' ' },
21126
+ { marker: '/', name: 'In Progress', type: 'IN_PROGRESS', next: 'x' },
21127
+ { marker: '-', name: 'Cancelled', type: 'CANCELLED', next: ' ' },
21128
+ ];
21129
+ const LEGACY_THREE_STATE_TASK_STATUS_DEFINITIONS = [
21130
+ { marker: ' ', name: 'Todo', type: 'TODO', next: '/' },
21131
+ { marker: '/', name: 'In Progress', type: 'IN_PROGRESS', next: 'x' },
21132
+ { marker: 'x', name: 'Done', type: 'DONE', next: ' ' },
21133
+ { marker: '-', name: 'Cancelled', type: 'CANCELLED', next: ' ' },
21134
+ ];
21135
+ const LEGACY_DEFAULT_TASK_STATUS_DEFINITIONS = (/* unused pure expression or super */ null && (LEGACY_TWO_STATE_TASK_STATUS_DEFINITIONS));
21136
+ const task_status_DEFAULT_TASK_STATUS_DEFINITIONS = [
21137
+ { marker: ' ', name: 'Todo', type: 'TODO', next: 'x' },
21138
+ { marker: 'x', name: 'Done', type: 'DONE', next: ' ' },
21139
+ ];
21140
+ const FULL_TASK_STATUS_DEFINITIONS = [
21141
+ { marker: ' ', name: 'Todo', type: 'TODO', next: '/' },
21142
+ { marker: '/', name: 'In Progress', type: 'IN_PROGRESS', next: 'x' },
21143
+ { marker: 'x', name: 'Done', type: 'DONE', next: ' ' },
21144
+ { marker: '-', name: 'Cancelled', type: 'CANCELLED', next: ' ' },
21145
+ { marker: '>', name: 'Deferred', type: 'TODO', next: 'x' },
21146
+ { marker: '!', name: 'Important', type: 'TODO', next: 'x' },
21147
+ { marker: '?', name: 'Question', type: 'TODO', next: 'x' },
21148
+ { marker: '@', name: 'Commissioned', type: 'TODO', next: 'x' },
21149
+ ];
21150
+ /**
21151
+ * Built-in statuses remain recognizable even when the user's default settings
21152
+ * only expose the simple two-state cycle.
21153
+ */
21154
+ const BUILTIN_TASK_STATUS_DEFINITIONS = [
21155
+ ...FULL_TASK_STATUS_DEFINITIONS,
21156
+ ];
21157
+ function normalizeTaskStatusDefinition(definition) {
21158
+ if (typeof definition.marker !== 'string' || definition.marker.length !== 1) {
21159
+ return null;
21160
+ }
21161
+ const next = typeof definition.next === 'string' && definition.next.length === 1 ? definition.next : undefined;
21162
+ return {
21163
+ ...definition,
21164
+ marker: definition.marker === 'X' ? 'x' : definition.marker,
21165
+ next: next === 'X' ? 'x' : next,
21166
+ };
21167
+ }
21168
+ function normalizeTaskStatusMarker(marker) {
21169
+ if (marker == null || marker === '') {
21170
+ return ' ';
21171
+ }
21172
+ const normalized = marker.slice(0, 1);
21173
+ return normalized === 'X' ? 'x' : normalized;
21174
+ }
21175
+ function getDefinitionByMarker(definitions) {
21176
+ const map = new Map();
21177
+ for (const definition of definitions) {
21178
+ const normalized = normalizeTaskStatusDefinition(definition);
21179
+ if (normalized) {
21180
+ map.set(normalized.marker, normalized);
21181
+ }
21182
+ }
21183
+ return map;
21184
+ }
21185
+ function isLegacyDefaultTaskStatusDefinitions(definitions) {
21186
+ const candidates = [LEGACY_TWO_STATE_TASK_STATUS_DEFINITIONS, LEGACY_THREE_STATE_TASK_STATUS_DEFINITIONS];
21187
+ for (const candidateDefinitions of candidates) {
21188
+ if (!definitions || definitions.length !== candidateDefinitions.length) {
21189
+ continue;
21190
+ }
21191
+ const currentByMarker = getDefinitionByMarker(definitions);
21192
+ if (currentByMarker.size !== candidateDefinitions.length) {
21193
+ continue;
21194
+ }
21195
+ const isMatch = candidateDefinitions.every((legacyDefinition) => {
21196
+ const current = currentByMarker.get(legacyDefinition.marker);
21197
+ const currentNext = typeof current?.next === 'string' ? normalizeTaskStatusMarker(current.next) : legacyDefinition.next;
21198
+ return (current &&
21199
+ current.name === legacyDefinition.name &&
21200
+ current.type === legacyDefinition.type &&
21201
+ currentNext === legacyDefinition.next);
21202
+ });
21203
+ if (isMatch) {
21204
+ return true;
21205
+ }
21206
+ }
21207
+ return false;
21208
+ }
21209
+ function isFullTaskStatusPresetDefinitions(definitions) {
21210
+ if (!definitions || definitions.length !== FULL_TASK_STATUS_DEFINITIONS.length) {
21211
+ return false;
21212
+ }
21213
+ const currentByMarker = getDefinitionByMarker(definitions);
21214
+ if (currentByMarker.size !== FULL_TASK_STATUS_DEFINITIONS.length) {
21215
+ return false;
21216
+ }
21217
+ for (const presetDefinition of FULL_TASK_STATUS_DEFINITIONS) {
21218
+ const current = currentByMarker.get(presetDefinition.marker);
21219
+ const currentNext = typeof current?.next === 'string' ? normalizeTaskStatusMarker(current.next) : presetDefinition.next;
21220
+ if (!current ||
21221
+ current.name !== presetDefinition.name ||
21222
+ current.type !== presetDefinition.type ||
21223
+ currentNext !== presetDefinition.next) {
21224
+ return false;
21225
+ }
21226
+ }
21227
+ return true;
21228
+ }
21229
+ function task_status_migrateLegacyDefaultTaskStatuses(definitions) {
21230
+ if (!isLegacyDefaultTaskStatusDefinitions(definitions)) {
21231
+ return undefined;
21232
+ }
21233
+ const currentByMarker = getDefinitionByMarker(definitions);
21234
+ return task_status_DEFAULT_TASK_STATUS_DEFINITIONS.map((defaultDefinition) => ({
21235
+ ...(currentByMarker.get(defaultDefinition.marker) ?? defaultDefinition),
21236
+ next: defaultDefinition.next,
21237
+ }));
21238
+ }
21239
+ function getTaskStatusDefinitions(definitions) {
21240
+ const merged = new Map();
21241
+ for (const definition of BUILTIN_TASK_STATUS_DEFINITIONS) {
21242
+ const normalized = normalizeTaskStatusDefinition(definition);
21243
+ if (normalized) {
21244
+ merged.set(normalized.marker, normalized);
21245
+ }
21246
+ }
21247
+ for (const definition of task_status_DEFAULT_TASK_STATUS_DEFINITIONS) {
21248
+ const normalized = normalizeTaskStatusDefinition(definition);
21249
+ if (normalized) {
21250
+ merged.set(normalized.marker, normalized);
21251
+ }
21252
+ }
21253
+ for (const definition of definitions ?? []) {
21254
+ const normalized = normalizeTaskStatusDefinition(definition);
21255
+ if (normalized) {
21256
+ merged.set(normalized.marker, normalized);
21257
+ }
21258
+ }
21259
+ return Array.from(merged.values());
21260
+ }
21261
+ function defaultNextForType(type) {
21262
+ if (type === 'DONE' || type === 'CANCELLED')
21263
+ return ' ';
21264
+ return 'x';
21265
+ }
21266
+ function resolveTaskStatus(marker, definitions) {
21267
+ const normalizedMarker = normalizeTaskStatusMarker(marker);
21268
+ const allDefinitions = getTaskStatusDefinitions(definitions);
21269
+ const definition = allDefinitions.find((item) => item.marker === normalizedMarker);
21270
+ const resolvedType = definition?.type ?? 'TODO';
21271
+ const done = resolvedType === 'DONE';
21272
+ const cancelled = resolvedType === 'CANCELLED';
21273
+ const terminal = done || cancelled;
21274
+ return {
21275
+ marker: normalizedMarker,
21276
+ name: definition?.name ?? `Custom ${normalizedMarker.trim() || 'Todo'}`,
21277
+ type: resolvedType,
21278
+ next: normalizeTaskStatusMarker(definition?.next ?? defaultNextForType(resolvedType)),
21279
+ color: definition?.color,
21280
+ icon: definition?.icon,
21281
+ known: Boolean(definition),
21282
+ done,
21283
+ cancelled,
21284
+ terminal,
21285
+ unfinished: !terminal,
21286
+ };
21287
+ }
21288
+ function isDoneTaskStatus(marker, definitions) {
21289
+ return resolveTaskStatus(marker, definitions).done;
21290
+ }
21291
+ function isCancelledTaskStatus(marker, definitions) {
21292
+ return resolveTaskStatus(marker, definitions).cancelled;
21293
+ }
21294
+ function isTerminalTaskStatus(marker, definitions) {
21295
+ return resolveTaskStatus(marker, definitions).terminal;
21296
+ }
21297
+ function getNextTaskStatus(marker, definitions) {
21298
+ return resolveTaskStatus(marker, definitions).next;
21299
+ }
21300
+
21301
+ ;// CONCATENATED MODULE: ../../packages/type/dist/index.js
21302
+ /**
21303
+ * @lifeos/type - Shared Type Declarations for LifeOS Projects
21304
+ */
21305
+ // Re-export all types from domain-specific modules
21306
+
21307
+
21308
+
21309
+
21310
+
21311
+
21312
+
21313
+
21314
+
21315
+
21316
+
20910
21317
  ;// CONCATENATED MODULE: ../../packages/markdown-indexer/dist/es/validators/tag-validator.js
20911
21318
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20912
21319
  function isValidTag(tag) {
@@ -21002,13 +21409,32 @@ function parseTagsFromContent(content) {
21002
21409
 
21003
21410
 
21004
21411
 
21412
+
21005
21413
  function extractPriority(text) {
21006
21414
  if (/⏫/.test(text)) return 'high';
21007
21415
  if (/🔼/.test(text)) return 'medium';
21008
21416
  if (/🔽/.test(text)) return 'low';
21009
21417
  if (/⏬/.test(text)) return 'lowest';
21010
21418
  }
21011
- function parseTasksFromContent(content) {
21419
+ const INLINE_TIME_RANGE_REG = /(?:^|\s)([01]?\d|2[0-3]):([0-5]\d)\s*-\s*([01]?\d|2[0-3]):([0-5]\d)(?=\s|$)/;
21420
+ const INLINE_TIME_RANGE_CLEAN_REG = /(?:^|\s)(?:[01]?\d|2[0-3]):[0-5]\d\s*-\s*(?:[01]?\d|2[0-3]):[0-5]\d(?=\s|$)/g;
21421
+ const BARE_TIMESTAMP_CLEAN_REG = /(?:^|\s)(?:[01]?\d|2[0-3]):[0-5]\d(?=\s|$)/;
21422
+ const TASK_DATE_METADATA_REG = / ?[📅📆🗓➕✅🛫⏳⌛❌] ?\d{4}-\d{2}-\d{2}/gu;
21423
+ function normalizeTime(hours, minutes) {
21424
+ return `${hours.padStart(2, '0')}:${minutes}`;
21425
+ }
21426
+ function extractInlineTimeRange(text) {
21427
+ const match = text.match(INLINE_TIME_RANGE_REG);
21428
+ if (!match) return {};
21429
+ return {
21430
+ startTime: normalizeTime(match[1], match[2]),
21431
+ endTime: normalizeTime(match[3], match[4])
21432
+ };
21433
+ }
21434
+ function cleanTaskText(text) {
21435
+ return text.replace(INLINE_TIME_RANGE_CLEAN_REG, ' ').replace(BARE_TIMESTAMP_CLEAN_REG, ' ').replace(TASK_DATE_METADATA_REG, '').replace(/\s+/g, ' ').trim();
21436
+ }
21437
+ function parseTasksFromContent(content, options = {}) {
21012
21438
  const tasks = [];
21013
21439
  const lines = content.split('\n');
21014
21440
  const frontmatterRange = getFrontmatterLineRange(content);
@@ -21017,27 +21443,35 @@ function parseTasksFromContent(content) {
21017
21443
  const match = TASK_REGEX.exec(lines[i]);
21018
21444
  if (!match) continue;
21019
21445
  const indent = match[1].length;
21020
- const status = match[3];
21021
- const text = match[4];
21022
- const checked = 'x' === status.toLowerCase() || '-' === status;
21023
- const dueMatch = text.match(DUE_REG);
21024
- const doneMatch = text.match(DONE_REG);
21025
- const startMatch = text.match(START_REG);
21026
- const scheduledMatch = text.match(SCHEDULED_REG);
21027
- const recurrenceMatch = text.match(regex_RECURRENCE_REG);
21446
+ const status = 'X' === match[3] ? 'x' : match[3];
21447
+ const resolvedStatus = resolveTaskStatus(status, options.taskStatuses);
21448
+ const originalText = match[4];
21449
+ const checked = resolvedStatus.terminal;
21450
+ const dueMatch = originalText.match(DUE_REG);
21451
+ const doneMatch = originalText.match(DONE_REG);
21452
+ const startMatch = originalText.match(START_REG);
21453
+ const scheduledMatch = originalText.match(SCHEDULED_REG);
21454
+ const recurrenceMatch = originalText.match(regex_RECURRENCE_REG);
21455
+ const timeRange = extractInlineTimeRange(originalText);
21456
+ const text = cleanTaskText(originalText);
21028
21457
  tasks.push({
21029
21458
  text,
21030
21459
  checked,
21031
21460
  status,
21461
+ statusType: resolvedStatus.type,
21462
+ statusName: resolvedStatus.name,
21463
+ nextStatus: resolvedStatus.next,
21032
21464
  indent,
21033
21465
  line: i,
21034
- due: dueMatch?.[1],
21466
+ due: dueMatch?.[1] ?? (startMatch || scheduledMatch ? void 0 : doneMatch?.[1]),
21035
21467
  done: doneMatch?.[1],
21036
21468
  start: startMatch?.[1],
21037
21469
  scheduled: scheduledMatch?.[1],
21470
+ startTime: timeRange.startTime,
21471
+ endTime: timeRange.endTime,
21038
21472
  recurrence: recurrenceMatch ? parseRecurrenceRuleText(recurrenceMatch[1]) : void 0,
21039
- tags: extractInlineTags(text),
21040
- priority: extractPriority(text),
21473
+ tags: extractInlineTags(originalText),
21474
+ priority: extractPriority(originalText),
21041
21475
  content: lines[i]
21042
21476
  });
21043
21477
  }
@@ -21217,8 +21651,8 @@ function enrichTasksFlat(parsedTasks, headings, path) {
21217
21651
  section: section?.text,
21218
21652
  sectionLine: section?.line,
21219
21653
  children: [],
21220
- blockId: extractBlockId(t.text),
21221
- completed: t.checked,
21654
+ blockId: extractBlockId(t.content ?? t.text),
21655
+ completed: 'DONE' === t.statusType,
21222
21656
  content: t.content,
21223
21657
  lineCount: 1
21224
21658
  };
@@ -21262,11 +21696,11 @@ function enrichMixed(parsedTasks, parsedBullets, headings, path) {
21262
21696
 
21263
21697
 
21264
21698
 
21265
- function parseFileToIndex(content, path, mtime) {
21699
+ function parseFileToIndex(content, path, mtime, options = {}) {
21266
21700
  const frontmatter = parseFrontmatter(content);
21267
21701
  const frontmatterKeys = Object.keys(frontmatter);
21268
21702
  const headings = parseHeadings(content);
21269
- const parsedTasks = shouldIgnoreAllTasksInFile(frontmatter) ? [] : parseTasksFromContent(content);
21703
+ const parsedTasks = shouldIgnoreAllTasksInFile(frontmatter) ? [] : parseTasksFromContent(content, options);
21270
21704
  const parsedBullets = parseBulletsFromContent(content);
21271
21705
  const { tasks, bullets } = enrichMixed(parsedTasks, parsedBullets, headings, path);
21272
21706
  const tags = parseTagsFromContent(content);
@@ -21792,108 +22226,7 @@ function useDebounceSubmit(callback, delay = 300) {
21792
22226
  return { submit };
21793
22227
  }
21794
22228
 
21795
- ;// CONCATENATED MODULE: ../../packages/type/dist/main.js
21796
- /**
21797
- * Main Plugin Type Declarations
21798
- * Extracted from apps/obsidian-plugin/src/type.ts
21799
- */
21800
- var SettingTabList;
21801
- (function (SettingTabList) {
21802
- SettingTabList["PERIODIC"] = "Periodic";
21803
- SettingTabList["THEME"] = "Theme";
21804
- SettingTabList["CALENDAR"] = "Calendar";
21805
- SettingTabList["ACTIVATION"] = "Activation";
21806
- SettingTabList["AI"] = "AI";
21807
- SettingTabList["AI_MODEL"] = "AI_MODEL";
21808
- SettingTabList["AI_PROMPT"] = "AI_PROMPT";
21809
- SettingTabList["MCP_SERVICES"] = "MCP_SERVICES";
21810
- })(SettingTabList || (SettingTabList = {}));
21811
- var TaskStatusType;
21812
- (function (TaskStatusType) {
21813
- TaskStatusType["DONE"] = "DONE";
21814
- TaskStatusType["RECORD"] = "RECORD";
21815
- TaskStatusType["DUE"] = "DUE";
21816
- })(TaskStatusType || (TaskStatusType = {}));
21817
- var LogLevel;
21818
- (function (LogLevel) {
21819
- LogLevel[LogLevel["info"] = 0] = "info";
21820
- LogLevel[LogLevel["warn"] = 1] = "warn";
21821
- LogLevel[LogLevel["error"] = 2] = "error";
21822
- })(LogLevel || (LogLevel = {}));
21823
- var EventViewType;
21824
- (function (EventViewType) {
21825
- EventViewType["DAY_GRID_DAY"] = "dayGridDay";
21826
- EventViewType["DAY_GRID_WEEK"] = "dayGridWeek";
21827
- EventViewType["DAY_GRID_MONTH"] = "dayGridMonth";
21828
- EventViewType["TIME_GRID_DAY"] = "timeGridDay";
21829
- EventViewType["TIME_GRID_WEEK"] = "timeGridWeek";
21830
- EventViewType["NORMAL_LIST"] = "normalList";
21831
- })(EventViewType || (EventViewType = {}));
21832
- /**
21833
- * 默认配置
21834
- */
21835
- const DEFAULT_SYNC_CONFIG = {
21836
- retry: {
21837
- maxAttempts: 3,
21838
- baseDelay: 1000,
21839
- maxDelay: 10000,
21840
- },
21841
- cache: {
21842
- enabled: true,
21843
- ttl: 5 * 60 * 1000, // 5 minutes
21844
- },
21845
- };
21846
- /**
21847
- * 默认番茄时钟设置
21848
- */
21849
- const main_DEFAULT_POMODORO_SETTINGS = {
21850
- pomodoroDuration: 25,
21851
- shortBreakDuration: 5,
21852
- longBreakDuration: 15,
21853
- longBreakInterval: 4,
21854
- autoStartNextPomodoro: false,
21855
- autoStartBreak: false,
21856
- autoFocusCount: 0,
21857
- continueAfterComplete: false,
21858
- pomodoroNotification: true,
21859
- pomodoroSound: true,
21860
- autoRecordToDaily: true,
21861
- };
21862
- /**
21863
- * 默认番茄时钟数据
21864
- */
21865
- const DEFAULT_POMODORO_DATA = {
21866
- version: 1,
21867
- records: [],
21868
- };
21869
-
21870
- ;// CONCATENATED MODULE: ../../packages/type/dist/extension.js
21871
- /**
21872
- * Extension (Browser Extension) Type Declarations
21873
- * Extracted from apps/chrome-extension/src/types/messaging.ts
21874
- */
21875
- // Port Names
21876
- const PORT_NAMES = {
21877
- CONTENT_PORT: 'CONTENT_PORT',
21878
- UI_PORT: 'UI_PORT',
21879
- };
21880
-
21881
- ;// CONCATENATED MODULE: ../../packages/type/dist/index.js
21882
- /**
21883
- * @lifeos/type - Shared Type Declarations for LifeOS Projects
21884
- */
21885
- // Re-export all types from domain-specific modules
21886
-
21887
-
21888
-
21889
-
21890
-
21891
-
21892
-
21893
-
21894
-
21895
-
21896
- ;// CONCATENATED MODULE: ../../packages/shared/dist/usePomodoro.js
22229
+ ;// CONCATENATED MODULE: ../../packages/shared/dist/usePomodoro.js
21897
22230
  /**
21898
22231
  * Pomodoro Timer Core Hook (shared)
21899
22232
  * Manages timer state, countdown/stopwatch logic
@@ -23748,6 +24081,7 @@ function getStem(filePath) {
23748
24081
 
23749
24082
 
23750
24083
 
24084
+
23751
24085
  function buildThemeHeaderRegex(config) {
23752
24086
  if (!config.themeHeaderPattern) {
23753
24087
  return null;
@@ -23791,7 +24125,7 @@ function normalizeSectionHeader(value) {
23791
24125
  .replace(/\s+/g, ' ')
23792
24126
  .trim();
23793
24127
  }
23794
- function parseHabitSectionItems(content, habitHeader) {
24128
+ function parseHabitSectionItems(content, habitHeader, taskStatuses) {
23795
24129
  const normalizedHabitHeader = normalizeSectionHeader(habitHeader);
23796
24130
  if (!normalizedHabitHeader) {
23797
24131
  return [];
@@ -23823,16 +24157,28 @@ function parseHabitSectionItems(content, habitHeader) {
23823
24157
  }
23824
24158
  const indent = listMatch[1].length;
23825
24159
  const rest = listMatch[3];
23826
- const taskMatch = /^\[( |x|X)\]\s+(.*)/.exec(rest);
24160
+ const taskMatch = /^\[([^\]\r\n])\]\s+(.*)/.exec(rest);
23827
24161
  const isTask = !!taskMatch;
23828
- const checked = taskMatch ? taskMatch[1].toLowerCase() === 'x' : false;
24162
+ const resolvedStatus = taskMatch ? resolveTaskStatus(taskMatch[1], taskStatuses) : undefined;
24163
+ const checked = resolvedStatus?.terminal ?? false;
23829
24164
  const text = taskMatch ? taskMatch[2] : rest;
23830
24165
  while (indentStack.length > 0 && indentStack[indentStack.length - 1].indent >= indent) {
23831
24166
  indentStack.pop();
23832
24167
  }
23833
24168
  const parent = indentStack.length > 0 ? indentStack[indentStack.length - 1].line : null;
23834
24169
  const lineNumber = index + 1;
23835
- items.push({ line: lineNumber, indent, text, isTask, checked, parent });
24170
+ items.push({
24171
+ line: lineNumber,
24172
+ indent,
24173
+ text,
24174
+ isTask,
24175
+ checked,
24176
+ status: resolvedStatus?.marker,
24177
+ statusType: resolvedStatus?.type,
24178
+ statusName: resolvedStatus?.name,
24179
+ nextStatus: resolvedStatus?.next,
24180
+ parent,
24181
+ });
23836
24182
  indentStack.push({ indent, line: lineNumber });
23837
24183
  }
23838
24184
  return items;
@@ -23898,9 +24244,95 @@ function parseThemes(content, themeHeaderRegex) {
23898
24244
  }
23899
24245
  return { themes, themeTimeMap, themeTotalTime };
23900
24246
  }
24247
+ function normalizeLine(line) {
24248
+ return line + 1;
24249
+ }
24250
+ function isMarkdownIndexedTask(item) {
24251
+ return 'checked' in item;
24252
+ }
24253
+ function mapIndexedChildren(children, normalizedFilePath) {
24254
+ const mapped = (children ?? []).map((child) => mapIndexedChild(child, normalizedFilePath));
24255
+ return mapped.length > 0 ? mapped : undefined;
24256
+ }
24257
+ function mapIndexedChild(item, normalizedFilePath) {
24258
+ const common = {
24259
+ file: normalizedFilePath,
24260
+ line: normalizeLine(item.line),
24261
+ text: item.text,
24262
+ section: item.section,
24263
+ tags: item.tags,
24264
+ indent: item.indent,
24265
+ parent: item.parent === undefined ? undefined : normalizeLine(item.parent),
24266
+ children: mapIndexedChildren(item.children, normalizedFilePath),
24267
+ };
24268
+ if (isMarkdownIndexedTask(item)) {
24269
+ return {
24270
+ ...common,
24271
+ isTask: true,
24272
+ checked: item.checked,
24273
+ status: item.status,
24274
+ statusType: item.statusType,
24275
+ statusName: item.statusName,
24276
+ nextStatus: item.nextStatus,
24277
+ blockId: item.blockId,
24278
+ startDate: item.start,
24279
+ dueDate: item.due,
24280
+ completionDate: item.done,
24281
+ startTime: item.startTime,
24282
+ endTime: item.endTime,
24283
+ recurrence: item.recurrence,
24284
+ priority: item.priority,
24285
+ };
24286
+ }
24287
+ return {
24288
+ ...common,
24289
+ isTask: false,
24290
+ };
24291
+ }
24292
+ function mapIndexedTask(task, normalizedFilePath) {
24293
+ return {
24294
+ file: normalizedFilePath,
24295
+ line: normalizeLine(task.line),
24296
+ text: task.text,
24297
+ checked: task.checked,
24298
+ status: task.status,
24299
+ statusType: task.statusType,
24300
+ statusName: task.statusName,
24301
+ nextStatus: task.nextStatus,
24302
+ blockId: task.blockId,
24303
+ startDate: task.start,
24304
+ dueDate: task.due,
24305
+ completionDate: task.done,
24306
+ startTime: task.startTime,
24307
+ endTime: task.endTime,
24308
+ recurrence: task.recurrence,
24309
+ section: task.section,
24310
+ tags: task.tags,
24311
+ indent: task.indent,
24312
+ parent: task.parent === undefined ? undefined : normalizeLine(task.parent),
24313
+ children: mapIndexedChildren(task.children, normalizedFilePath),
24314
+ isTask: true,
24315
+ priority: task.priority,
24316
+ };
24317
+ }
24318
+ function mapIndexedBullet(bullet, normalizedFilePath) {
24319
+ return {
24320
+ file: normalizedFilePath,
24321
+ line: normalizeLine(bullet.line),
24322
+ text: bullet.text,
24323
+ section: bullet.section,
24324
+ tags: bullet.tags,
24325
+ indent: bullet.indent,
24326
+ parent: bullet.parent === undefined ? undefined : normalizeLine(bullet.parent),
24327
+ children: mapIndexedChildren(bullet.children, normalizedFilePath),
24328
+ isTask: false,
24329
+ };
24330
+ }
23901
24331
  function parseLifeOSFileContent(content, filePath, mtime, config) {
23902
24332
  const normalizedFilePath = path_normalizePath(filePath);
23903
- const indexed = markdownIndexerRuntime_parseFileToIndex(content, normalizedFilePath, mtime);
24333
+ const indexed = markdownIndexerRuntime_parseFileToIndex(content, normalizedFilePath, mtime, {
24334
+ taskStatuses: config.taskStatuses,
24335
+ });
23904
24336
  const themeHeaderRegex = buildThemeHeaderRegex(config);
23905
24337
  const { themes, themeTimeMap, themeTotalTime } = parseThemes(content, themeHeaderRegex);
23906
24338
  return {
@@ -23916,30 +24348,9 @@ function parseLifeOSFileContent(content, filePath, mtime, config) {
23916
24348
  themeTotalTime,
23917
24349
  frontmatterKeys: indexed.frontmatterKeys,
23918
24350
  frontmatterValues: parseFrontmatterValues(indexed.frontmatter),
23919
- habitItems: parseHabitSectionItems(content, config.habitHeader),
23920
- tasks: indexed.tasks.map((task) => ({
23921
- file: normalizedFilePath,
23922
- line: task.line + 1,
23923
- text: task.text,
23924
- checked: task.checked,
23925
- blockId: task.blockId,
23926
- startDate: task.start,
23927
- dueDate: task.due,
23928
- completionDate: task.done,
23929
- recurrence: task.recurrence,
23930
- section: task.section,
23931
- tags: task.tags,
23932
- indent: task.indent,
23933
- priority: task.priority,
23934
- })),
23935
- bullets: indexed.bullets.map((bullet) => ({
23936
- file: normalizedFilePath,
23937
- line: bullet.line + 1,
23938
- text: bullet.text,
23939
- section: bullet.section,
23940
- tags: bullet.tags,
23941
- indent: bullet.indent,
23942
- })),
24351
+ habitItems: parseHabitSectionItems(content, config.habitHeader, config.taskStatuses),
24352
+ tasks: indexed.tasks.map((task) => mapIndexedTask(task, normalizedFilePath)),
24353
+ bullets: indexed.bullets.map((bullet) => mapIndexedBullet(bullet, normalizedFilePath)),
23943
24354
  basename: getBasename(normalizedFilePath),
23944
24355
  basenameNoExt: getStem(normalizedFilePath).toLowerCase(),
23945
24356
  dirname: getDirname(normalizedFilePath),
@@ -24667,11 +25078,7 @@ function addDays(dateStr, days) {
24667
25078
  return date.toISOString().slice(0, 10);
24668
25079
  }
24669
25080
  function getTaskDateGroup(task) {
24670
- if (task.checked)
24671
- return 'done';
24672
- const statusMatch = task.text.match(/^\[([ x\-/])\]/i);
24673
- const status = statusMatch?.[1]?.toLowerCase();
24674
- if (status === 'x' || status === '-') {
25081
+ if (task.statusType === 'DONE' || task.statusType === 'CANCELLED' || task.checked) {
24675
25082
  return 'done';
24676
25083
  }
24677
25084
  const dueDate = task.dueDate;
@@ -25046,6 +25453,522 @@ function internal_helpers_appendToSection(content, header, block) {
25046
25453
  return lines.join('\n');
25047
25454
  }
25048
25455
 
25456
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/defaults/calendar-display.js
25457
+
25458
+ function calendar_display_createCalendarDisplayDefaults() {
25459
+ return {
25460
+ useCalendar: true,
25461
+ useCalendarSidebar: true,
25462
+ useCalendarAllDay: false,
25463
+ useCalendarCollapse: false,
25464
+ useCalendar24Hour: false,
25465
+ useCalendarSimpleTaskDisplay: false,
25466
+ taskStatuses: DEFAULT_TASK_STATUS_DEFINITIONS.map((definition)=>({
25467
+ ...definition
25468
+ })),
25469
+ hideRemoteTasksInUnfinished: false,
25470
+ taskDelayDays: 7,
25471
+ weekStart: -1,
25472
+ taskFilterRules: {
25473
+ headers: [],
25474
+ paths: [],
25475
+ tags: [],
25476
+ contents: [],
25477
+ mode: 'exclude'
25478
+ },
25479
+ taskFilterDateRange: {},
25480
+ useTagColor: false,
25481
+ tagColors: {}
25482
+ };
25483
+ }
25484
+
25485
+
25486
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/defaults/periodic.js
25487
+ function periodic_createPeriodicDefaults() {
25488
+ return {
25489
+ usePeriodicNotes: true,
25490
+ periodicNotesPath: 'PeriodicNotes',
25491
+ dailyRecordHeader: 'Daily Record',
25492
+ habitHeader: 'Habit',
25493
+ projectListHeader: 'Project List',
25494
+ areaListHeader: 'First Things Dimension',
25495
+ themeListHeader: 'Theme List',
25496
+ useDailyRecordTimestamp: false,
25497
+ useChineseCalendar: false,
25498
+ usePeriodicAdvanced: false,
25499
+ periodicNotesTemplateFilePathDaily: '',
25500
+ periodicNotesTemplateFilePathWeekly: '',
25501
+ periodicNotesTemplateFilePathMonthly: '',
25502
+ periodicNotesTemplateFilePathQuarterly: '',
25503
+ periodicNotesTemplateFilePathYearly: '',
25504
+ periodicNotesPathFormatDaily: '',
25505
+ periodicNotesPathFormatWeekly: '',
25506
+ periodicNotesPathFormatMonthly: '',
25507
+ periodicNotesPathFormatQuarterly: '',
25508
+ periodicNotesPathFormatYearly: ''
25509
+ };
25510
+ }
25511
+
25512
+
25513
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/defaults/index.js
25514
+
25515
+
25516
+
25517
+
25518
+
25519
+ function createSharedDefaults(options = {}) {
25520
+ const { ai } = options;
25521
+ return {
25522
+ ...createAIDefaults(ai),
25523
+ ...createCalendarDisplayDefaults(),
25524
+ ...createRemoteCalendarDefaults(),
25525
+ ...createPeriodicDefaults(),
25526
+ ...createThemeDefaults()
25527
+ };
25528
+ }
25529
+
25530
+
25531
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/template-filters.js
25532
+
25533
+ const PERIODIC_DEFAULTS = periodic_createPeriodicDefaults();
25534
+ function normalizeTemplatePath(value) {
25535
+ return (value || '').replace(/\\/g, '/').trim();
25536
+ }
25537
+ function isTemplatePathList(value) {
25538
+ return Array.isArray(value);
25539
+ }
25540
+ function getTemplatePaths(settings) {
25541
+ const periodicNotesPath = normalizeTemplatePath(settings.periodicNotesPath) || PERIODIC_DEFAULTS.periodicNotesPath;
25542
+ return [
25543
+ 'Template.md',
25544
+ `${periodicNotesPath}/Templates`,
25545
+ settings.projectsTemplateFilePath,
25546
+ settings.themesTemplateFilePath,
25547
+ settings.areasTemplateFilePath,
25548
+ settings.resourcesTemplateFilePath,
25549
+ settings.archivesTemplateFilePath,
25550
+ settings.periodicNotesTemplateFilePathYearly,
25551
+ settings.periodicNotesTemplateFilePathQuarterly,
25552
+ settings.periodicNotesTemplateFilePathMonthly,
25553
+ settings.periodicNotesTemplateFilePathWeekly,
25554
+ settings.periodicNotesTemplateFilePathDaily
25555
+ ].map((templatePath)=>normalizeTemplatePath(templatePath)).filter(Boolean);
25556
+ }
25557
+ function template_filters_isTemplateFilePath(filePath, settingsOrTemplatePaths) {
25558
+ const normalizedFilePath = normalizeTemplatePath(filePath);
25559
+ if (!normalizedFilePath) return false;
25560
+ const templatePaths = isTemplatePathList(settingsOrTemplatePaths) ? settingsOrTemplatePaths : getTemplatePaths(settingsOrTemplatePaths);
25561
+ return templatePaths.some((templatePath)=>normalizedFilePath.includes(templatePath));
25562
+ }
25563
+
25564
+
25565
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/templates.js
25566
+ const BUILT_IN_PERIODIC_TEMPLATE_COPY = {
25567
+ en: {
25568
+ dailyRecordHeader: 'Daily Record',
25569
+ projectListHeader: 'Project List',
25570
+ tasksHeader: 'Tasks',
25571
+ reviewHeader: 'Review',
25572
+ goalsHeader: 'Goals',
25573
+ weeklyLead: 'Plan your weekly tasks.',
25574
+ monthlyLead: 'Plan your monthly tasks.',
25575
+ quarterlyLead: 'Set your quarterly goals.',
25576
+ yearlyLead: 'Set your yearly goals.'
25577
+ },
25578
+ 'zh-cn': {
25579
+ dailyRecordHeader: '日常记录',
25580
+ projectListHeader: '项目列表',
25581
+ tasksHeader: '任务',
25582
+ reviewHeader: '复盘',
25583
+ goalsHeader: '目标',
25584
+ weeklyLead: '安排周度任务。',
25585
+ monthlyLead: '安排月度任务。',
25586
+ quarterlyLead: '制定季度目标。',
25587
+ yearlyLead: '制定年度目标。'
25588
+ },
25589
+ 'zh-tw': {
25590
+ dailyRecordHeader: '日常記錄',
25591
+ projectListHeader: '專案列表',
25592
+ tasksHeader: '任務',
25593
+ reviewHeader: '回顧',
25594
+ goalsHeader: '目標',
25595
+ weeklyLead: '安排每週任務。',
25596
+ monthlyLead: '安排每月任務。',
25597
+ quarterlyLead: '設定季度目標。',
25598
+ yearlyLead: '設定年度目標。'
25599
+ }
25600
+ };
25601
+ const BUILT_IN_THEME_TEMPLATE = (/* unused pure expression or super */ null && (`---
25602
+ tags:
25603
+ - {{tags}}
25604
+ type: theme
25605
+ ---
25606
+
25607
+ # {{title}}
25608
+
25609
+ ## Overview
25610
+
25611
+
25612
+
25613
+ ## Related Notes
25614
+
25615
+ `));
25616
+ function normalizeBuiltInTemplateLocale(locale) {
25617
+ const normalized = locale?.trim().toLowerCase().replace(/_/g, '-');
25618
+ if (!normalized) return 'en';
25619
+ if (normalized.startsWith('zh-tw') || normalized.startsWith('zh-hk') || normalized.startsWith('zh-mo') || normalized.startsWith('zh-hant')) return 'zh-tw';
25620
+ if (normalized.startsWith('zh')) return 'zh-cn';
25621
+ return 'en';
25622
+ }
25623
+ function getBuiltInPeriodicTemplateCopy(locale, copy) {
25624
+ return {
25625
+ ...BUILT_IN_PERIODIC_TEMPLATE_COPY[normalizeBuiltInTemplateLocale(locale)],
25626
+ ...copy ?? {}
25627
+ };
25628
+ }
25629
+ function ensureHeading(raw, level = 2) {
25630
+ return /^#+\s/.test(raw) ? raw : `${'#'.repeat(level)} ${raw}`;
25631
+ }
25632
+ function configuredText(value) {
25633
+ const trimmed = value?.trim();
25634
+ return trimmed ? trimmed : null;
25635
+ }
25636
+ function joinTemplateBlocks(blocks) {
25637
+ return `${blocks.filter(Boolean).join('\n\n')}\n`;
25638
+ }
25639
+ function buildBuiltInPeriodicTemplate(options) {
25640
+ const { type, config, locale, copy: copyOverride } = options;
25641
+ const copy = getBuiltInPeriodicTemplateCopy(locale, copyOverride);
25642
+ const dailyHeader = ensureHeading(configuredText(config?.dailyRecordHeader) ?? copy.dailyRecordHeader);
25643
+ const projectListHeader = ensureHeading(configuredText(config?.projectListHeader) ?? copy.projectListHeader);
25644
+ const tasksHeader = ensureHeading(copy.tasksHeader);
25645
+ const reviewHeader = ensureHeading(copy.reviewHeader);
25646
+ const goalsHeader = ensureHeading(copy.goalsHeader);
25647
+ const themeOn = config?.useThemeNotes !== false;
25648
+ const seed = '- ';
25649
+ switch(type){
25650
+ case 'Daily':
25651
+ {
25652
+ const blocks = [
25653
+ '# {{title}}'
25654
+ ];
25655
+ if (themeOn) blocks.push(`${projectListHeader}\n\n<% snapshot("project") %>`);
25656
+ blocks.push(`${dailyHeader}\n\n${seed}`);
25657
+ return joinTemplateBlocks(blocks);
25658
+ }
25659
+ case 'Weekly':
25660
+ return joinTemplateBlocks([
25661
+ '# {{title}}',
25662
+ `> ${copy.weeklyLead}`,
25663
+ `${tasksHeader}\n\n${seed}`,
25664
+ `${reviewHeader}\n\n${seed}`
25665
+ ]);
25666
+ case 'Monthly':
25667
+ return joinTemplateBlocks([
25668
+ '# {{title}}',
25669
+ `> ${copy.monthlyLead}`,
25670
+ `${tasksHeader}\n\n${seed}`,
25671
+ `${reviewHeader}\n\n${seed}`
25672
+ ]);
25673
+ case 'Quarterly':
25674
+ {
25675
+ const goalsBody = themeOn ? '<% snapshot("area") %>' : seed;
25676
+ return joinTemplateBlocks([
25677
+ '# {{title}}',
25678
+ `> ${copy.quarterlyLead}`,
25679
+ `${goalsHeader}\n\n${goalsBody}`,
25680
+ `${reviewHeader}\n\n${seed}`
25681
+ ]);
25682
+ }
25683
+ case 'Yearly':
25684
+ {
25685
+ const goalsBody = themeOn ? '<% snapshot("area") %>' : seed;
25686
+ return joinTemplateBlocks([
25687
+ '# {{title}}',
25688
+ `> ${copy.yearlyLead}`,
25689
+ `${goalsHeader}\n\n${goalsBody}`,
25690
+ `${reviewHeader}\n\n${seed}`
25691
+ ]);
25692
+ }
25693
+ }
25694
+ }
25695
+ function getPathBasename(filePath) {
25696
+ const normalized = filePath.replace(/\\/g, '/').replace(/\/+$/g, '');
25697
+ if (!normalized) return filePath;
25698
+ const slashIndex = normalized.lastIndexOf('/');
25699
+ return slashIndex >= 0 ? normalized.slice(slashIndex + 1) : normalized;
25700
+ }
25701
+ function templates_buildBuiltInThemeTemplate(tag) {
25702
+ const tagName = tag.replace(/^#/, '');
25703
+ const title = getPathBasename(tagName) || tagName;
25704
+ return BUILT_IN_THEME_TEMPLATE.split('{{tags}}').join(tagName).split('{{title}}').join(title);
25705
+ }
25706
+
25707
+
25708
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/validation/index.js
25709
+
25710
+ function hasConfiguredAIVendor(settings) {
25711
+ if (settings.useGPT && settings.gptApiKey) return true;
25712
+ if (settings.useClaude && settings.claudeApiKey) return true;
25713
+ if (settings.useDeepSeek && settings.deepseekApiKey) return true;
25714
+ if (settings.useQwen && settings.qwenApiKey) return true;
25715
+ if (settings.useOllama && settings.ollamaBaseURL) return true;
25716
+ if (settings.customAIModels?.some((m)=>m.apiKey && m.baseURL)) return true;
25717
+ return false;
25718
+ }
25719
+ const FIELD_RENAMES = (/* unused pure expression or super */ null && ([
25720
+ [
25721
+ 'googleCalendarSelectedCalendar',
25722
+ 'googleCalendarSelectedCalendarId'
25723
+ ],
25724
+ [
25725
+ 'maxConversationTurns',
25726
+ 'aiMaxConversationTurns'
25727
+ ]
25728
+ ]));
25729
+ const OBSOLETE_FIELDS = (/* unused pure expression or super */ null && ([
25730
+ 'deepSeekApiKey',
25731
+ 'deepSeekBaseURL',
25732
+ 'deepSeekModel'
25733
+ ]));
25734
+ function migrateFieldNames(settings) {
25735
+ let changed = false;
25736
+ for (const [oldKey, newKey] of FIELD_RENAMES)if (oldKey in settings && !(newKey in settings)) {
25737
+ settings[newKey] = settings[oldKey];
25738
+ delete settings[oldKey];
25739
+ changed = true;
25740
+ }
25741
+ return changed;
25742
+ }
25743
+ function removeObsoleteKeys(settings) {
25744
+ let changed = false;
25745
+ for (const key of OBSOLETE_FIELDS)if (key in settings) {
25746
+ delete settings[key];
25747
+ changed = true;
25748
+ }
25749
+ return changed;
25750
+ }
25751
+ function migrateTaskStatuses(settings) {
25752
+ const migrated = migrateLegacyDefaultTaskStatuses(settings.taskStatuses);
25753
+ if (!migrated) return false;
25754
+ settings.taskStatuses = migrated;
25755
+ return true;
25756
+ }
25757
+
25758
+
25759
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/ai/presentation.js
25760
+ const CONTEXT_AI_SETTINGS_VENDORS = (/* unused pure expression or super */ null && ([
25761
+ 'claude-code',
25762
+ 'codex',
25763
+ 'claude',
25764
+ 'gpt',
25765
+ 'gemini',
25766
+ 'deepseek',
25767
+ 'qwen',
25768
+ 'minimax',
25769
+ 'zhipu',
25770
+ 'kimi',
25771
+ 'ollama',
25772
+ 'custom'
25773
+ ]));
25774
+ const AI_SETTINGS_VENDOR_METADATA = {
25775
+ gpt: {
25776
+ name: 'GPT',
25777
+ apiKeyPlaceholder: 'sk-...',
25778
+ apiKeyLink: 'https://platform.openai.com/api-keys'
25779
+ },
25780
+ gemini: {
25781
+ name: 'Gemini',
25782
+ apiKeyPlaceholder: 'API Key...',
25783
+ apiKeyLink: 'https://aistudio.google.com/app/apikey'
25784
+ },
25785
+ claude: {
25786
+ name: 'Claude',
25787
+ apiKeyPlaceholder: 'sk-ant-...',
25788
+ apiKeyLink: 'https://console.anthropic.com/settings/keys'
25789
+ },
25790
+ deepseek: {
25791
+ name: 'DeepSeek',
25792
+ apiKeyPlaceholder: 'sk-...',
25793
+ apiKeyLink: 'https://platform.deepseek.com/api_keys'
25794
+ },
25795
+ qwen: {
25796
+ name: 'Qwen',
25797
+ apiKeyPlaceholder: 'sk-...',
25798
+ apiKeyLink: 'https://dashscope.console.aliyun.com/apiKey'
25799
+ },
25800
+ minimax: {
25801
+ name: 'MiniMax',
25802
+ apiKeyPlaceholder: 'eyJ...',
25803
+ apiKeyLink: 'https://platform.minimaxi.com/user-center/basic-information/interface-key'
25804
+ },
25805
+ zhipu: {
25806
+ name: 'Zhipu',
25807
+ apiKeyPlaceholder: 'sk-...',
25808
+ apiKeyLink: 'https://open.bigmodel.cn/usercenter/apikeys'
25809
+ },
25810
+ kimi: {
25811
+ name: 'Kimi (Moonshot)',
25812
+ apiKeyPlaceholder: 'sk-...',
25813
+ apiKeyLink: 'https://platform.moonshot.cn/console/api-keys'
25814
+ },
25815
+ ollama: {
25816
+ name: 'Ollama',
25817
+ apiKeyPlaceholder: ''
25818
+ },
25819
+ custom: {
25820
+ name: 'Custom',
25821
+ apiKeyPlaceholder: 'Enter API key...'
25822
+ },
25823
+ 'claude-code': {
25824
+ name: 'Claude Code',
25825
+ apiKeyPlaceholder: ''
25826
+ },
25827
+ codex: {
25828
+ name: 'Codex',
25829
+ apiKeyPlaceholder: ''
25830
+ }
25831
+ };
25832
+ const SELECT_MODEL_PLACEHOLDER_KEYS = {
25833
+ gpt: 'AI_GPT_SELECT_MODEL',
25834
+ gemini: 'AI_GEMINI_SELECT_MODEL',
25835
+ claude: 'AI_CLAUDE_SELECT_MODEL',
25836
+ deepseek: 'AI_DEEPSEEK_SELECT_MODEL',
25837
+ qwen: 'AI_QWEN_SELECT_MODEL',
25838
+ minimax: 'AI_MINIMAX_SELECT_MODEL',
25839
+ zhipu: 'AI_ZHIPU_SELECT_MODEL',
25840
+ kimi: 'AI_KIMI_SELECT_MODEL',
25841
+ ollama: 'AI_OLLAMA_SELECT_MODEL'
25842
+ };
25843
+ const AI_MODEL_SUGGESTIONS = {
25844
+ claude: [
25845
+ 'claude-sonnet-4-5-20250929',
25846
+ 'claude-opus-4-5-20250929',
25847
+ 'claude-haiku-4-5-20250929',
25848
+ 'claude-3-5-sonnet-20241022',
25849
+ 'claude-3-5-haiku-20241022',
25850
+ 'claude-3-opus-20240229'
25851
+ ],
25852
+ deepseek: [
25853
+ 'deepseek-chat',
25854
+ 'deepseek-reasoner'
25855
+ ],
25856
+ qwen: [
25857
+ 'qwen3-coder-plus',
25858
+ 'qwen3-coder-flash',
25859
+ 'qwen3-max',
25860
+ 'qwen3-plus',
25861
+ 'qwen3-flash'
25862
+ ],
25863
+ minimax: [
25864
+ 'MiniMax-M2.7',
25865
+ 'MiniMax-M2.7-highspeed',
25866
+ 'MiniMax-M2.5',
25867
+ 'MiniMax-M2.5-highspeed',
25868
+ 'MiniMax-M2.1',
25869
+ 'MiniMax-M2.1-highspeed',
25870
+ 'MiniMax-M2'
25871
+ ],
25872
+ zhipu: [
25873
+ 'glm-4-plus',
25874
+ 'glm-4-flash',
25875
+ 'glm-4-long',
25876
+ 'glm-4',
25877
+ 'glm-3-turbo'
25878
+ ],
25879
+ kimi: [
25880
+ 'moonshot-v1-auto',
25881
+ 'moonshot-v1-128k',
25882
+ 'moonshot-v1-32k',
25883
+ 'moonshot-v1-8k'
25884
+ ]
25885
+ };
25886
+ function getMessage(messages, key) {
25887
+ return messages[key] ?? '';
25888
+ }
25889
+ function buildAIValidationMessages(messages) {
25890
+ return {
25891
+ API_KEY_CANNOT_BE_EMPTY: getMessage(messages, 'API_KEY_CANNOT_BE_EMPTY'),
25892
+ API_KEY_VALIDATION_SUCCESS: getMessage(messages, 'API_KEY_VALIDATION_SUCCESS'),
25893
+ API_KEY_VALIDATION_FAILED: getMessage(messages, 'API_KEY_VALIDATION_FAILED'),
25894
+ API_KEY_VALIDATION_FAILED_GENERAL: getMessage(messages, 'API_KEY_VALIDATION_FAILED_GENERAL'),
25895
+ API_KEY_INVALID_OR_EXPIRED: getMessage(messages, 'API_KEY_INVALID_OR_EXPIRED'),
25896
+ API_KEY_INSUFFICIENT_PERMISSIONS: getMessage(messages, 'API_KEY_INSUFFICIENT_PERMISSIONS'),
25897
+ API_KEY_RATE_LIMIT_EXCEEDED: getMessage(messages, 'API_KEY_RATE_LIMIT_EXCEEDED'),
25898
+ API_KEY_ENDPOINT_NOT_FOUND: getMessage(messages, 'API_KEY_ENDPOINT_NOT_FOUND'),
25899
+ API_KEY_VALIDATION_ERROR: getMessage(messages, 'API_KEY_VALIDATION_ERROR')
25900
+ };
25901
+ }
25902
+ function buildAIVendorConfigMessages(messages, validationMessages = buildAIValidationMessages(messages)) {
25903
+ return {
25904
+ validation: validationMessages,
25905
+ AI_BASE_URL: getMessage(messages, 'AI_BASE_URL'),
25906
+ AI_API_KEY: getMessage(messages, 'AI_API_KEY'),
25907
+ AI_GET_API_KEY: getMessage(messages, 'AI_GET_API_KEY'),
25908
+ AI_DOCS: getMessage(messages, 'AI_DOCS'),
25909
+ AI_MODELS: getMessage(messages, 'AI_MODELS'),
25910
+ AI_MODEL: getMessage(messages, 'AI_MODEL'),
25911
+ AI_MODEL_HELP: getMessage(messages, 'AI_MODEL_HELP'),
25912
+ API_KEY_VALIDATE: getMessage(messages, 'API_KEY_VALIDATE'),
25913
+ API_KEY_VALIDATE_TOOLTIP: getMessage(messages, 'API_KEY_VALIDATE_TOOLTIP'),
25914
+ API_KEY_ENTER_FIRST: getMessage(messages, 'API_KEY_ENTER_FIRST'),
25915
+ AI_OLLAMA_API_KEY_OPTIONAL: messages.AI_OLLAMA_API_KEY_OPTIONAL ?? messages['AI_OLLAMA_API_KEY_OPTIONAL'],
25916
+ AI_OLLAMA_API_KEY_PLACEHOLDER: messages.AI_OLLAMA_API_KEY_PLACEHOLDER ?? messages['AI_OLLAMA_API_KEY_PLACEHOLDER']
25917
+ };
25918
+ }
25919
+ function buildCustomAIModelMessages(messages, validationMessages = buildAIValidationMessages(messages)) {
25920
+ return {
25921
+ validation: validationMessages,
25922
+ AI_CUSTOM_MODELS: getMessage(messages, 'AI_CUSTOM_MODELS'),
25923
+ AI_CUSTOM_MODELS_HELP: getMessage(messages, 'AI_CUSTOM_MODELS_HELP'),
25924
+ AI_CUSTOM_MODEL_VENDOR: getMessage(messages, 'AI_CUSTOM_MODEL_VENDOR'),
25925
+ AI_CUSTOM_MODEL_VENDOR_HELP: getMessage(messages, 'AI_CUSTOM_MODEL_VENDOR_HELP'),
25926
+ AI_BASE_URL: getMessage(messages, 'AI_BASE_URL'),
25927
+ AI_BASE_URL_HELP: getMessage(messages, 'AI_BASE_URL_HELP'),
25928
+ AI_CUSTOM_MODEL_API_KEY: getMessage(messages, 'AI_CUSTOM_MODEL_API_KEY'),
25929
+ AI_API_KEY_HELP: getMessage(messages, 'AI_API_KEY_HELP'),
25930
+ AI_MODEL: getMessage(messages, 'AI_MODEL'),
25931
+ AI_MODEL_HELP: getMessage(messages, 'AI_MODEL_HELP'),
25932
+ SELECT_OR_INPUT_MODEL_NAME: getMessage(messages, 'SELECT_OR_INPUT_MODEL_NAME'),
25933
+ AI_ADD_CUSTOM_MODEL: getMessage(messages, 'AI_ADD_CUSTOM_MODEL'),
25934
+ AI_REMOVE_CUSTOM_MODEL: getMessage(messages, 'AI_REMOVE_CUSTOM_MODEL'),
25935
+ API_KEY_ENTER_FIRST: getMessage(messages, 'API_KEY_ENTER_FIRST'),
25936
+ API_KEY_VALIDATE: getMessage(messages, 'API_KEY_VALIDATE'),
25937
+ API_KEY_VALIDATE_TOOLTIP: getMessage(messages, 'API_KEY_VALIDATE_TOOLTIP')
25938
+ };
25939
+ }
25940
+ function createAISettingsPresentation(messages) {
25941
+ const validationMessages = buildAIValidationMessages(messages);
25942
+ return {
25943
+ validationMessages,
25944
+ vendorMessages: buildAIVendorConfigMessages(messages, validationMessages),
25945
+ customModelMessages: buildCustomAIModelMessages(messages, validationMessages)
25946
+ };
25947
+ }
25948
+ function getAISelectModelPlaceholder(messages, vendorId) {
25949
+ const typedVendorId = vendorId;
25950
+ const placeholderKey = SELECT_MODEL_PLACEHOLDER_KEYS[typedVendorId];
25951
+ if (placeholderKey) {
25952
+ const vendorPlaceholder = messages[placeholderKey];
25953
+ if (vendorPlaceholder) return vendorPlaceholder;
25954
+ }
25955
+ return messages.AI_SELECT_MODEL || `Select ${AI_SETTINGS_VENDOR_METADATA[typedVendorId]?.name ?? vendorId} Model`;
25956
+ }
25957
+ function getAIModelSuggestions(vendorId) {
25958
+ const typedVendorId = vendorId;
25959
+ return [
25960
+ ...AI_MODEL_SUGGESTIONS[typedVendorId] ?? []
25961
+ ];
25962
+ }
25963
+
25964
+
25965
+ ;// CONCATENATED MODULE: ../../packages/settings-core/dist/es/index.js
25966
+
25967
+
25968
+
25969
+
25970
+
25971
+
25049
25972
  ;// CONCATENATED MODULE: ../../packages/template-engine/dist/processors/conditional.js
25050
25973
 
25051
25974
  /**
@@ -25197,12 +26120,47 @@ class engine_TemplateEngine {
25197
26120
 
25198
26121
 
25199
26122
 
25200
- // EXTERNAL MODULE: ../../node_modules/dayjs/dayjs.min.js
25201
- var dayjs_dayjs_min = __nccwpck_require__(9646);
25202
- // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/isoWeek.js
25203
- var isoWeek = __nccwpck_require__(564);
25204
- // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/quarterOfYear.js
25205
- var plugin_quarterOfYear = __nccwpck_require__(2149);
26123
+ ;// CONCATENATED MODULE: ../../packages/vault-lifeos-service/dist/daily-notes-core.js
26124
+
26125
+
26126
+ const DAILY_NOTES_CONFIG_PATH = '.obsidian/daily-notes.json';
26127
+ const DEFAULT_DAILY_NOTES_FORMAT = 'YYYY-MM-DD';
26128
+ function isRecord(value) {
26129
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
26130
+ }
26131
+ function normalizeDailyNotesPath(value) {
26132
+ if (typeof value !== 'string') {
26133
+ return '';
26134
+ }
26135
+ return value
26136
+ .trim()
26137
+ .replace(/\\/g, '/')
26138
+ .replace(/^\/+|\/+$/g, '')
26139
+ .replace(/\/{2,}/g, '/');
26140
+ }
26141
+ async function daily_notes_core_getObsidianDailyNotesCoreSettings(vaultRoot) {
26142
+ let parsed;
26143
+ try {
26144
+ parsed = JSON.parse(await readFile(join(vaultRoot, DAILY_NOTES_CONFIG_PATH), 'utf8'));
26145
+ }
26146
+ catch {
26147
+ return null;
26148
+ }
26149
+ if (!isRecord(parsed)) {
26150
+ return null;
26151
+ }
26152
+ const config = parsed;
26153
+ const folder = normalizeDailyNotesPath(config.folder);
26154
+ const template = normalizeDailyNotesPath(config.template);
26155
+ const format = typeof config.format === 'string' && config.format.trim() ? config.format.trim() : DEFAULT_DAILY_NOTES_FORMAT;
26156
+ return {
26157
+ folder,
26158
+ format,
26159
+ template,
26160
+ source: DAILY_NOTES_CONFIG_PATH,
26161
+ };
26162
+ }
26163
+
25206
26164
  ;// CONCATENATED MODULE: ../../packages/vault-lifeos-service/dist/templates.js
25207
26165
  // Template-aware note creation for the headless CLI.
25208
26166
  //
@@ -25222,10 +26180,6 @@ var plugin_quarterOfYear = __nccwpck_require__(2149);
25222
26180
 
25223
26181
 
25224
26182
 
25225
-
25226
-
25227
- dayjs_dayjs_min.extend(isoWeek);
25228
- dayjs_dayjs_min.extend(plugin_quarterOfYear);
25229
26183
  const SNAPSHOT_DIR_KEYS = {
25230
26184
  project: 'projectsPath',
25231
26185
  area: 'areasPath',
@@ -25304,59 +26258,21 @@ function createCliTemplateEngine(root, settings) {
25304
26258
  });
25305
26259
  return engine;
25306
26260
  }
25307
- function periodicTitle(periodType, date) {
25308
- const d = dayjs(date);
25309
- switch (periodType) {
25310
- case 'Weekly':
25311
- return `${d.isoWeekYear()}-W${String(d.isoWeek()).padStart(2, '0')}`;
25312
- case 'Monthly':
25313
- return d.format('YYYY-MM');
25314
- case 'Quarterly':
25315
- return d.format('YYYY-[Q]Q');
25316
- case 'Yearly':
25317
- return d.format('YYYY');
25318
- default:
25319
- return d.format('YYYY-MM-DD');
25320
- }
25321
- }
25322
26261
  /** Built-in fallback when no template file exists (mirrors the plugin's default). */
25323
- function defaultPeriodicTemplate(periodType, date, settings) {
25324
- const d = dayjs(date);
25325
- const rawHeader = settings.dailyRecordHeader || 'Daily Record';
25326
- const recordHeader = /^#+\s/.test(rawHeader) ? rawHeader : `## ${rawHeader}`;
25327
- return `---
25328
- type: periodic
25329
- period: ${periodType.toLowerCase()}
25330
- date: ${d.format('YYYY-MM-DD')}
25331
- ---
25332
-
25333
- # ${periodicTitle(periodType, date)}
25334
-
25335
- ${recordHeader}
25336
-
25337
- - [ ]
25338
-
25339
- `;
26262
+ function defaultPeriodicTemplate(periodType, settings) {
26263
+ const themeNotesSetting = settings.useThemeNotes;
26264
+ return buildSharedBuiltInPeriodicTemplate({
26265
+ type: periodType,
26266
+ config: {
26267
+ dailyRecordHeader: settings.dailyRecordHeader,
26268
+ projectListHeader: settings.projectListHeader,
26269
+ useThemeNotes: themeNotesSetting,
26270
+ },
26271
+ });
25340
26272
  }
25341
26273
  /** Built-in fallback theme template (mirrors the plugin's default). */
25342
26274
  function defaultThemeTemplate(tag) {
25343
- const tagName = tag.replace(/^#/, '');
25344
- const displayName = tagName.split('/').pop() || tagName;
25345
- return `---
25346
- tags:
25347
- - ${tagName}
25348
- type: theme
25349
- ---
25350
-
25351
- # ${displayName}
25352
-
25353
- ## Overview
25354
-
25355
-
25356
-
25357
- ## Related Notes
25358
-
25359
- `;
26275
+ return buildBuiltInThemeTemplate(tag);
25360
26276
  }
25361
26277
  /** Inject a tag into the note's frontmatter `tags`/`aliases` (mirrors the plugin). */
25362
26278
  function addTagToFrontmatter(content, tag) {
@@ -25394,7 +26310,10 @@ function addTagToFrontmatter(content, tag) {
25394
26310
  const tagsString = tags.join(' ');
25395
26311
  return `${fm}\n${restContent}`.replace(/<%\s*tp\.frontmatter\.tags\s*%>/g, tagsString);
25396
26312
  }
25397
- function resolvePeriodicTemplatePath(settings, periodType) {
26313
+ function resolvePeriodicTemplatePath(settings, periodType, dailyNotesCoreSettings) {
26314
+ if (periodType === 'Daily' && dailyNotesCoreSettings?.template) {
26315
+ return dailyNotesCoreSettings.template;
26316
+ }
25398
26317
  const custom = settings[`periodicNotesTemplateFilePath${periodType}`];
25399
26318
  if (custom)
25400
26319
  return custom;
@@ -25412,12 +26331,12 @@ async function readTemplateOr(cwd, templatePath, fallback) {
25412
26331
  try {
25413
26332
  const { content } = await readVaultLifeOSFile(cwd, templatePath);
25414
26333
  if (content.trim())
25415
- return content;
26334
+ return { content, usedTemplate: true };
25416
26335
  }
25417
26336
  catch {
25418
26337
  // template file missing — use the built-in default
25419
26338
  }
25420
- return fallback();
26339
+ return { content: fallback(), usedTemplate: false };
25421
26340
  }
25422
26341
  function baseName(relPath) {
25423
26342
  return (relPath.split('/').pop() ?? relPath).replace(/\.(md|markdown)$/i, '');
@@ -25428,9 +26347,9 @@ function baseName(relPath) {
25428
26347
  */
25429
26348
  async function createPeriodicNoteFromTemplate(cwd, periodType, relPath, date, options = {}) {
25430
26349
  const { root, settings } = await getVaultLifeOSSettings(cwd);
25431
- const templatePath = resolvePeriodicTemplatePath(settings, periodType);
25432
- const usedTemplate = existsSync(join(root, templatePath));
25433
- const raw = await readTemplateOr(cwd, templatePath, () => defaultPeriodicTemplate(periodType, date, settings));
26350
+ const dailyNotesCoreSettings = periodType === 'Daily' ? await getObsidianDailyNotesCoreSettings(root) : null;
26351
+ const templatePath = resolvePeriodicTemplatePath(settings, periodType, dailyNotesCoreSettings);
26352
+ const { content: raw, usedTemplate } = await readTemplateOr(cwd, templatePath, () => defaultPeriodicTemplate(periodType, settings));
25434
26353
  const engine = createCliTemplateEngine(root, settings);
25435
26354
  const content = await engine.process(raw, {
25436
26355
  date,
@@ -25448,8 +26367,7 @@ async function createPeriodicNoteFromTemplate(cwd, periodType, relPath, date, op
25448
26367
  async function createThemeNoteFromTemplate(cwd, type, tag, relPath, options = {}) {
25449
26368
  const { root, settings } = await getVaultLifeOSSettings(cwd);
25450
26369
  const templatePath = resolveThemeTemplatePath(settings, type);
25451
- const usedTemplate = existsSync(join(root, templatePath));
25452
- const raw = await readTemplateOr(cwd, templatePath, () => defaultThemeTemplate(tag));
26370
+ const { content: raw, usedTemplate } = await readTemplateOr(cwd, templatePath, () => defaultThemeTemplate(tag));
25453
26371
  const engine = createCliTemplateEngine(root, settings);
25454
26372
  let content = await engine.process(raw, {
25455
26373
  date: new Date(),
@@ -25572,7 +26490,7 @@ const MAX_INDEXED_MARKDOWN_FILES = 10000;
25572
26490
  const METADATA_RECHECK_MS = 3000;
25573
26491
  const indexCacheByRoot = new Map();
25574
26492
  const pendingIndexBuilds = new Map();
25575
- function isRecord(value) {
26493
+ function dist_isRecord(value) {
25576
26494
  return Boolean(value && typeof value === 'object' && !Array.isArray(value));
25577
26495
  }
25578
26496
  function normalizeVaultRoot(cwd) {
@@ -25612,7 +26530,7 @@ async function readJsonRecord(filePath) {
25612
26530
  try {
25613
26531
  const raw = await (0,external_node_fs_promises_namespaceObject.readFile)(filePath, 'utf8');
25614
26532
  const parsed = JSON.parse(raw);
25615
- return isRecord(parsed) ? parsed : null;
26533
+ return dist_isRecord(parsed) ? parsed : null;
25616
26534
  }
25617
26535
  catch {
25618
26536
  return null;
@@ -25882,7 +26800,7 @@ function normalizeStringArray(value) {
25882
26800
  return strings.length > 0 ? strings : [];
25883
26801
  }
25884
26802
  function normalizeTaskFilters(value) {
25885
- if (!isRecord(value)) {
26803
+ if (!dist_isRecord(value)) {
25886
26804
  return undefined;
25887
26805
  }
25888
26806
  const filters = {};
@@ -25973,7 +26891,7 @@ async function searchVaultLifeOSFiles(cwd, query = '', limit = 20) {
25973
26891
  });
25974
26892
  return result.items
25975
26893
  .filter((item) => {
25976
- if (!isRecord(item))
26894
+ if (!dist_isRecord(item))
25977
26895
  return false;
25978
26896
  return typeof item.path === 'string' && typeof item.name === 'string' && typeof item.mtime === 'number';
25979
26897
  })
@@ -25992,7 +26910,7 @@ async function searchVaultLifeOSTags(cwd, query = '', limit = 20) {
25992
26910
  });
25993
26911
  return result.items
25994
26912
  .filter((item) => {
25995
- if (!isRecord(item))
26913
+ if (!dist_isRecord(item))
25996
26914
  return false;
25997
26915
  return typeof item.tag === 'string' && typeof item.count === 'number';
25998
26916
  })
@@ -26163,6 +27081,7 @@ async function dist_createVaultLifeOSFile(cwd, file, content = '', options = {})
26163
27081
  // Template-aware note creation (periodic + theme notes via @lifeos/template-engine).
26164
27082
 
26165
27083
 
27084
+
26166
27085
  ;// CONCATENATED MODULE: ../remosidian-server/dist/vault.js
26167
27086
 
26168
27087
 
@@ -27383,6 +28302,7 @@ function createRemosidianServer(options = {}) {
27383
28302
  root: vault.root,
27384
28303
  })),
27385
28304
  pairedDevices: pairings.pairedCount(),
28305
+ wsClients: webSocketServer.clients.size,
27386
28306
  uptimeSeconds: Math.round((Date.now() - startedAt) / 1000),
27387
28307
  ai: chatService.configured
27388
28308
  ? {
@@ -27398,11 +28318,27 @@ function createRemosidianServer(options = {}) {
27398
28318
  },
27399
28319
  };
27400
28320
  };
28321
+ const legacyToken = options.legacyToken ?? process.env.REMOSIDIAN_LEGACY_TOKEN ?? '';
28322
+ // Hosted-review pairing knobs (mirror Vibelet's review deploy). A window of
28323
+ // 0 means "never expires" (~10 years); reusable lets multiple review devices
28324
+ // pair off the same code; the legacy token doubles as a restart-proof review
28325
+ // pairing credential. All default to normal behavior when unset.
28326
+ const TEN_YEARS_MS = 10 * 365.25 * 24 * 3_600_000;
28327
+ const envPairWindowMs = Number(process.env.REMOSIDIAN_PAIR_WINDOW_MS);
28328
+ const pairWindowMs = Number.isFinite(envPairWindowMs)
28329
+ ? envPairWindowMs === 0
28330
+ ? TEN_YEARS_MS
28331
+ : envPairWindowMs
28332
+ : undefined;
28333
+ const pairReusable = process.env.REMOSIDIAN_PAIR_REUSABLE === '1';
27401
28334
  const pairingHttp = createPairingHttpHandler({
27402
28335
  identity,
27403
28336
  pairings,
27404
28337
  getAdvertisedConnectionTarget,
27405
28338
  payloadType: 'remosidian-pair',
28339
+ ...(pairWindowMs !== undefined ? { pairWindowMs } : {}),
28340
+ pairReusable,
28341
+ ...(legacyToken ? { reviewToken: legacyToken } : {}),
27406
28342
  extras: () => ({
27407
28343
  runtime: hostRuntime,
27408
28344
  vaults: config.vaults.map((vault) => ({
@@ -27411,7 +28347,6 @@ function createRemosidianServer(options = {}) {
27411
28347
  })),
27412
28348
  }),
27413
28349
  });
27414
- const legacyToken = options.legacyToken ?? process.env.REMOSIDIAN_LEGACY_TOKEN ?? '';
27415
28350
  const httpServer = (0,external_node_http_namespaceObject.createServer)((req, res) => {
27416
28351
  void (async () => {
27417
28352
  const url = new URL(req.url ?? '/', 'http://localhost');