@aurora-foundation/obsidian-next 0.4.7 → 0.4.9

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 (232) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +628 -190
  3. package/README.md +23 -9
  4. package/dist/auditLog-6WDBDNYL.js +8 -0
  5. package/dist/auditLog-HGPVDSDC.js +8 -0
  6. package/dist/auditLog-TDIKFBM4.js +8 -0
  7. package/dist/auditLog-XC2KY3ZZ.js +8 -0
  8. package/dist/chunk-2I235WNB.js +133 -0
  9. package/dist/chunk-2JWDGXTR.js +42 -0
  10. package/dist/chunk-2NOB6W2B.js +133 -0
  11. package/dist/chunk-3LFKVKKL.js +7199 -0
  12. package/dist/chunk-3U6WHPDX.js +4695 -0
  13. package/dist/chunk-3UCL6RYE.js +7272 -0
  14. package/dist/chunk-4GN2UQLI.js +130 -0
  15. package/dist/chunk-4MW33MZD.js +516 -0
  16. package/dist/chunk-4PUJBUKZ.js +4716 -0
  17. package/dist/chunk-4QHK6H6O.js +130 -0
  18. package/dist/chunk-55CQIHCO.js +133 -0
  19. package/dist/chunk-5LWINFWI.js +676 -0
  20. package/dist/chunk-5OKGLNQW.js +439 -0
  21. package/dist/chunk-5T6ETZEO.js +6183 -0
  22. package/dist/chunk-5WGIFUVL.js +4234 -0
  23. package/dist/chunk-66EW47T3.js +4237 -0
  24. package/dist/chunk-6TXUOTT2.js +581 -0
  25. package/dist/chunk-6YUYSYDA.js +130 -0
  26. package/dist/chunk-74VPNFMX.js +133 -0
  27. package/dist/chunk-77CGJRGV.js +6188 -0
  28. package/dist/chunk-7DS3VT4C.js +7135 -0
  29. package/dist/chunk-7FHX3VBT.js +133 -0
  30. package/dist/chunk-7MHF56YU.js +6178 -0
  31. package/dist/chunk-ABLPMV7G.js +133 -0
  32. package/dist/chunk-B77K6OQZ.js +687 -0
  33. package/dist/chunk-BKOXH66O.js +133 -0
  34. package/dist/chunk-BPP76UN2.js +130 -0
  35. package/dist/chunk-C4D56GRC.js +5936 -0
  36. package/dist/chunk-CCDPY4WE.js +370 -0
  37. package/dist/chunk-CHNVBJN3.js +7272 -0
  38. package/dist/chunk-CKBZI576.js +7229 -0
  39. package/dist/chunk-CW5HBSJ2.js +7198 -0
  40. package/dist/chunk-DGHDJEY7.js +133 -0
  41. package/dist/chunk-DPNIQWKZ.js +439 -0
  42. package/dist/chunk-DU4T3V2T.js +214 -0
  43. package/dist/chunk-DV3WFKNB.js +4679 -0
  44. package/dist/chunk-DZI2OVN2.js +516 -0
  45. package/dist/chunk-E45VILML.js +7198 -0
  46. package/dist/chunk-ECEUUYXC.js +7199 -0
  47. package/dist/chunk-EJRRSHPW.js +685 -0
  48. package/dist/chunk-EMBMLZFE.js +370 -0
  49. package/dist/chunk-EPG5V5OO.js +285 -0
  50. package/dist/chunk-F2R4HXXW.js +130 -0
  51. package/dist/chunk-FK6N66ES.js +581 -0
  52. package/dist/chunk-G3CZKGYA.js +197 -0
  53. package/dist/chunk-GUUPG4A7.js +7111 -0
  54. package/dist/chunk-HBAAUGUN.js +7230 -0
  55. package/dist/chunk-HHFJMK2Q.js +6177 -0
  56. package/dist/chunk-HINRQTCZ.js +196 -0
  57. package/dist/chunk-HRKJ3R2U.js +288 -0
  58. package/dist/chunk-HWVK4CVE.js +439 -0
  59. package/dist/chunk-JEYSADNZ.js +581 -0
  60. package/dist/chunk-JNEIL7UN.js +4252 -0
  61. package/dist/chunk-JTWSK277.js +676 -0
  62. package/dist/chunk-K4CHTTCJ.js +942 -0
  63. package/dist/chunk-K7R5KUDS.js +4695 -0
  64. package/dist/chunk-KNJFOURE.js +7151 -0
  65. package/dist/chunk-KY22FIT3.js +7256 -0
  66. package/dist/chunk-L2OTIJSF.js +4228 -0
  67. package/dist/chunk-LEEBUHP6.js +4655 -0
  68. package/dist/chunk-LK7UP2T7.js +130 -0
  69. package/dist/chunk-LPGNO3PK.js +284 -0
  70. package/dist/chunk-LYQYJMWS.js +133 -0
  71. package/dist/chunk-MBYFJXR3.js +130 -0
  72. package/dist/chunk-N3WX44L3.js +130 -0
  73. package/dist/chunk-N6AQWES3.js +6197 -0
  74. package/dist/chunk-NW4XSTQZ.js +130 -0
  75. package/dist/chunk-NWG2XURH.js +130 -0
  76. package/dist/chunk-O3GF3LJD.js +6142 -0
  77. package/dist/chunk-OHP5LD3Y.js +6188 -0
  78. package/dist/chunk-P5PQSFZT.js +6182 -0
  79. package/dist/chunk-PAADOWNP.js +130 -0
  80. package/dist/chunk-PERGND7L.js +7213 -0
  81. package/dist/chunk-PWA7V4XX.js +179 -0
  82. package/dist/chunk-QGCWEP6L.js +7111 -0
  83. package/dist/chunk-QVT2IHNJ.js +175 -0
  84. package/dist/chunk-QZNGYPMS.js +6161 -0
  85. package/dist/chunk-R6P2E2ZQ.js +207 -0
  86. package/dist/chunk-ROSDMGIL.js +4679 -0
  87. package/dist/chunk-RQZP7IKG.js +196 -0
  88. package/dist/chunk-RUQSPX3U.js +133 -0
  89. package/dist/chunk-S3BYHP5M.js +130 -0
  90. package/dist/chunk-S6GNETVE.js +438 -0
  91. package/dist/chunk-SDT2ZE2R.js +133 -0
  92. package/dist/chunk-SHQBXJFC.js +6166 -0
  93. package/dist/chunk-TJNISYTE.js +42 -0
  94. package/dist/chunk-TJW74HFF.js +130 -0
  95. package/dist/chunk-TPP72DTK.js +7096 -0
  96. package/dist/chunk-UOESII6R.js +42 -0
  97. package/dist/chunk-UWEDGLYJ.js +6142 -0
  98. package/dist/chunk-V5FYNAFX.js +133 -0
  99. package/dist/chunk-VPURF6UT.js +7198 -0
  100. package/dist/chunk-VQH6LWIZ.js +6184 -0
  101. package/dist/chunk-VS22YVX6.js +7111 -0
  102. package/dist/chunk-VSF5KBW7.js +367 -0
  103. package/dist/chunk-VV3JMCKY.js +214 -0
  104. package/dist/chunk-W5L7HOE3.js +133 -0
  105. package/dist/chunk-WFEVQISK.js +676 -0
  106. package/dist/chunk-WJZPSCEP.js +516 -0
  107. package/dist/chunk-WLV4MKEF.js +16 -0
  108. package/dist/chunk-WSEVQFFI.js +5428 -0
  109. package/dist/chunk-X7N2RNR3.js +5428 -0
  110. package/dist/chunk-XKZNMRNO.js +133 -0
  111. package/dist/chunk-Y7BVEC36.js +130 -0
  112. package/dist/chunk-YG7YSNNU.js +4226 -0
  113. package/dist/chunk-YHM62466.js +261 -0
  114. package/dist/chunk-YLTYJLDZ.js +7208 -0
  115. package/dist/chunk-YPMJD4YE.js +56 -0
  116. package/dist/chunk-YTX3FU2A.js +7199 -0
  117. package/dist/chunk-ZEQ3EBBN.js +214 -0
  118. package/dist/chunk-ZIWLQSLK.js +42 -0
  119. package/dist/chunk-ZJELNTEO.js +516 -0
  120. package/dist/chunk-ZOSSVNGK.js +370 -0
  121. package/dist/config-EYK32F2E.js +10 -0
  122. package/dist/config-FJPPPYTY.js +10 -0
  123. package/dist/config-VAHPVILX.js +10 -0
  124. package/dist/context-2YGE4U75.js +10 -0
  125. package/dist/context-5UFVYKES.js +9 -0
  126. package/dist/context-ANZF4J72.js +10 -0
  127. package/dist/context-GLUNCUBQ.js +10 -0
  128. package/dist/context-M5ULPZKQ.js +10 -0
  129. package/dist/context-NYOIRZKV.js +10 -0
  130. package/dist/context-YP2REI6A.js +10 -0
  131. package/dist/database-MP2JBLMF.js +8 -0
  132. package/dist/index.js +6177 -4688
  133. package/dist/keyManager-P2SZONKE.js +8 -0
  134. package/dist/mcp/index.js +127 -47
  135. package/dist/memory-BPGJAL4J.js +13 -0
  136. package/dist/memory-FRQOUI6W.js +13 -0
  137. package/dist/memory-OAMK27IZ.js +13 -0
  138. package/dist/memory-OZ734ALL.js +13 -0
  139. package/dist/memory-PQ2EWRMU.js +13 -0
  140. package/dist/memory-PXL45M6W.js +13 -0
  141. package/dist/memory-QZTBTYPH.js +13 -0
  142. package/dist/migrations-TLJ3WRVW.js +188 -0
  143. package/dist/resume-2NHDK6EI.js +17 -0
  144. package/dist/resume-44L2PDB2.js +17 -0
  145. package/dist/resume-4MXIWUJO.js +7 -0
  146. package/dist/resume-72VJX66I.js +17 -0
  147. package/dist/resume-7ZW4XM3B.js +15 -0
  148. package/dist/resume-AZHYQ657.js +17 -0
  149. package/dist/resume-CNLXSYHV.js +17 -0
  150. package/dist/resume-DPN4Q777.js +16 -0
  151. package/dist/resume-DSFHVNPI.js +15 -0
  152. package/dist/resume-GHLQJJTO.js +17 -0
  153. package/dist/resume-HJ6SBWTF.js +17 -0
  154. package/dist/resume-HRLYHY2L.js +17 -0
  155. package/dist/resume-ISIQFKO6.js +17 -0
  156. package/dist/resume-JQDEA6PS.js +15 -0
  157. package/dist/resume-KP3Y3Y7P.js +17 -0
  158. package/dist/resume-M4KHR5OI.js +17 -0
  159. package/dist/resume-N62OAMBG.js +17 -0
  160. package/dist/resume-NNMA5POT.js +17 -0
  161. package/dist/resume-ODYT3J4H.js +17 -0
  162. package/dist/resume-PCFJXA5O.js +17 -0
  163. package/dist/resume-PLF4XGBD.js +15 -0
  164. package/dist/resume-Q2PFX57V.js +17 -0
  165. package/dist/resume-QB4XI2J5.js +17 -0
  166. package/dist/resume-R5MFTUPF.js +17 -0
  167. package/dist/resume-SVA7223Z.js +17 -0
  168. package/dist/resume-TYKKDJZI.js +17 -0
  169. package/dist/resume-XIS45HKV.js +17 -0
  170. package/dist/resume-YCSEJTU7.js +17 -0
  171. package/dist/resume-YD76GI2J.js +15 -0
  172. package/dist/resume-YDN7EL77.js +17 -0
  173. package/dist/resume-YE7DB4ZA.js +17 -0
  174. package/dist/resume-YKAKOXWV.js +15 -0
  175. package/dist/resume-ZHBCVFDY.js +17 -0
  176. package/dist/scheduler-2CK24A2Q.js +14 -0
  177. package/dist/scheduler-7OAF2XKX.js +14 -0
  178. package/dist/scheduler-AS23AAB5.js +14 -0
  179. package/dist/scheduler-PCOYQJA5.js +14 -0
  180. package/dist/scheduler-V2ECBQPK.js +14 -0
  181. package/dist/scheduler-VEWZ6L7V.js +13 -0
  182. package/dist/scheduler-W37QMGDQ.js +14 -0
  183. package/dist/session-2E2JKPD7.js +15 -0
  184. package/dist/session-2VSF257B.js +14 -0
  185. package/dist/session-4APFTDJU.js +14 -0
  186. package/dist/session-5YS5LNNL.js +16 -0
  187. package/dist/session-6MO5ZPOB.js +16 -0
  188. package/dist/session-6XMGPRTQ.js +14 -0
  189. package/dist/session-7DJR77R7.js +16 -0
  190. package/dist/session-7DQHPWTR.js +14 -0
  191. package/dist/session-ADKIQCR5.js +16 -0
  192. package/dist/session-AOGH2GGI.js +16 -0
  193. package/dist/session-C4W6GDYG.js +16 -0
  194. package/dist/session-DCGNGGMV.js +14 -0
  195. package/dist/session-F5JKZAN2.js +16 -0
  196. package/dist/session-G6F3O2FQ.js +16 -0
  197. package/dist/session-GFBSARRO.js +16 -0
  198. package/dist/session-H5IWAIUI.js +16 -0
  199. package/dist/session-IPFA6AHC.js +14 -0
  200. package/dist/session-IWG2UOAX.js +14 -0
  201. package/dist/session-KJ2K4Y4M.js +14 -0
  202. package/dist/session-KPXFBW6Q.js +14 -0
  203. package/dist/session-KR256UL5.js +16 -0
  204. package/dist/session-M72LJXPR.js +16 -0
  205. package/dist/session-MBK3FODN.js +14 -0
  206. package/dist/session-MOUFAU7G.js +16 -0
  207. package/dist/session-NRC6ZXFQ.js +16 -0
  208. package/dist/session-NRPQMV4K.js +16 -0
  209. package/dist/session-O5IFFJZQ.js +14 -0
  210. package/dist/session-OF5BGKDE.js +16 -0
  211. package/dist/session-OGRZMIM7.js +14 -0
  212. package/dist/session-OJOFAJG3.js +16 -0
  213. package/dist/session-OKU4N3SP.js +16 -0
  214. package/dist/session-P2VAOSFB.js +14 -0
  215. package/dist/session-PKOVZD4M.js +16 -0
  216. package/dist/session-POAIMUVN.js +16 -0
  217. package/dist/session-PSHFONFE.js +16 -0
  218. package/dist/session-QKYVVZFV.js +16 -0
  219. package/dist/session-QPWGBMUS.js +14 -0
  220. package/dist/session-R5UG5PZR.js +14 -0
  221. package/dist/session-RAY6BZRQ.js +16 -0
  222. package/dist/session-S3VATHMU.js +16 -0
  223. package/dist/session-SYTD7RHW.js +14 -0
  224. package/dist/session-UHMMVO4J.js +16 -0
  225. package/dist/session-WEX5K3ZY.js +14 -0
  226. package/dist/session-XFLOXGU3.js +14 -0
  227. package/dist/session-XV2A4HHG.js +14 -0
  228. package/dist/settings-3VPJYD4D.js +8 -0
  229. package/dist/settings-GZTJJTBK.js +8 -0
  230. package/dist/settings-YKJFSKMO.js +8 -0
  231. package/dist/shell-FM34624T.js +8 -0
  232. package/package.json +14 -4
