@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,196 @@
1
+ import {
2
+ auditLog
3
+ } from "./chunk-5SWSM5VM.js";
4
+ import {
5
+ context
6
+ } from "./chunk-MSDU36RT.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 Scheduler = class _Scheduler {
18
+ static instance;
19
+ abilities = /* @__PURE__ */ new Map();
20
+ timer = null;
21
+ isRunning = false;
22
+ constructor() {
23
+ }
24
+ static getInstance() {
25
+ if (!_Scheduler.instance) {
26
+ _Scheduler.instance = new _Scheduler();
27
+ }
28
+ return _Scheduler.instance;
29
+ }
30
+ /**
31
+ * Initialize the scheduler loop
32
+ */
33
+ start() {
34
+ if (this.isRunning) return;
35
+ this.isRunning = true;
36
+ this.tick().catch((err) => console.error("[Scheduler] Initial tick failed:", err));
37
+ this.timer = setInterval(() => this.tick(), 1e4);
38
+ bus.emitAgent({ type: "thought", content: "[Obsidian] Started background task monitor [Active Heartbeat]" });
39
+ }
40
+ stop() {
41
+ if (this.timer) {
42
+ clearInterval(this.timer);
43
+ this.timer = null;
44
+ }
45
+ this.isRunning = false;
46
+ }
47
+ /**
48
+ * Register a new ability that can be scheduled
49
+ */
50
+ registerAbility(name, func) {
51
+ this.abilities.set(name, func);
52
+ }
53
+ /**
54
+ * Get list of registered abilities
55
+ */
56
+ getAbilities() {
57
+ return Array.from(this.abilities.keys());
58
+ }
59
+ /**
60
+ * Schedule a new task
61
+ */
62
+ async scheduleTask(cronExpression, abilityName, params = {}) {
63
+ try {
64
+ parseExpression(cronExpression);
65
+ } catch (err) {
66
+ throw new Error(`Invalid cron expression: ${cronExpression}`);
67
+ }
68
+ if (!this.abilities.has(abilityName)) {
69
+ throw new Error(`Unknown ability: ${abilityName}`);
70
+ }
71
+ const id = `task_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
72
+ const sessionId = context.get().session_id;
73
+ const task = {
74
+ id,
75
+ session_id: sessionId,
76
+ cron_expression: cronExpression,
77
+ command: abilityName,
78
+ params: JSON.stringify(params),
79
+ last_run_at: Date.now(),
80
+ active: 1
81
+ };
82
+ db.getDb().prepare(`
83
+ INSERT INTO scheduled_tasks (id, session_id, cron_expression, command, params, last_run_at, active)
84
+ VALUES (?, ?, ?, ?, ?, ?, ?)
85
+ `).run(task.id, task.session_id, task.cron_expression, task.command, task.params, task.last_run_at, task.active);
86
+ bus.emitAgent({ type: "thought", content: `[Scheduler] Scheduled ${abilityName} (${cronExpression})` });
87
+ return task;
88
+ }
89
+ /**
90
+ * List all active tasks
91
+ */
92
+ listTasks() {
93
+ const tasks = db.getDb().prepare(`
94
+ SELECT * FROM scheduled_tasks WHERE active = 1
95
+ `).all();
96
+ return tasks.map((t) => {
97
+ try {
98
+ const interval = parseExpression(t.cron_expression);
99
+ t.next_run_at = interval.next().getTime();
100
+ } catch {
101
+ t.next_run_at = 0;
102
+ }
103
+ return t;
104
+ });
105
+ }
106
+ /**
107
+ * Main execution loop
108
+ */
109
+ async tick() {
110
+ const tasks = this.listTasks();
111
+ const now = Date.now();
112
+ for (const task of tasks) {
113
+ try {
114
+ const baseline = task.last_run_at || now - 61e3;
115
+ let taskParams = {};
116
+ try {
117
+ taskParams = task.params ? JSON.parse(task.params) : {};
118
+ } catch {
119
+ }
120
+ if (taskParams.__once && taskParams.__target) {
121
+ if (now >= taskParams.__target) {
122
+ await this.executeTask(task);
123
+ }
124
+ continue;
125
+ }
126
+ const interval = parseExpression(task.cron_expression, {
127
+ currentDate: baseline
128
+ });
129
+ const nextRun = interval.next().getTime();
130
+ if (nextRun <= now) {
131
+ await this.executeTask(task);
132
+ }
133
+ } catch (error) {
134
+ console.error(`[Scheduler] Error checking task ${task.id}:`, error);
135
+ }
136
+ }
137
+ }
138
+ async executeTask(task) {
139
+ const ability = this.abilities.get(task.command);
140
+ if (!ability) {
141
+ bus.emitAgent({ type: "error", message: `Scheduler: Ability ${task.command} not found for task ${task.id}` });
142
+ return;
143
+ }
144
+ bus.emitAgent({
145
+ type: "scheduler_task_started",
146
+ taskId: task.id,
147
+ command: task.command
148
+ });
149
+ try {
150
+ let params = {};
151
+ if (task.params) {
152
+ try {
153
+ params = JSON.parse(task.params);
154
+ } catch {
155
+ }
156
+ }
157
+ await ability(params);
158
+ bus.emitAgent({
159
+ type: "scheduler_task_completed",
160
+ taskId: task.id,
161
+ command: task.command
162
+ });
163
+ if (params.__once) {
164
+ db.getDb().prepare(`UPDATE scheduled_tasks SET active = 0 WHERE id = ?`).run(task.id);
165
+ bus.emitAgent({ type: "thought", content: `[Scheduler] One-time task ${task.id} completed and deactivated.` });
166
+ }
167
+ } catch (error) {
168
+ console.error(`[Scheduler] Task ${task.id} failed:`, error);
169
+ await auditLog.logSystemEvent("scheduler_error", { taskId: task.id, error: error.message });
170
+ bus.emitAgent({ type: "scheduler_task_failed", taskId: task.id, command: task.command, error: error.message });
171
+ } finally {
172
+ db.getDb().prepare(`
173
+ UPDATE scheduled_tasks SET last_run_at = ? WHERE id = ?
174
+ `).run(Date.now(), task.id);
175
+ }
176
+ }
177
+ /**
178
+ * Remove (deactivate) a scheduled task
179
+ */
180
+ async removeTask(taskId) {
181
+ const result = db.getDb().prepare(`
182
+ UPDATE scheduled_tasks SET active = 0 WHERE id = ?
183
+ `).run(taskId);
184
+ if (result.changes && result.changes > 0) {
185
+ bus.emitAgent({ type: "thought", content: `[Scheduler] Deactivated task: ${taskId}` });
186
+ return true;
187
+ }
188
+ return false;
189
+ }
190
+ };
191
+ var scheduler = Scheduler.getInstance();
192
+
193
+ export {
194
+ Scheduler,
195
+ scheduler
196
+ };
@@ -0,0 +1,288 @@
1
+ // src/core/settings.ts
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import os from "os";
5
+ import { z } from "zod";
6
+ var SETTINGS_DIR = ".obsidian-next";
7
+ var SETTINGS_FILE = "settings.json";
8
+ var SettingsSchema = z.object({
9
+ // Execution mode
10
+ mode: z.enum(["auto", "plan", "safe"]).default("safe"),
11
+ // Auto-accept settings
12
+ autoAccept: z.object({
13
+ enabled: z.boolean().default(false),
14
+ readOperations: z.boolean().default(true),
15
+ safeCommands: z.boolean().default(true)
16
+ }).default({}),
17
+ // Tool permissions
18
+ permissions: z.object({
19
+ // Patterns always allowed without prompt: "tool:pattern"
20
+ allow: z.array(z.string()).default([]),
21
+ // Patterns allowed without prompt AND without sandbox
22
+ allowUnsandboxed: z.array(z.string()).default([]),
23
+ // Patterns always blocked
24
+ deny: z.array(z.string()).default([])
25
+ }).default({}),
26
+ // Security settings
27
+ security: z.object({
28
+ // PII redaction before sending to LLM
29
+ piiRedaction: z.boolean().default(true),
30
+ // Audit logging of all commands
31
+ auditLogging: z.boolean().default(true),
32
+ // Key storage backend preference
33
+ keyBackend: z.enum(["auto", "keychain", "secret-tool", "encrypted-file", "env"]).default("auto"),
34
+ // Restrict filesystem access to sandbox directories
35
+ sandbox: z.boolean().default(false)
36
+ }).default({}),
37
+ // UI preferences
38
+ ui: z.object({
39
+ syntaxHighlight: z.boolean().default(true),
40
+ diffColors: z.boolean().default(true),
41
+ showLineNumbers: z.boolean().default(true),
42
+ // Owl animation settings
43
+ owlAnimation: z.object({
44
+ enabled: z.boolean().default(false),
45
+ flyWhenIdle: z.boolean().default(false),
46
+ idleTimeout: z.number().default(6e4),
47
+ // 60s before idle animation
48
+ sleepTimeout: z.number().default(3e5)
49
+ // 5m before sleep animation
50
+ }).default({})
51
+ }).default({}),
52
+ // Remote Gateway (Telegram)
53
+ telegram: z.object({
54
+ enabled: z.boolean().default(false),
55
+ botToken: z.string().optional(),
56
+ allowedUserIds: z.array(z.string()).default([])
57
+ }).default({})
58
+ });
59
+ var DEFAULT_SETTINGS = {
60
+ mode: "safe",
61
+ autoAccept: {
62
+ enabled: false,
63
+ readOperations: false,
64
+ safeCommands: false
65
+ },
66
+ permissions: {
67
+ allow: [],
68
+ // Empty - user builds their own allow list
69
+ allowUnsandboxed: [],
70
+ deny: []
71
+ },
72
+ security: {
73
+ piiRedaction: true,
74
+ // Enabled by default - protects user privacy
75
+ auditLogging: true,
76
+ // Enabled by default - for accountability
77
+ keyBackend: "auto",
78
+ // Auto-detect best available backend
79
+ sandbox: false
80
+ // Disabled by default
81
+ },
82
+ ui: {
83
+ syntaxHighlight: true,
84
+ diffColors: true,
85
+ showLineNumbers: true,
86
+ owlAnimation: {
87
+ enabled: false,
88
+ flyWhenIdle: false,
89
+ idleTimeout: 6e4,
90
+ // 60s before idle animation
91
+ sleepTimeout: 3e5
92
+ // 5m before sleep animation
93
+ }
94
+ },
95
+ telegram: {
96
+ enabled: false,
97
+ allowedUserIds: []
98
+ }
99
+ };
100
+ var SettingsManager = class {
101
+ settingsPath;
102
+ cache = null;
103
+ sessionAllow = /* @__PURE__ */ new Set();
104
+ sessionUnsandboxed = /* @__PURE__ */ new Set();
105
+ sessionDeny = /* @__PURE__ */ new Set();
106
+ constructor() {
107
+ this.settingsPath = path.join(os.homedir(), SETTINGS_DIR, SETTINGS_FILE);
108
+ }
109
+ async load() {
110
+ if (this.cache) return this.cache;
111
+ return this.reload();
112
+ }
113
+ async reload() {
114
+ try {
115
+ const data = await fs.readFile(this.settingsPath, "utf-8");
116
+ const parsed = JSON.parse(data);
117
+ this.cache = SettingsSchema.parse({ ...DEFAULT_SETTINGS, ...parsed });
118
+ } catch {
119
+ this.cache = DEFAULT_SETTINGS;
120
+ await this.save(DEFAULT_SETTINGS);
121
+ }
122
+ return this.cache;
123
+ }
124
+ /**
125
+ * Add a permission to the allow list (called when user approves a command)
126
+ */
127
+ async addAllowedPermission(tool, command) {
128
+ const s = await this.load();
129
+ const pattern = `${tool}:${command}`;
130
+ if (!s.permissions.allow.includes(pattern)) {
131
+ s.permissions.allow.push(pattern);
132
+ await this.save({ permissions: s.permissions });
133
+ }
134
+ }
135
+ /**
136
+ * Add a permission to the unsandboxed allow list
137
+ */
138
+ async addUnsandboxedPermission(tool, command) {
139
+ const s = await this.load();
140
+ const pattern = `${tool}:${command}`;
141
+ if (!s.permissions.allowUnsandboxed.includes(pattern)) {
142
+ s.permissions.allowUnsandboxed.push(pattern);
143
+ if (!s.permissions.allow.includes(pattern)) {
144
+ s.permissions.allow.push(pattern);
145
+ }
146
+ await this.save({ permissions: s.permissions });
147
+ }
148
+ }
149
+ /**
150
+ * Add a permission to the session-only allow/deny list
151
+ */
152
+ async addSessionPermission(tool, command, approved, bypass = false) {
153
+ const pattern = `${tool}:${command}`;
154
+ if (approved) {
155
+ this.sessionAllow.add(pattern);
156
+ this.sessionDeny.delete(pattern);
157
+ if (bypass) {
158
+ this.sessionUnsandboxed.add(pattern);
159
+ }
160
+ } else {
161
+ this.sessionDeny.add(pattern);
162
+ this.sessionAllow.delete(pattern);
163
+ this.sessionUnsandboxed.delete(pattern);
164
+ }
165
+ }
166
+ /**
167
+ * Add a permission to the deny list
168
+ */
169
+ async addDeniedPermission(tool, command) {
170
+ const s = await this.load();
171
+ const pattern = `${tool}:${command}`;
172
+ if (!s.permissions.deny.includes(pattern)) {
173
+ s.permissions.deny.push(pattern);
174
+ await this.save({ permissions: s.permissions });
175
+ }
176
+ }
177
+ async save(newSettings) {
178
+ const current = await this.load();
179
+ const merged = { ...current, ...newSettings };
180
+ if (newSettings.autoAccept) {
181
+ merged.autoAccept = { ...current.autoAccept, ...newSettings.autoAccept };
182
+ }
183
+ if (newSettings.permissions) {
184
+ merged.permissions = {
185
+ ...current.permissions,
186
+ ...newSettings.permissions
187
+ };
188
+ }
189
+ if (newSettings.security) {
190
+ merged.security = { ...current.security, ...newSettings.security };
191
+ }
192
+ if (newSettings.ui) {
193
+ merged.ui = { ...current.ui, ...newSettings.ui };
194
+ }
195
+ const validated = SettingsSchema.parse(merged);
196
+ const dir = path.dirname(this.settingsPath);
197
+ await fs.mkdir(dir, { recursive: true });
198
+ await fs.writeFile(this.settingsPath, JSON.stringify(validated, null, 2));
199
+ this.cache = validated;
200
+ }
201
+ async get(key) {
202
+ const s = await this.load();
203
+ return s[key];
204
+ }
205
+ async set(key, value) {
206
+ await this.save({ [key]: value });
207
+ }
208
+ /**
209
+ * Check if a tool:command pattern is authorized for THIS SESSION only
210
+ */
211
+ async isSessionAuthorized(tool, command) {
212
+ const pattern = `${tool}:${command}`;
213
+ return this.sessionAllow.has(pattern);
214
+ }
215
+ /**
216
+ * Check if a tool:command pattern is allowed (session or persistent)
217
+ */
218
+ async isAllowed(tool, command) {
219
+ const pattern = `${tool}:${command}`;
220
+ if (this.sessionAllow.has(pattern)) {
221
+ return true;
222
+ }
223
+ const s = await this.load();
224
+ for (const deny of s.permissions.deny) {
225
+ if (this.matchPattern(pattern, deny)) {
226
+ return false;
227
+ }
228
+ }
229
+ for (const allow of s.permissions.allow) {
230
+ if (this.matchPattern(pattern, allow)) {
231
+ return true;
232
+ }
233
+ }
234
+ return false;
235
+ }
236
+ /**
237
+ * Check if a tool:command pattern is allowed to bypass sandbox
238
+ */
239
+ async isUnsandboxed(tool, command) {
240
+ const pattern = `${tool}:${command}`;
241
+ if (this.sessionUnsandboxed.has(pattern)) {
242
+ return true;
243
+ }
244
+ const s = await this.load();
245
+ for (const allow of s.permissions.allowUnsandboxed) {
246
+ if (this.matchPattern(pattern, allow)) {
247
+ return true;
248
+ }
249
+ }
250
+ return false;
251
+ }
252
+ /**
253
+ * Check if a tool:command pattern is explicitly denied
254
+ */
255
+ async isDenied(tool, command) {
256
+ const pattern = `${tool}:${command}`;
257
+ if (this.sessionDeny.has(pattern)) {
258
+ return true;
259
+ }
260
+ const s = await this.load();
261
+ for (const deny of s.permissions.deny) {
262
+ if (this.matchPattern(pattern, deny)) {
263
+ return true;
264
+ }
265
+ }
266
+ return false;
267
+ }
268
+ /**
269
+ * Simple glob-like pattern matching
270
+ * Supports * as wildcard
271
+ */
272
+ matchPattern(value, pattern) {
273
+ const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
274
+ return new RegExp(`^${regex}$`).test(value);
275
+ }
276
+ clearCache() {
277
+ this.cache = null;
278
+ }
279
+ getPath() {
280
+ return this.settingsPath;
281
+ }
282
+ };
283
+ var settings = new SettingsManager();
284
+
285
+ export {
286
+ SettingsSchema,
287
+ settings
288
+ };