@@ -0,0 +1,367 @@
1
+ import {
2
+ config
3
+ } from "./chunk-7MMY74WO.js";
4
+ import {
5
+ settings
6
+ } from "./chunk-EPG5V5OO.js";
7
+ import {
8
+ db
9
+ } from "./chunk-FNLWB54Z.js";
10
+
11
+ // src/core/context.ts
12
+ import path from "path";
13
+ var CONTEXT_CONFIG = {
14
+ DECAY_HALF_LIFE_MS: 36e5,
15
+ // 1 hour - files lose half their score every hour
16
+ MAX_WORKING_SET_SIZE: 50,
17
+ // Limit working set to prevent unbounded growth
18
+ IMPORTANCE_MODIFIED: 2,
19
+ // 2x weight for modified files
20
+ IMPORTANCE_ENTRY_POINT: 1.5,
21
+ // Higher weight for index.ts, main.ts, etc.
22
+ IMPORTANCE_RECENT_EDIT: 1.3,
23
+ // Files edited in last 5 interactions
24
+ TOKEN_ESTIMATE_PER_LINE: 4
25
+ // Rough estimate: 4 tokens per line
26
+ };
27
+ var ENTRY_POINT_PATTERNS = [
28
+ /^index\.(ts|tsx|js|jsx)$/,
29
+ /^main\.(ts|tsx|js|jsx)$/,
30
+ /^app\.(ts|tsx|js|jsx)$/,
31
+ /^server\.(ts|tsx|js|jsx)$/
32
+ ];
33
+ function calculateRankScore(accessCount, lastAccessed, isModified, isEntryPoint) {
34
+ const ageMs = Date.now() - lastAccessed;
35
+ const decayFactor = Math.pow(0.5, ageMs / CONTEXT_CONFIG.DECAY_HALF_LIFE_MS);
36
+ let importanceMultiplier = 1;
37
+ if (isModified) importanceMultiplier *= CONTEXT_CONFIG.IMPORTANCE_MODIFIED;
38
+ if (isEntryPoint) importanceMultiplier *= CONTEXT_CONFIG.IMPORTANCE_ENTRY_POINT;
39
+ return accessCount * decayFactor * importanceMultiplier;
40
+ }
41
+ function isEntryPointFile(filePath) {
42
+ const filename = path.basename(filePath);
43
+ return ENTRY_POINT_PATTERNS.some((pattern) => pattern.test(filename));
44
+ }
45
+ function generateSessionId() {
46
+ return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
47
+ }
48
+ function createEmptyContext() {
49
+ const now = (/* @__PURE__ */ new Date()).toISOString();
50
+ return {
51
+ session_id: generateSessionId(),
52
+ mode: "safe",
53
+ current_task: null,
54
+ files_read: [],
55
+ files_modified: [],
56
+ working_set: [],
57
+ last_action: null,
58
+ created_at: now,
59
+ updated_at: now
60
+ };
61
+ }
62
+ var ContextManager = class {
63
+ ctx = createEmptyContext();
64
+ constructor() {
65
+ }
66
+ async init() {
67
+ try {
68
+ const lastSession = db.getDb().prepare(`
69
+ SELECT id, created_at, source, permissions
70
+ FROM sessions
71
+ ORDER BY created_at DESC
72
+ LIMIT 1
73
+ `).get();
74
+ if (lastSession) {
75
+ await this.load(lastSession.id);
76
+ } else {
77
+ this.ctx = createEmptyContext();
78
+ await this.save();
79
+ }
80
+ } catch (e) {
81
+ console.error("Failed to init context from DB:", e);
82
+ this.ctx = createEmptyContext();
83
+ await this.save();
84
+ }
85
+ }
86
+ async load(sessionId) {
87
+ if (!sessionId) return;
88
+ try {
89
+ const session = db.getDb().prepare(`SELECT * FROM sessions WHERE id = ?`).get(sessionId);
90
+ if (!session) return;
91
+ const workingSetRows = db.getDb().prepare(`
92
+ SELECT file_path
93
+ FROM working_set
94
+ WHERE session_id = ?
95
+ ORDER BY rank_score DESC
96
+ `).all(sessionId);
97
+ this.ctx = {
98
+ session_id: session.id,
99
+ mode: "safe",
100
+ // Mode loaded from settings usually, but DB could store it if we added column
101
+ current_task: null,
102
+ // Tasks are now in 'tasks' table
103
+ files_read: [],
104
+ // Reset on load, or we could store this in DB if needed
105
+ files_modified: [],
106
+ working_set: workingSetRows.map((r) => r.file_path),
107
+ last_action: null,
108
+ created_at: new Date(session.created_at).toISOString(),
109
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
110
+ // Refreshed
111
+ };
112
+ await this.syncModeFromSettings();
113
+ } catch (e) {
114
+ console.error("Failed to load context:", e);
115
+ }
116
+ }
117
+ async save() {
118
+ this.ctx.updated_at = (/* @__PURE__ */ new Date()).toISOString();
119
+ const cfg = await config.load();
120
+ try {
121
+ const timestamp = Date.now();
122
+ db.getDb().prepare(`
123
+ INSERT INTO sessions (id, created_at, workspace)
124
+ VALUES (?, ?, ?)
125
+ ON CONFLICT(id) DO UPDATE SET
126
+ workspace = excluded.workspace,
127
+ created_at = excluded.created_at
128
+ `).run(this.ctx.session_id, timestamp, cfg.workspaceRoot);
129
+ const insertFile = db.getDb().prepare(`
130
+ INSERT INTO working_set (session_id, file_path, rank_score, last_accessed, access_count)
131
+ VALUES (?, ?, ?, ?, 1)
132
+ ON CONFLICT(session_id, file_path) DO UPDATE SET
133
+ access_count = access_count + 1,
134
+ last_accessed = ?
135
+ `);
136
+ const transaction = db.getDb().transaction(() => {
137
+ for (const file of this.ctx.working_set) {
138
+ insertFile.run(this.ctx.session_id, file, 1, timestamp, timestamp);
139
+ }
140
+ });
141
+ transaction();
142
+ } catch (e) {
143
+ console.error("Failed to save context to DB:", e);
144
+ }
145
+ }
146
+ async archive() {
147
+ }
148
+ async startNewSession() {
149
+ const oldMode = this.ctx.mode;
150
+ this.ctx = createEmptyContext();
151
+ this.ctx.mode = oldMode;
152
+ await this.save();
153
+ await settings.set("mode", this.ctx.mode);
154
+ }
155
+ // Getters
156
+ get() {
157
+ return { ...this.ctx };
158
+ }
159
+ getMode() {
160
+ return this.ctx.mode;
161
+ }
162
+ async syncModeFromSettings() {
163
+ const s = await settings.load();
164
+ this.ctx.mode = s.mode;
165
+ }
166
+ getCurrentTask() {
167
+ return this.ctx.current_task;
168
+ }
169
+ getWorkingSet() {
170
+ return [...this.ctx.working_set];
171
+ }
172
+ // Setters
173
+ async setMode(mode) {
174
+ this.ctx.mode = mode;
175
+ await settings.set("mode", mode);
176
+ }
177
+ async setTask(task) {
178
+ this.ctx.current_task = task;
179
+ }
180
+ // Tracking
181
+ async trackRead(filePath, tokenEstimate = 0) {
182
+ const cfg = await config.load();
183
+ const normalized = path.relative(cfg.workspaceRoot, path.resolve(filePath));
184
+ if (!this.ctx.files_read.includes(normalized)) {
185
+ this.ctx.files_read.push(normalized);
186
+ }
187
+ if (!this.ctx.working_set.includes(normalized)) {
188
+ this.ctx.working_set.push(normalized);
189
+ }
190
+ try {
191
+ const timestamp = Date.now();
192
+ const isModified = this.ctx.files_modified.includes(normalized);
193
+ const isEntryPoint = isEntryPointFile(normalized);
194
+ const existing = db.getDb().prepare(`
195
+ SELECT access_count FROM working_set
196
+ WHERE session_id = ? AND file_path = ?
197
+ `).get(this.ctx.session_id, normalized);
198
+ const newAccessCount = (existing?.access_count || 0) + 1;
199
+ const rankScore = calculateRankScore(newAccessCount, timestamp, isModified, isEntryPoint);
200
+ db.getDb().prepare(`
201
+ INSERT INTO working_set (session_id, file_path, rank_score, last_accessed, access_count)
202
+ VALUES (?, ?, ?, ?, 1)
203
+ ON CONFLICT(session_id, file_path) DO UPDATE SET
204
+ access_count = access_count + 1,
205
+ last_accessed = ?,
206
+ rank_score = ?
207
+ `).run(this.ctx.session_id, normalized, rankScore, timestamp, timestamp, rankScore);
208
+ await this.pruneWorkingSet();
209
+ } catch (e) {
210
+ console.error("Failed to track read:", e);
211
+ }
212
+ }
213
+ async trackModified(filePath, tokenEstimate = 0) {
214
+ const cfg = await config.load();
215
+ const normalized = path.relative(cfg.workspaceRoot, path.resolve(filePath));
216
+ if (!this.ctx.files_modified.includes(normalized)) {
217
+ this.ctx.files_modified.push(normalized);
218
+ }
219
+ try {
220
+ const timestamp = Date.now();
221
+ const existing = db.getDb().prepare(`
222
+ SELECT access_count FROM working_set
223
+ WHERE session_id = ? AND file_path = ?
224
+ `).get(this.ctx.session_id, normalized);
225
+ const accessCount = existing?.access_count || 1;
226
+ const isEntryPoint = isEntryPointFile(normalized);
227
+ const rankScore = calculateRankScore(accessCount, timestamp, true, isEntryPoint);
228
+ db.getDb().prepare(`
229
+ UPDATE working_set SET rank_score = ?, last_accessed = ?
230
+ WHERE session_id = ? AND file_path = ?
231
+ `).run(rankScore, timestamp, this.ctx.session_id, normalized);
232
+ } catch (e) {
233
+ await this.trackRead(filePath, tokenEstimate);
234
+ }
235
+ }
236
+ /**
237
+ * Prune working set to prevent unbounded growth
238
+ * Keeps top N files by rank score
239
+ */
240
+ async pruneWorkingSet() {
241
+ try {
242
+ const count = db.getDb().prepare(`
243
+ SELECT COUNT(*) as count FROM working_set WHERE session_id = ?
244
+ `).get(this.ctx.session_id);
245
+ if (count.count > CONTEXT_CONFIG.MAX_WORKING_SET_SIZE) {
246
+ db.getDb().prepare(`
247
+ DELETE FROM working_set
248
+ WHERE session_id = ? AND file_path NOT IN (
249
+ SELECT file_path FROM working_set
250
+ WHERE session_id = ?
251
+ ORDER BY rank_score DESC
252
+ LIMIT ?
253
+ )
254
+ `).run(this.ctx.session_id, this.ctx.session_id, CONTEXT_CONFIG.MAX_WORKING_SET_SIZE);
255
+ const remaining = db.getDb().prepare(`
256
+ SELECT file_path FROM working_set
257
+ WHERE session_id = ?
258
+ ORDER BY rank_score DESC
259
+ `).all(this.ctx.session_id);
260
+ this.ctx.working_set = remaining.map((r) => r.file_path);
261
+ }
262
+ } catch (e) {
263
+ console.error("Failed to prune working set:", e);
264
+ }
265
+ }
266
+ /**
267
+ * Get working set entries with full metadata
268
+ */
269
+ getWorkingSetWithMetadata() {
270
+ try {
271
+ const rows = db.getDb().prepare(`
272
+ SELECT file_path, access_count, last_accessed, rank_score
273
+ FROM working_set
274
+ WHERE session_id = ?
275
+ ORDER BY rank_score DESC
276
+ `).all(this.ctx.session_id);
277
+ return rows.map((r) => ({
278
+ filePath: r.file_path,
279
+ accessCount: r.access_count,
280
+ lastAccessed: r.last_accessed,
281
+ isModified: this.ctx.files_modified.includes(r.file_path),
282
+ tokenEstimate: 0
283
+ // Would need to read file to estimate
284
+ }));
285
+ } catch (e) {
286
+ return [];
287
+ }
288
+ }
289
+ /**
290
+ * Recalculate all rank scores (useful for periodic refresh)
291
+ */
292
+ async recalculateRankScores() {
293
+ try {
294
+ const rows = db.getDb().prepare(`
295
+ SELECT file_path, access_count, last_accessed
296
+ FROM working_set
297
+ WHERE session_id = ?
298
+ `).all(this.ctx.session_id);
299
+ const updateStmt = db.getDb().prepare(`
300
+ UPDATE working_set SET rank_score = ?
301
+ WHERE session_id = ? AND file_path = ?
302
+ `);
303
+ db.getDb().transaction(() => {
304
+ for (const row of rows) {
305
+ const isModified = this.ctx.files_modified.includes(row.file_path);
306
+ const isEntryPoint = isEntryPointFile(row.file_path);
307
+ const newScore = calculateRankScore(
308
+ row.access_count,
309
+ row.last_accessed,
310
+ isModified,
311
+ isEntryPoint
312
+ );
313
+ updateStmt.run(newScore, this.ctx.session_id, row.file_path);
314
+ }
315
+ })();
316
+ } catch (e) {
317
+ console.error("Failed to recalculate rank scores:", e);
318
+ }
319
+ }
320
+ async setLastAction(action) {
321
+ this.ctx.last_action = action;
322
+ }
323
+ // Reset
324
+ async reset() {
325
+ this.ctx = createEmptyContext();
326
+ await this.save();
327
+ }
328
+ async clearWorkingSet() {
329
+ this.ctx.working_set = [];
330
+ db.getDb().prepare("DELETE FROM working_set WHERE session_id = ?").run(this.ctx.session_id);
331
+ }
332
+ // Summary for LLM
333
+ getSummary() {
334
+ const lines = [];
335
+ if (this.ctx.current_task) {
336
+ lines.push(`Task: ${this.ctx.current_task}`);
337
+ }
338
+ const topFiles = this.getWorkingSetWithMetadata().slice(0, 5);
339
+ if (topFiles.length > 0) {
340
+ const fileList = topFiles.map((f) => {
341
+ const modified = f.isModified ? "*" : "";
342
+ return `${modified}${f.filePath}`;
343
+ }).join(", ");
344
+ lines.push(`Working set (top 5): ${fileList}`);
345
+ }
346
+ if (this.ctx.files_modified.length > 0) {
347
+ lines.push(`Modified this session: ${this.ctx.files_modified.slice(-3).join(", ")}`);
348
+ }
349
+ return lines.join("\n");
350
+ }
351
+ /**
352
+ * Get context statistics for monitoring
353
+ */
354
+ getStats() {
355
+ return {
356
+ totalFilesRead: this.ctx.files_read.length,
357
+ totalFilesModified: this.ctx.files_modified.length,
358
+ workingSetSize: this.ctx.working_set.length,
359
+ sessionAge: Date.now() - new Date(this.ctx.created_at).getTime()
360
+ };
361
+ }
362
+ };
363
+ var context = new ContextManager();
364
+
365
+ export {
366
+ context
367
+ };
@@ -0,0 +1,214 @@
1
+ import {
2
+ auditLog
3
+ } from "./chunk-JTWSK277.js";
4
+ import {
5
+ context
6
+ } from "./chunk-ZOSSVNGK.js";
7
+ import {
8
+ bus
9
+ } from "./chunk-WQM6FFSD.js";
10
+ import {
11
+ db
12
+ } from "./chunk-FNLWB54Z.js";
13
+
14
+ // src/core/scheduler.ts
15
+ import cronParser from "cron-parser";
16
+ var parseExpression = cronParser.parseExpression || cronParser.default?.parseExpression || cronParser.parse || cronParser.default?.parse;
17
+ var MAX_CONSECUTIVE_FAILURES = 3;
18
+ var Scheduler = class _Scheduler {
19
+ static instance;
20
+ abilities = /* @__PURE__ */ new Map();
21
+ timer = null;
22
+ isRunning = false;
23
+ failureCounts = /* @__PURE__ */ new Map();
24
+ constructor() {
25
+ }
26
+ static getInstance() {
27
+ if (!_Scheduler.instance) {
28
+ _Scheduler.instance = new _Scheduler();
29
+ }
30
+ return _Scheduler.instance;
31
+ }
32
+ /**
33
+ * Initialize the scheduler loop
34
+ */
35
+ start() {
36
+ if (this.isRunning) return;
37
+ this.isRunning = true;
38
+ this.tick().catch((err) => bus.emitAgent({ type: "error", message: `[Scheduler] Initial tick failed: ${err instanceof Error ? err.message : String(err)}` }));
39
+ this.timer = setInterval(() => this.tick(), 1e4);
40
+ bus.emitAgent({ type: "thought", content: "[Obsidian] Started background task monitor [Active Heartbeat]" });
41
+ }
42
+ stop() {
43
+ if (this.timer) {
44
+ clearInterval(this.timer);
45
+ this.timer = null;
46
+ }
47
+ this.isRunning = false;
48
+ }
49
+ /**
50
+ * Register a new ability that can be scheduled
51
+ */
52
+ registerAbility(name, func) {
53
+ this.abilities.set(name, func);
54
+ }
55
+ /**
56
+ * Get list of registered abilities
57
+ */
58
+ getAbilities() {
59
+ return Array.from(this.abilities.keys());
60
+ }
61
+ /**
62
+ * Schedule a new task
63
+ */
64
+ async scheduleTask(cronExpression, abilityName, params = {}) {
65
+ try {
66
+ parseExpression(cronExpression);
67
+ } catch (err) {
68
+ throw new Error(`Invalid cron expression: ${cronExpression}`);
69
+ }
70
+ if (!this.abilities.has(abilityName)) {
71
+ throw new Error(`Unknown ability: ${abilityName}`);
72
+ }
73
+ const id = `task_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
74
+ const sessionId = context.get().session_id;
75
+ const task = {
76
+ id,
77
+ session_id: sessionId,
78
+ cron_expression: cronExpression,
79
+ command: abilityName,
80
+ params: JSON.stringify(params),
81
+ last_run_at: Date.now(),
82
+ active: 1
83
+ };
84
+ db.getDb().prepare(`
85
+ INSERT INTO scheduled_tasks (id, session_id, cron_expression, command, params, last_run_at, active)
86
+ VALUES (?, ?, ?, ?, ?, ?, ?)
87
+ `).run(task.id, task.session_id, task.cron_expression, task.command, task.params, task.last_run_at, task.active);
88
+ bus.emitAgent({ type: "thought", content: `[Scheduler] Scheduled ${abilityName} (${cronExpression})` });
89
+ return task;
90
+ }
91
+ /**
92
+ * List all active tasks
93
+ */
94
+ listTasks() {
95
+ const tasks = db.getDb().prepare(`
96
+ SELECT * FROM scheduled_tasks WHERE active = 1
97
+ `).all();
98
+ return tasks.map((t) => {
99
+ try {
100
+ const interval = parseExpression(t.cron_expression);
101
+ t.next_run_at = interval.next().getTime();
102
+ } catch {
103
+ t.next_run_at = 0;
104
+ }
105
+ return t;
106
+ });
107
+ }
108
+ /**
109
+ * Main execution loop
110
+ */
111
+ async tick() {
112
+ const tasks = this.listTasks();
113
+ const now = Date.now();
114
+ for (const task of tasks) {
115
+ try {
116
+ const baseline = task.last_run_at || now - 61e3;
117
+ let taskParams = {};
118
+ try {
119
+ taskParams = task.params ? JSON.parse(task.params) : {};
120
+ } catch {
121
+ }
122
+ if (taskParams.__once && taskParams.__target) {
123
+ if (now >= taskParams.__target) {
124
+ await this.executeTask(task);
125
+ }
126
+ continue;
127
+ }
128
+ const interval = parseExpression(task.cron_expression, {
129
+ currentDate: baseline
130
+ });
131
+ const nextRun = interval.next().getTime();
132
+ if (nextRun <= now) {
133
+ await this.executeTask(task);
134
+ }
135
+ } catch (error) {
136
+ bus.emitAgent({ type: "error", message: `[Scheduler] Error checking task ${task.id}: ${error instanceof Error ? error.message : String(error)}` });
137
+ }
138
+ }
139
+ }
140
+ async executeTask(task) {
141
+ const ability = this.abilities.get(task.command);
142
+ if (!ability) {
143
+ bus.emitAgent({ type: "error", message: `[Scheduler] Ability "${task.command}" not found. Disabling task ${task.id}.` });
144
+ db.getDb().prepare("UPDATE scheduled_tasks SET active = 0 WHERE id = ?").run(task.id);
145
+ return;
146
+ }
147
+ bus.emitAgent({
148
+ type: "scheduler_task_started",
149
+ taskId: task.id,
150
+ command: task.command
151
+ });
152
+ try {
153
+ let params = {};
154
+ if (task.params) {
155
+ try {
156
+ params = JSON.parse(task.params);
157
+ } catch {
158
+ }
159
+ }
160
+ await ability(params);
161
+ bus.emitAgent({
162
+ type: "scheduler_task_completed",
163
+ taskId: task.id,
164
+ command: task.command
165
+ });
166
+ this.failureCounts.delete(task.id);
167
+ if (params.__once) {
168
+ db.getDb().prepare(`UPDATE scheduled_tasks SET active = 0 WHERE id = ?`).run(task.id);
169
+ bus.emitAgent({ type: "thought", content: `[Scheduler] One-time task ${task.id} completed and deactivated.` });
170
+ }
171
+ } catch (error) {
172
+ await auditLog.logSystemEvent("scheduler_error", { taskId: task.id, error: error.message });
173
+ bus.emitAgent({ type: "scheduler_task_failed", taskId: task.id, command: task.command, error: error.message });
174
+ const failures = (this.failureCounts.get(task.id) || 0) + 1;
175
+ this.failureCounts.set(task.id, failures);
176
+ if (failures >= MAX_CONSECUTIVE_FAILURES) {
177
+ db.getDb().prepare("UPDATE scheduled_tasks SET active = 0 WHERE id = ?").run(task.id);
178
+ this.failureCounts.delete(task.id);
179
+ bus.emitAgent({
180
+ type: "error",
181
+ message: `[Scheduler] Task ${task.id} (${task.command}) disabled after ${MAX_CONSECUTIVE_FAILURES} consecutive failures.`
182
+ });
183
+ } else {
184
+ bus.emitAgent({
185
+ type: "error",
186
+ message: `[Scheduler] Task ${task.id} (${task.command}) failed: ${error.message} (${failures}/${MAX_CONSECUTIVE_FAILURES} before auto-disable)`
187
+ });
188
+ }
189
+ } finally {
190
+ db.getDb().prepare(`
191
+ UPDATE scheduled_tasks SET last_run_at = ? WHERE id = ?
192
+ `).run(Date.now(), task.id);
193
+ }
194
+ }
195
+ /**
196
+ * Remove (deactivate) a scheduled task
197
+ */
198
+ async removeTask(taskId) {
199
+ const result = db.getDb().prepare(`
200
+ UPDATE scheduled_tasks SET active = 0 WHERE id = ?
201
+ `).run(taskId);
202
+ if (result.changes && result.changes > 0) {
203
+ bus.emitAgent({ type: "thought", content: `[Scheduler] Deactivated task: ${taskId}` });
204
+ return true;
205
+ }
206
+ return false;
207
+ }
208
+ };
209
+ var scheduler = Scheduler.getInstance();
210
+
211
+ export {
212
+ Scheduler,
213
+ scheduler
214
+ };
@@ -0,0 +1,133 @@
1
+ import {
2
+ history,
3
+ session,
4
+ tasks
5
+ } from "./chunk-VS22YVX6.js";
6
+ import {
7
+ context
8
+ } from "./chunk-DPNIQWKZ.js";
9
+ import {
10
+ bus
11
+ } from "./chunk-WQM6FFSD.js";
12
+
13
+ // src/commands/resume.ts
14
+ import path from "path";
15
+ var resumeCommand = async (args) => {
16
+ if (args[0] === "--delete" || args[0] === "-d") {
17
+ const sessionId = args[1];
18
+ if (!sessionId) {
19
+ bus.emitAgent({
20
+ type: "error",
21
+ message: "Usage: /resume --delete <session_id>"
22
+ });
23
+ return;
24
+ }
25
+ const deleted = await session.delete(sessionId);
26
+ if (deleted) {
27
+ bus.emitAgent({
28
+ type: "done",
29
+ summary: `Session ${sessionId} deleted.`
30
+ });
31
+ } else {
32
+ bus.emitAgent({
33
+ type: "error",
34
+ message: `Session ${sessionId} not found.`
35
+ });
36
+ }
37
+ return;
38
+ }
39
+ if (args[0] === "--last" || args[0] === "-l") {
40
+ const sessions = await session.list();
41
+ if (sessions.length === 0) {
42
+ bus.emitAgent({
43
+ type: "error",
44
+ message: "No saved sessions found."
45
+ });
46
+ return;
47
+ }
48
+ args[0] = sessions[0].id;
49
+ }
50
+ if (!args[0]) {
51
+ const sessions = await session.list();
52
+ if (sessions.length === 0) {
53
+ bus.emitAgent({
54
+ type: "thought",
55
+ content: "No saved sessions found.\n\nSessions are created when you run /exit."
56
+ });
57
+ bus.emitAgent({
58
+ type: "done",
59
+ summary: "No sessions available."
60
+ });
61
+ return;
62
+ }
63
+ const content2 = [
64
+ "Saved Session Registry",
65
+ ...sessions.slice(0, 10).map((s) => {
66
+ const date = new Date(s.savedAt);
67
+ const dateStr = date.toLocaleDateString();
68
+ const timeStr = date.toLocaleTimeString([], {
69
+ hour: "2-digit",
70
+ minute: "2-digit"
71
+ });
72
+ const workspaceName = path.basename(s.workspace);
73
+ return [
74
+ ` \u23BF [${s.id}]`,
75
+ ` \u23BF Date ${dateStr} ${timeStr}`,
76
+ ` \u23BF Workspace ${workspaceName}`,
77
+ s.task ? ` \u23BF Task ${s.task}` : null,
78
+ ` \u23BF Activity ${s.filesModified} files handled`,
79
+ ""
80
+ ].filter(Boolean).join("\n");
81
+ }),
82
+ sessions.length > 10 ? ` ... and ${sessions.length - 10} more sessions
83
+ ` : "",
84
+ " [Usage]",
85
+ " \u23BF /resume <id> Restore session",
86
+ " \u23BF /resume --last Restore latest",
87
+ ""
88
+ ].join("\n");
89
+ bus.emitAgent({
90
+ type: "thought",
91
+ content: content2
92
+ });
93
+ bus.emitAgent({
94
+ type: "done",
95
+ summary: `${sessions.length} session(s) available.`
96
+ });
97
+ return;
98
+ }
99
+ const sessionIdArg = args[0];
100
+ const result = await session.restore(sessionIdArg);
101
+ if (!result.success) {
102
+ bus.emitAgent({
103
+ type: "error",
104
+ message: result.error || "Failed to restore session"
105
+ });
106
+ return;
107
+ }
108
+ const currentTask = tasks.get();
109
+ const currentContext = context.get();
110
+ const content = [
111
+ "Session Restored Successfully",
112
+ ` \u23BF ID ${sessionIdArg}`,
113
+ ` \u23BF Root ${path.basename(process.cwd())}`,
114
+ "",
115
+ " [Restored State]",
116
+ ` \u23BF Context ${currentContext.files_read.length} files in set`,
117
+ ` \u23BF History ${(await history.load()).length} events rehydrated`,
118
+ ` \u23BF Task ${currentTask?.title || "None"}`,
119
+ ""
120
+ ].join("\n");
121
+ bus.emitAgent({
122
+ type: "thought",
123
+ content
124
+ });
125
+ bus.emitAgent({
126
+ type: "done",
127
+ summary: `Session ${sessionIdArg} restored.`
128
+ });
129
+ };
130
+
131
+ export {
132
+ resumeCommand
133
+ };