auden 0.1.0-alpha.2

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 (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/auden-paths.d.ts +8 -0
  4. package/dist/auden-paths.d.ts.map +1 -0
  5. package/dist/auden-paths.js +10 -0
  6. package/dist/auden-paths.js.map +1 -0
  7. package/dist/bin.d.ts +11 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +13 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/chunk.d.ts +3 -0
  12. package/dist/chunk.d.ts.map +1 -0
  13. package/dist/chunk.js +13 -0
  14. package/dist/chunk.js.map +1 -0
  15. package/dist/commands/doctor.d.ts +13 -0
  16. package/dist/commands/doctor.d.ts.map +1 -0
  17. package/dist/commands/doctor.js +125 -0
  18. package/dist/commands/doctor.js.map +1 -0
  19. package/dist/commands/eval/index.d.ts +2 -0
  20. package/dist/commands/eval/index.d.ts.map +1 -0
  21. package/dist/commands/eval/index.js +2 -0
  22. package/dist/commands/eval/index.js.map +1 -0
  23. package/dist/commands/eval/run.d.ts +38 -0
  24. package/dist/commands/eval/run.d.ts.map +1 -0
  25. package/dist/commands/eval/run.js +179 -0
  26. package/dist/commands/eval/run.js.map +1 -0
  27. package/dist/commands/guides/active.d.ts +2 -0
  28. package/dist/commands/guides/active.d.ts.map +1 -0
  29. package/dist/commands/guides/active.js +38 -0
  30. package/dist/commands/guides/active.js.map +1 -0
  31. package/dist/commands/guides/index.d.ts +2 -0
  32. package/dist/commands/guides/index.d.ts.map +1 -0
  33. package/dist/commands/guides/index.js +13 -0
  34. package/dist/commands/guides/index.js.map +1 -0
  35. package/dist/commands/guides/project.d.ts +13 -0
  36. package/dist/commands/guides/project.d.ts.map +1 -0
  37. package/dist/commands/guides/project.js +71 -0
  38. package/dist/commands/guides/project.js.map +1 -0
  39. package/dist/commands/guides/search.d.ts +8 -0
  40. package/dist/commands/guides/search.d.ts.map +1 -0
  41. package/dist/commands/guides/search.js +46 -0
  42. package/dist/commands/guides/search.js.map +1 -0
  43. package/dist/commands/init.d.ts +43 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +436 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/mcp.d.ts +23 -0
  48. package/dist/commands/mcp.d.ts.map +1 -0
  49. package/dist/commands/mcp.js +55 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/pull.d.ts +38 -0
  52. package/dist/commands/pull.d.ts.map +1 -0
  53. package/dist/commands/pull.js +127 -0
  54. package/dist/commands/pull.js.map +1 -0
  55. package/dist/commands/rules/export.d.ts +140 -0
  56. package/dist/commands/rules/export.d.ts.map +1 -0
  57. package/dist/commands/rules/export.js +635 -0
  58. package/dist/commands/rules/export.js.map +1 -0
  59. package/dist/commands/rules/import.d.ts +33 -0
  60. package/dist/commands/rules/import.d.ts.map +1 -0
  61. package/dist/commands/rules/import.js +122 -0
  62. package/dist/commands/rules/import.js.map +1 -0
  63. package/dist/commands/rules/index.d.ts +2 -0
  64. package/dist/commands/rules/index.d.ts.map +1 -0
  65. package/dist/commands/rules/index.js +13 -0
  66. package/dist/commands/rules/index.js.map +1 -0
  67. package/dist/commands/rules/watch.d.ts +43 -0
  68. package/dist/commands/rules/watch.d.ts.map +1 -0
  69. package/dist/commands/rules/watch.js +125 -0
  70. package/dist/commands/rules/watch.js.map +1 -0
  71. package/dist/commands/status.d.ts +2 -0
  72. package/dist/commands/status.d.ts.map +1 -0
  73. package/dist/commands/status.js +61 -0
  74. package/dist/commands/status.js.map +1 -0
  75. package/dist/commands/suggest.d.ts +8 -0
  76. package/dist/commands/suggest.d.ts.map +1 -0
  77. package/dist/commands/suggest.js +43 -0
  78. package/dist/commands/suggest.js.map +1 -0
  79. package/dist/commands/sync.d.ts +23 -0
  80. package/dist/commands/sync.d.ts.map +1 -0
  81. package/dist/commands/sync.js +193 -0
  82. package/dist/commands/sync.js.map +1 -0
  83. package/dist/commands/verdict/index.d.ts +2 -0
  84. package/dist/commands/verdict/index.d.ts.map +1 -0
  85. package/dist/commands/verdict/index.js +11 -0
  86. package/dist/commands/verdict/index.js.map +1 -0
  87. package/dist/commands/verdict/record.d.ts +18 -0
  88. package/dist/commands/verdict/record.d.ts.map +1 -0
  89. package/dist/commands/verdict/record.js +60 -0
  90. package/dist/commands/verdict/record.js.map +1 -0
  91. package/dist/config.d.ts +96 -0
  92. package/dist/config.d.ts.map +1 -0
  93. package/dist/config.js +246 -0
  94. package/dist/config.js.map +1 -0
  95. package/dist/context/pull.d.ts +40 -0
  96. package/dist/context/pull.d.ts.map +1 -0
  97. package/dist/context/pull.js +46 -0
  98. package/dist/context/pull.js.map +1 -0
  99. package/dist/dashboard-health.d.ts +20 -0
  100. package/dist/dashboard-health.d.ts.map +1 -0
  101. package/dist/dashboard-health.js +24 -0
  102. package/dist/dashboard-health.js.map +1 -0
  103. package/dist/eval-provider.d.ts +30 -0
  104. package/dist/eval-provider.d.ts.map +1 -0
  105. package/dist/eval-provider.js +359 -0
  106. package/dist/eval-provider.js.map +1 -0
  107. package/dist/eval-summary.d.ts +24 -0
  108. package/dist/eval-summary.d.ts.map +1 -0
  109. package/dist/eval-summary.js +30 -0
  110. package/dist/eval-summary.js.map +1 -0
  111. package/dist/feedback/extract.d.ts +6 -0
  112. package/dist/feedback/extract.d.ts.map +1 -0
  113. package/dist/feedback/extract.js +580 -0
  114. package/dist/feedback/extract.js.map +1 -0
  115. package/dist/http-retry.d.ts +23 -0
  116. package/dist/http-retry.d.ts.map +1 -0
  117. package/dist/http-retry.js +54 -0
  118. package/dist/http-retry.js.map +1 -0
  119. package/dist/index.d.ts +6 -0
  120. package/dist/index.d.ts.map +1 -0
  121. package/dist/index.js +33 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/mcp/client.d.ts +70 -0
  124. package/dist/mcp/client.d.ts.map +1 -0
  125. package/dist/mcp/client.js +121 -0
  126. package/dist/mcp/client.js.map +1 -0
  127. package/dist/mcp/scope.d.ts +30 -0
  128. package/dist/mcp/scope.d.ts.map +1 -0
  129. package/dist/mcp/scope.js +64 -0
  130. package/dist/mcp/scope.js.map +1 -0
  131. package/dist/mcp/server.d.ts +57 -0
  132. package/dist/mcp/server.d.ts.map +1 -0
  133. package/dist/mcp/server.js +427 -0
  134. package/dist/mcp/server.js.map +1 -0
  135. package/dist/mcp/write-items.d.ts +34 -0
  136. package/dist/mcp/write-items.d.ts.map +1 -0
  137. package/dist/mcp/write-items.js +59 -0
  138. package/dist/mcp/write-items.js.map +1 -0
  139. package/dist/rules/deletions-client.d.ts +16 -0
  140. package/dist/rules/deletions-client.d.ts.map +1 -0
  141. package/dist/rules/deletions-client.js +40 -0
  142. package/dist/rules/deletions-client.js.map +1 -0
  143. package/dist/rules/diff.d.ts +19 -0
  144. package/dist/rules/diff.d.ts.map +1 -0
  145. package/dist/rules/diff.js +36 -0
  146. package/dist/rules/diff.js.map +1 -0
  147. package/dist/rules/discover.d.ts +81 -0
  148. package/dist/rules/discover.d.ts.map +1 -0
  149. package/dist/rules/discover.js +307 -0
  150. package/dist/rules/discover.js.map +1 -0
  151. package/dist/rules/file-origin.d.ts +16 -0
  152. package/dist/rules/file-origin.d.ts.map +1 -0
  153. package/dist/rules/file-origin.js +31 -0
  154. package/dist/rules/file-origin.js.map +1 -0
  155. package/dist/rules/global-flag.d.ts +12 -0
  156. package/dist/rules/global-flag.d.ts.map +1 -0
  157. package/dist/rules/global-flag.js +15 -0
  158. package/dist/rules/global-flag.js.map +1 -0
  159. package/dist/rules/import-client.d.ts +37 -0
  160. package/dist/rules/import-client.d.ts.map +1 -0
  161. package/dist/rules/import-client.js +98 -0
  162. package/dist/rules/import-client.js.map +1 -0
  163. package/dist/rules/init-pull.d.ts +34 -0
  164. package/dist/rules/init-pull.d.ts.map +1 -0
  165. package/dist/rules/init-pull.js +43 -0
  166. package/dist/rules/init-pull.js.map +1 -0
  167. package/dist/rules/member-files-client.d.ts +17 -0
  168. package/dist/rules/member-files-client.d.ts.map +1 -0
  169. package/dist/rules/member-files-client.js +29 -0
  170. package/dist/rules/member-files-client.js.map +1 -0
  171. package/dist/rules/path-contains.d.ts +9 -0
  172. package/dist/rules/path-contains.d.ts.map +1 -0
  173. package/dist/rules/path-contains.js +17 -0
  174. package/dist/rules/path-contains.js.map +1 -0
  175. package/dist/rules/payload.d.ts +13 -0
  176. package/dist/rules/payload.d.ts.map +1 -0
  177. package/dist/rules/payload.js +35 -0
  178. package/dist/rules/payload.js.map +1 -0
  179. package/dist/rules/pull-bundle.d.ts +13 -0
  180. package/dist/rules/pull-bundle.d.ts.map +1 -0
  181. package/dist/rules/pull-bundle.js +32 -0
  182. package/dist/rules/pull-bundle.js.map +1 -0
  183. package/dist/rules/watch.d.ts +121 -0
  184. package/dist/rules/watch.d.ts.map +1 -0
  185. package/dist/rules/watch.js +457 -0
  186. package/dist/rules/watch.js.map +1 -0
  187. package/dist/skill-template.d.ts +19 -0
  188. package/dist/skill-template.d.ts.map +1 -0
  189. package/dist/skill-template.js +174 -0
  190. package/dist/skill-template.js.map +1 -0
  191. package/dist/sync-batches.d.ts +37 -0
  192. package/dist/sync-batches.d.ts.map +1 -0
  193. package/dist/sync-batches.js +67 -0
  194. package/dist/sync-batches.js.map +1 -0
  195. package/dist/sync-client.d.ts +22 -0
  196. package/dist/sync-client.d.ts.map +1 -0
  197. package/dist/sync-client.js +38 -0
  198. package/dist/sync-client.js.map +1 -0
  199. package/dist/sync-response.d.ts +23 -0
  200. package/dist/sync-response.d.ts.map +1 -0
  201. package/dist/sync-response.js +22 -0
  202. package/dist/sync-response.js.map +1 -0
  203. package/dist/token-verify.d.ts +14 -0
  204. package/dist/token-verify.d.ts.map +1 -0
  205. package/dist/token-verify.js +30 -0
  206. package/dist/token-verify.js.map +1 -0
  207. package/dist/usage/extract.d.ts +31 -0
  208. package/dist/usage/extract.d.ts.map +1 -0
  209. package/dist/usage/extract.js +200 -0
  210. package/dist/usage/extract.js.map +1 -0
  211. package/dist/usage/providers.d.ts +8 -0
  212. package/dist/usage/providers.d.ts.map +1 -0
  213. package/dist/usage/providers.js +23 -0
  214. package/dist/usage/providers.js.map +1 -0
  215. package/dist/verdict-queue.d.ts +50 -0
  216. package/dist/verdict-queue.d.ts.map +1 -0
  217. package/dist/verdict-queue.js +131 -0
  218. package/dist/verdict-queue.js.map +1 -0
  219. package/package.json +72 -0
@@ -0,0 +1,457 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { watch as fsWatch } from 'node:fs';
3
+ import { lstat, readFile, stat } from 'node:fs/promises';
4
+ import { homedir as osHomedir } from 'node:os';
5
+ import { dirname, join, relative, resolve } from 'node:path';
6
+ import { detectFormat, isSkillMemberPath } from '@auden.to/projections';
7
+ import { rescanSkill } from './discover.js';
8
+ import { isPathWithin } from './path-contains.js';
9
+ import { buildRulePayload } from './payload.js';
10
+ function sha256(content) {
11
+ return createHash('sha256').update(content, 'utf8').digest('hex');
12
+ }
13
+ /** Fingerprint of just a skill's member set (paths + hashes, skipped list). */
14
+ function memberSetSignature(file) {
15
+ if (!file.members)
16
+ return `withheld:${file.membersSkipped ?? 0}`;
17
+ const members = file.members
18
+ .map((member) => `${member.path}:${member.contentHash}`)
19
+ .sort()
20
+ .join('\n');
21
+ const skipped = (file.membersSkippedPaths ?? []).slice().sort().join(',');
22
+ return `members=${members}||skipped=${skipped}`;
23
+ }
24
+ /**
25
+ * Stable fingerprint of everything a skill's re-sync payload carries — the
26
+ * SKILL.md body plus its member set. `rules watch` always re-sends a skill's
27
+ * whole authoritative member list, so this covers both a SKILL.md edit and a
28
+ * member edit and lets a touched-but-unchanged event (or a redundant re-scan
29
+ * queued behind an identical one) skip the network call.
30
+ */
31
+ function skillSyncSignature(file) {
32
+ return `${file.contentHash}::${memberSetSignature(file)}`;
33
+ }
34
+ async function defaultReadFile(absolutePath) {
35
+ try {
36
+ // lstat (not stat): a watched path that is itself a symlink (e.g.
37
+ // .agents/sneaky -> ~/.ssh/id_rsa) must not be followed, read, and synced
38
+ // to the dashboard.
39
+ const info = await lstat(absolutePath);
40
+ if (!info.isFile())
41
+ return null;
42
+ const raw = await readFile(absolutePath, 'utf8');
43
+ return { rawContent: raw, lastModified: Math.floor(info.mtimeMs) };
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ /**
50
+ * Stateful engine that turns raw fs events into batched import/delete calls.
51
+ * Exposed so tests can drive it deterministically.
52
+ *
53
+ * Per-path debouncing collapses editor save bursts. A deletion is only
54
+ * reported after `deleteStabilityMs` confirms the file is still gone — this
55
+ * lets atomic delete-then-create saves resolve as a change instead.
56
+ */
57
+ export class RuleWatchEngine {
58
+ allowedRoots;
59
+ source;
60
+ debounceMs;
61
+ deleteStabilityMs;
62
+ sendImports;
63
+ sendDeletions;
64
+ log;
65
+ readFileImpl;
66
+ rescanSkillImpl;
67
+ known = new Map();
68
+ pending = new Map();
69
+ // Tracks the stability-window timer per path so shutdown (or a fresh event)
70
+ // can cancel it before it fires. Without this a Ctrl+C during the window
71
+ // could still POST a deletion after the engine reported "stopped".
72
+ deletionTimers = new Map();
73
+ // Per-skill (keyed by the SKILL.md absolute path) tail of the re-sync chain.
74
+ // Every skill re-sync appends here so concurrent triggers for the same skill
75
+ // run one-at-a-time — each re-scan sees the previous POST's outcome, so a
76
+ // slower earlier snapshot can't land after a newer one and revert it.
77
+ skillChains = new Map();
78
+ stop = null;
79
+ stopped = false;
80
+ constructor(options) {
81
+ this.allowedRoots = (options.allowedRoots ?? [options.cwd]).map((r) => resolve(r));
82
+ this.source = options.source;
83
+ this.debounceMs = options.debounceMs;
84
+ this.deleteStabilityMs = options.deleteStabilityMs;
85
+ this.log = options.log ?? ((line) => console.log(line));
86
+ this.readFileImpl = options.readFileImpl ?? defaultReadFile;
87
+ this.rescanSkillImpl = options.rescanSkillImpl ?? rescanSkill;
88
+ this.sendImports =
89
+ options.sendImports ??
90
+ (async () => {
91
+ throw new Error('sendImports not configured');
92
+ });
93
+ this.sendDeletions =
94
+ options.sendDeletions ??
95
+ (async () => {
96
+ throw new Error('sendDeletions not configured');
97
+ });
98
+ for (const file of options.initial) {
99
+ this.known.set(file.absolutePath, {
100
+ absolutePath: file.absolutePath,
101
+ payloadPath: file.payloadPath,
102
+ displayPath: file.displayPath,
103
+ format: file.format,
104
+ contentHash: file.contentHash,
105
+ // Seed the skill fingerprint from the initial scan so a later event
106
+ // that leaves body + members unchanged skips a redundant re-sync.
107
+ // Spread (not assign undefined) to satisfy exactOptionalPropertyTypes.
108
+ ...(file.format === 'skill-md'
109
+ ? { syncSignature: skillSyncSignature(file) }
110
+ : {}),
111
+ });
112
+ }
113
+ }
114
+ start() {
115
+ if (this.stop)
116
+ return;
117
+ this.stop = this.source.start((event) => this.onEvent(event));
118
+ }
119
+ async shutdown() {
120
+ this.stopped = true;
121
+ for (const timer of this.pending.values())
122
+ clearTimeout(timer);
123
+ this.pending.clear();
124
+ for (const timer of this.deletionTimers.values())
125
+ clearTimeout(timer);
126
+ this.deletionTimers.clear();
127
+ // Drop references to in-flight re-sync chains; queued `doResyncSkill` calls
128
+ // already no-op on the `stopped` flag set above.
129
+ this.skillChains.clear();
130
+ if (!this.stop)
131
+ return;
132
+ const stop = this.stop;
133
+ this.stop = null;
134
+ await stop();
135
+ }
136
+ /** @internal — test helper to drive an event without going through the source. */
137
+ injectEvent(event) {
138
+ this.onEvent(event);
139
+ }
140
+ /** @internal — test helper to flush a pending debounce immediately. */
141
+ async flush(absolutePath) {
142
+ const timer = this.pending.get(absolutePath);
143
+ if (!timer)
144
+ return;
145
+ clearTimeout(timer);
146
+ this.pending.delete(absolutePath);
147
+ await this.process(absolutePath);
148
+ }
149
+ onEvent(event) {
150
+ if (this.stopped)
151
+ return;
152
+ const abs = resolve(event.absolutePath);
153
+ const accepted = this.known.has(abs) || this.allowedRoots.some((root) => isPathWithin(root, abs));
154
+ if (!accepted)
155
+ return;
156
+ // A fresh event invalidates any in-flight deletion stability window for
157
+ // the same path — the file is clearly being touched again.
158
+ const pendingDelete = this.deletionTimers.get(abs);
159
+ if (pendingDelete) {
160
+ clearTimeout(pendingDelete);
161
+ this.deletionTimers.delete(abs);
162
+ }
163
+ const existing = this.pending.get(abs);
164
+ if (existing)
165
+ clearTimeout(existing);
166
+ const timer = setTimeout(() => {
167
+ this.pending.delete(abs);
168
+ void this.process(abs).catch((err) => {
169
+ this.log(` watch error on ${abs}: ${err instanceof Error ? err.message : err}`);
170
+ });
171
+ }, this.debounceMs);
172
+ this.pending.set(abs, timer);
173
+ }
174
+ async process(absolutePath) {
175
+ if (this.stopped)
176
+ return;
177
+ // Skill member content (scripts/references/assets) never imports on its
178
+ // own — a member add/edit/delete re-syncs the whole owning skill so the
179
+ // server's authoritative member list stays complete. Route these before
180
+ // the single-file path below, which only understands top-level guide
181
+ // files. A member with no tracked owning skill (its SKILL.md hasn't synced
182
+ // yet) is dropped here; the SKILL.md's own event re-scans members on
183
+ // arrival (see the skill-md branch below), so the skill still lands whole.
184
+ if (!this.known.has(absolutePath) && isSkillMemberPath(absolutePath)) {
185
+ const owner = this.findOwningSkill(absolutePath);
186
+ if (owner)
187
+ await this.resyncSkill(owner);
188
+ return;
189
+ }
190
+ const file = await this.readFileImpl(absolutePath);
191
+ const known = this.known.get(absolutePath);
192
+ if (!file) {
193
+ // File missing right now. If we already knew about it, schedule a
194
+ // deletion after the stability window — but skip if a fresh event comes
195
+ // in for the same path first (handled by re-entering process via the
196
+ // debounce timer).
197
+ if (!known)
198
+ return;
199
+ this.scheduleDeletion(known);
200
+ return;
201
+ }
202
+ // File present — either fresh discovery or content change. Compute format
203
+ // if we didn't know about it yet.
204
+ let format = known?.format;
205
+ let payloadPath = known?.payloadPath;
206
+ let displayPath = known?.displayPath;
207
+ if (!format || !payloadPath || !displayPath) {
208
+ const detected = detectFormat(absolutePath);
209
+ if (!detected) {
210
+ // Watched root surfaced a file we don't understand — ignore silently.
211
+ return;
212
+ }
213
+ format = detected;
214
+ const root = this.allowedRoots.find((r) => isPathWithin(r, absolutePath));
215
+ const rel = root ? relative(root, absolutePath).replaceAll('\\', '/') : absolutePath;
216
+ payloadPath = rel;
217
+ displayPath = rel;
218
+ }
219
+ // A SKILL.md event syncs the skill *whole* — body plus its authoritative
220
+ // member set — exactly like the initial discovery scan. This is what makes
221
+ // a freshly-created (or bulk-copied) skill import its supporting files, not
222
+ // just the SKILL.md, without waiting for a later member edit. Register the
223
+ // skill so member events can find their owner, then hand off to the
224
+ // serialized re-sync (which dedups an unchanged body + member set).
225
+ if (format === 'skill-md') {
226
+ const skill = this.known.get(absolutePath);
227
+ if (!skill) {
228
+ this.known.set(absolutePath, {
229
+ absolutePath,
230
+ payloadPath,
231
+ displayPath,
232
+ format,
233
+ contentHash: null,
234
+ });
235
+ }
236
+ await this.resyncSkill(this.known.get(absolutePath));
237
+ return;
238
+ }
239
+ const contentHash = sha256(file.rawContent);
240
+ if (known && known.contentHash === contentHash) {
241
+ // No-op: same bytes (e.g. touch without edit).
242
+ return;
243
+ }
244
+ const payload = buildRulePayload({
245
+ absolutePath,
246
+ payloadPath,
247
+ displayPath,
248
+ format,
249
+ rawContent: file.rawContent,
250
+ lastModified: file.lastModified,
251
+ contentHash,
252
+ });
253
+ try {
254
+ await this.sendImports([payload]);
255
+ this.known.set(absolutePath, {
256
+ absolutePath,
257
+ payloadPath,
258
+ displayPath,
259
+ format,
260
+ contentHash,
261
+ });
262
+ this.log(` synced ${displayPath} (${contentHash.slice(0, 12)})`);
263
+ }
264
+ catch (err) {
265
+ this.log(` failed to sync ${displayPath}: ${err instanceof Error ? err.message : err}`);
266
+ }
267
+ }
268
+ /**
269
+ * Find the tracked SKILL.md whose directory most tightly contains
270
+ * `absolutePath` — the skill a changed member file belongs to. Longest
271
+ * match wins so a nested skill owns its own subtree.
272
+ */
273
+ findOwningSkill(absolutePath) {
274
+ let best;
275
+ let bestLen = -1;
276
+ for (const file of this.known.values()) {
277
+ if (file.format !== 'skill-md')
278
+ continue;
279
+ const skillDir = dirname(file.absolutePath);
280
+ if (isPathWithin(skillDir, absolutePath) && skillDir.length > bestLen) {
281
+ best = file;
282
+ bestLen = skillDir.length;
283
+ }
284
+ }
285
+ return best;
286
+ }
287
+ /**
288
+ * Re-scan a skill's directory and re-send its SKILL.md payload with a fresh
289
+ * members array, serialized per owning skill. The server treats that array as
290
+ * the complete member set, so a member (or SKILL.md) add/edit/delete
291
+ * propagates by re-sending the whole skill. Chaining on `skillChains` keeps
292
+ * two near-simultaneous events for the same skill from POSTing concurrently —
293
+ * an earlier, staler snapshot must not land after a newer one and revert it.
294
+ */
295
+ resyncSkill(skill) {
296
+ const prev = this.skillChains.get(skill.absolutePath) ?? Promise.resolve();
297
+ const next = prev.then(() => this.doResyncSkill(skill));
298
+ // Store a non-rejecting tail so one failed sync doesn't wedge the chain,
299
+ // while callers still await the real (possibly rejecting) `next`.
300
+ this.skillChains.set(skill.absolutePath, next.catch(() => { }));
301
+ return next;
302
+ }
303
+ async doResyncSkill(skill) {
304
+ if (this.stopped)
305
+ return;
306
+ const discovered = await this.rescanSkillImpl({
307
+ skillMdAbsolutePath: skill.absolutePath,
308
+ skillMdPayloadPath: skill.payloadPath,
309
+ skillMdDisplayPath: skill.displayPath,
310
+ });
311
+ if (!discovered) {
312
+ // SKILL.md itself is gone — its own deletion event retires the guide and
313
+ // its member rows; nothing to re-sync here.
314
+ return;
315
+ }
316
+ const signature = skillSyncSignature(discovered);
317
+ // Skip when nothing the payload carries changed (touched-but-unedited file,
318
+ // binary asset write, or a duplicate re-scan queued behind an identical one).
319
+ if (skill.syncSignature === signature)
320
+ return;
321
+ const payload = buildRulePayload(discovered);
322
+ try {
323
+ await this.sendImports([payload]);
324
+ // Mutating the tracked KnownFile in place (same reference as the map
325
+ // entry) records what we just synced.
326
+ skill.syncSignature = signature;
327
+ skill.contentHash = discovered.contentHash;
328
+ this.log(` synced ${discovered.displayPath}`);
329
+ }
330
+ catch (err) {
331
+ this.log(` failed to sync ${discovered.displayPath}: ${err instanceof Error ? err.message : err}`);
332
+ }
333
+ }
334
+ scheduleDeletion(known) {
335
+ if (this.deleteStabilityMs <= 0) {
336
+ void this.fireDeletion(known);
337
+ return;
338
+ }
339
+ // Cancel any previous deletion in flight for this path; the latest event
340
+ // wins and resets the stability window.
341
+ const existing = this.deletionTimers.get(known.absolutePath);
342
+ if (existing)
343
+ clearTimeout(existing);
344
+ const timer = setTimeout(async () => {
345
+ this.deletionTimers.delete(known.absolutePath);
346
+ if (this.stopped)
347
+ return;
348
+ const stillGone = await this.readFileImpl(known.absolutePath);
349
+ if (stillGone) {
350
+ // Recovered within the window — re-run process so the new content is
351
+ // sent as an import.
352
+ await this.process(known.absolutePath);
353
+ return;
354
+ }
355
+ await this.fireDeletion(known);
356
+ }, this.deleteStabilityMs);
357
+ this.deletionTimers.set(known.absolutePath, timer);
358
+ }
359
+ async fireDeletion(known) {
360
+ if (this.stopped)
361
+ return;
362
+ const deletion = {
363
+ path: known.payloadPath,
364
+ format: known.format,
365
+ };
366
+ try {
367
+ await this.sendDeletions([deletion]);
368
+ this.known.delete(known.absolutePath);
369
+ this.log(` disabled ${known.displayPath} (file removed)`);
370
+ }
371
+ catch (err) {
372
+ this.log(` failed to disable ${known.displayPath}: ${err instanceof Error ? err.message : err}`);
373
+ }
374
+ }
375
+ }
376
+ // Top-level files we watch the cwd for so creation/rename of these specific
377
+ // names is caught even when they don't exist at start. Anything else under
378
+ // cwd is the user's repo (often huge) — we don't follow it.
379
+ const PROJECT_TOP_LEVEL_FILES = ['AGENTS.md', 'CLAUDE.md', '.cursorrules'];
380
+ const PROJECT_GUIDE_DIRS = ['.agents', '.claude', '.cursor/rules'];
381
+ // Global rule directories scanned when --global is set. Cursor rules are
382
+ // scoped to `.cursor/rules` (not the whole `.cursor/` tree) so we don't watch
383
+ // unrelated Cursor state — chat history, indexes — especially under `~/.cursor`.
384
+ const GLOBAL_GUIDE_DIRS = ['.claude', '.cursor/rules'];
385
+ export function createFsWatchSource(options) {
386
+ return {
387
+ start(onEvent) {
388
+ const watchers = [];
389
+ const home = options.global ? (options.homedir ?? osHomedir()) : null;
390
+ const watchImpl = options.watchImpl ?? ((p, o, l) => fsWatch(p, o, l));
391
+ const tryWatch = async (root, recursive, relativeBase, displayBase, nameFilter) => {
392
+ try {
393
+ const info = await stat(root);
394
+ if (!info.isDirectory() && !info.isFile())
395
+ return;
396
+ }
397
+ catch {
398
+ return;
399
+ }
400
+ const handler = (_eventType, filename) => {
401
+ if (!filename)
402
+ return;
403
+ if (nameFilter && !nameFilter(filename))
404
+ return;
405
+ const absolutePath = join(root, filename);
406
+ const payloadPath = join(relativeBase, filename).replaceAll('\\', '/');
407
+ const displayPath = join(displayBase, filename).replaceAll('\\', '/');
408
+ // Pre-filter to supported guide files plus skill member content
409
+ // (scripts/references/assets under a skills/ tree). Member paths have
410
+ // no format of their own; the engine routes them to a whole-skill
411
+ // re-scan. Everything else is dropped to keep the noise down.
412
+ if (!detectFormat(payloadPath) && !isSkillMemberPath(payloadPath))
413
+ return;
414
+ onEvent({
415
+ kind: 'change',
416
+ absolutePath,
417
+ payloadPath,
418
+ displayPath,
419
+ });
420
+ };
421
+ try {
422
+ watchers.push(watchImpl(root, { recursive }, handler));
423
+ }
424
+ catch {
425
+ // Best-effort: a missing directory just means we silently skip it
426
+ // until the user creates one. fs.watch can also throw EACCES on
427
+ // restricted homedirs — skip and continue.
428
+ }
429
+ };
430
+ // Watch cwd non-recursively, filtered to the three top-level guide
431
+ // files. Recursive cwd watch would generate huge event volume on real
432
+ // repos (node_modules, build outputs) only to drop everything in the
433
+ // engine. Guide directories below get their own recursive watcher.
434
+ const projectFiles = new Set(PROJECT_TOP_LEVEL_FILES);
435
+ void tryWatch(options.cwd, false, '', '', (name) => projectFiles.has(name));
436
+ for (const dir of PROJECT_GUIDE_DIRS) {
437
+ void tryWatch(join(options.cwd, dir), true, dir, dir);
438
+ }
439
+ if (home) {
440
+ for (const dir of GLOBAL_GUIDE_DIRS) {
441
+ void tryWatch(join(home, dir), true, dir, `~/${dir}`);
442
+ }
443
+ }
444
+ return async () => {
445
+ for (const w of watchers) {
446
+ try {
447
+ w.close();
448
+ }
449
+ catch {
450
+ // Already closed or stale handle — fine.
451
+ }
452
+ }
453
+ };
454
+ },
455
+ };
456
+ }
457
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/rules/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE5D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEvE,OAAO,EAAE,WAAW,EAA4B,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAkF/C,SAAS,MAAM,CAAC,OAAe;IAC7B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACnE,CAAC;AAED,+EAA+E;AAC/E,SAAS,kBAAkB,CAAC,IAAyB;IACnD,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,OAAO,YAAY,IAAI,CAAC,cAAc,IAAI,CAAC,EAAE,CAAA;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;SACzB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;SACvD,IAAI,EAAE;SACN,IAAI,CAAC,IAAI,CAAC,CAAA;IACb,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzE,OAAO,WAAW,OAAO,aAAa,OAAO,EAAE,CAAA;AACjD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,IAAyB;IACnD,OAAO,GAAG,IAAI,CAAC,WAAW,KAAK,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAA;AAC3D,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,YAAoB;IACjD,IAAI,CAAC;QACH,kEAAkE;QAClE,0EAA0E;QAC1E,oBAAoB;QACpB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,CAAA;QACtC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAA;QAC/B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;QAChD,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAA;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,eAAe;IACT,YAAY,CAAU;IACtB,MAAM,CAAkB;IACxB,UAAU,CAAQ;IAClB,iBAAiB,CAAQ;IACzB,WAAW,CAAoD;IAC/D,aAAa,CAAsD;IACnE,GAAG,CAAwB;IAC3B,YAAY,CAAiD;IAC7D,eAAe,CAAoB;IAEnC,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAA;IACpC,OAAO,GAAG,IAAI,GAAG,EAAyC,CAAA;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,mEAAmE;IAClD,cAAc,GAAG,IAAI,GAAG,EAAyC,CAAA;IAClF,6EAA6E;IAC7E,6EAA6E;IAC7E,0EAA0E;IAC1E,sEAAsE;IACrD,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAA;IACvD,IAAI,GAAiC,IAAI,CAAA;IACzC,OAAO,GAAG,KAAK,CAAA;IAEvB,YAAY,OAA2B;QACrC,IAAI,CAAC,YAAY,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;QAClF,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAA;QACpC,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAA;QAClD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;QACvD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,eAAe,CAAA;QAC3D,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,WAAW,CAAA;QAC7D,IAAI,CAAC,WAAW;YACd,OAAO,CAAC,WAAW;gBACnB,CAAC,KAAK,IAAI,EAAE;oBACV,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;gBAC/C,CAAC,CAAC,CAAA;QACJ,IAAI,CAAC,aAAa;YAChB,OAAO,CAAC,aAAa;gBACrB,CAAC,KAAK,IAAI,EAAE;oBACV,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;gBACjD,CAAC,CAAC,CAAA;QAEJ,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE;gBAChC,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,oEAAoE;gBACpE,kEAAkE;gBAClE,uEAAuE;gBACvE,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU;oBAC5B,CAAC,CAAC,EAAE,aAAa,EAAE,kBAAkB,CAAC,IAAI,CAAC,EAAE;oBAC7C,CAAC,CAAC,EAAE,CAAC;aACR,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,IAAI;YAAE,OAAM;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAC/D,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,YAAY,CAAC,KAAK,CAAC,CAAA;QAC9D,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;QACpB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;YAAE,YAAY,CAAC,KAAK,CAAC,CAAA;QACrE,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAC3B,4EAA4E;QAC5E,iDAAiD;QACjD,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAA;QACxB,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAM;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,MAAM,IAAI,EAAE,CAAA;IACd,CAAC;IAED,kFAAkF;IAClF,WAAW,CAAC,KAAiB;QAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;IAED,uEAAuE;IACvE,KAAK,CAAC,KAAK,CAAC,YAAoB;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,YAAY,CAAC,KAAK,CAAC,CAAA;QACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACjC,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;IAClC,CAAC;IAEO,OAAO,CAAC,KAAiB;QAC/B,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAEvC,MAAM,QAAQ,GACZ,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;QAClF,IAAI,CAAC,QAAQ;YAAE,OAAM;QAErB,wEAAwE;QACxE,2DAA2D;QAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAClD,IAAI,aAAa,EAAE,CAAC;YAClB,YAAY,CAAC,aAAa,CAAC,CAAA;YAC3B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACjC,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACtC,IAAI,QAAQ;YAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;QAEpC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACxB,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACnC,IAAI,CAAC,GAAG,CAAC,oBAAoB,GAAG,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAA;YAClF,CAAC,CAAC,CAAA;QACJ,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;QACnB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAC9B,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,YAAoB;QACxC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QAExB,wEAAwE;QACxE,wEAAwE;QACxE,wEAAwE;QACxE,qEAAqE;QACrE,2EAA2E;QAC3E,qEAAqE;QACrE,2EAA2E;QAC3E,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;YACrE,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAA;YAChD,IAAI,KAAK;gBAAE,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAA;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAE1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,kEAAkE;YAClE,wEAAwE;YACxE,qEAAqE;YACrE,mBAAmB;YACnB,IAAI,CAAC,KAAK;gBAAE,OAAM;YAClB,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;YAC5B,OAAM;QACR,CAAC;QAED,0EAA0E;QAC1E,kCAAkC;QAClC,IAAI,MAAM,GAAG,KAAK,EAAE,MAAM,CAAA;QAC1B,IAAI,WAAW,GAAG,KAAK,EAAE,WAAW,CAAA;QACpC,IAAI,WAAW,GAAG,KAAK,EAAE,WAAW,CAAA;QAEpC,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAA;YAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,sEAAsE;gBACtE,OAAM;YACR,CAAC;YACD,MAAM,GAAG,QAAQ,CAAA;YACjB,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAA;YACzE,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAA;YACpF,WAAW,GAAG,GAAG,CAAA;YACjB,WAAW,GAAG,GAAG,CAAA;QACnB,CAAC;QAED,yEAAyE;QACzE,2EAA2E;QAC3E,4EAA4E;QAC5E,2EAA2E;QAC3E,oEAAoE;QACpE,oEAAoE;QACpE,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;YAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE;oBAC3B,YAAY;oBACZ,WAAW;oBACX,WAAW;oBACX,MAAM;oBACN,WAAW,EAAE,IAAI;iBAClB,CAAC,CAAA;YACJ,CAAC;YACD,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAE,CAAC,CAAA;YACrD,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAC3C,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;YAC/C,+CAA+C;YAC/C,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAwB,gBAAgB,CAAC;YACpD,YAAY;YACZ,WAAW;YACX,WAAW;YACX,MAAM;YACN,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,WAAW;SACZ,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;YACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE;gBAC3B,YAAY;gBACZ,WAAW;gBACX,WAAW;gBACX,MAAM;gBACN,WAAW;aACZ,CAAC,CAAA;YACF,IAAI,CAAC,GAAG,CAAC,YAAY,WAAW,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAA;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CACN,oBAAoB,WAAW,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAC/E,CAAA;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,eAAe,CAAC,YAAoB;QAC1C,IAAI,IAA2B,CAAA;QAC/B,IAAI,OAAO,GAAG,CAAC,CAAC,CAAA;QAChB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;gBAAE,SAAQ;YACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;YAC3C,IAAI,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;gBACtE,IAAI,GAAG,IAAI,CAAA;gBACX,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA;YAC3B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;;;OAOG;IACK,WAAW,CAAC,KAAgB;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;QAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA;QACvD,yEAAyE;QACzE,kEAAkE;QAClE,IAAI,CAAC,WAAW,CAAC,GAAG,CAClB,KAAK,CAAC,YAAY,EAClB,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CACrB,CAAA;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,KAAgB;QAC1C,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC;YAC5C,mBAAmB,EAAE,KAAK,CAAC,YAAY;YACvC,kBAAkB,EAAE,KAAK,CAAC,WAAW;YACrC,kBAAkB,EAAE,KAAK,CAAC,WAAW;SACtC,CAAC,CAAA;QACF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,yEAAyE;YACzE,4CAA4C;YAC5C,OAAM;QACR,CAAC;QAED,MAAM,SAAS,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAA;QAChD,4EAA4E;QAC5E,8EAA8E;QAC9E,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;YAAE,OAAM;QAE7C,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;QAC5C,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;YACjC,qEAAqE;YACrE,sCAAsC;YACtC,KAAK,CAAC,aAAa,GAAG,SAAS,CAAA;YAC/B,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC,WAAW,CAAA;YAC1C,IAAI,CAAC,GAAG,CAAC,YAAY,UAAU,CAAC,WAAW,EAAE,CAAC,CAAA;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CACN,oBAAoB,UAAU,CAAC,WAAW,KACxC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GACvC,EAAE,CACH,CAAA;QACH,CAAC;IACH,CAAC;IAEO,gBAAgB,CAAC,KAAgB;QACvC,IAAI,IAAI,CAAC,iBAAiB,IAAI,CAAC,EAAE,CAAC;YAChC,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;QACD,yEAAyE;QACzE,wCAAwC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAC5D,IAAI,QAAQ;YAAE,YAAY,CAAC,QAAQ,CAAC,CAAA;QAEpC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;YAClC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;YAC9C,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAM;YACxB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;YAC7D,IAAI,SAAS,EAAE,CAAC;gBACd,qEAAqE;gBACrE,qBAAqB;gBACrB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;gBACtC,OAAM;YACR,CAAC;YACD,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QAChC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAA;QAC1B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;IACpD,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,KAAgB;QACzC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAM;QACxB,MAAM,QAAQ,GAAyB;YACrC,IAAI,EAAE,KAAK,CAAC,WAAW;YACvB,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAA;QACD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YACpC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;YACrC,IAAI,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,WAAW,iBAAiB,CAAC,CAAA;QAC5D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CACN,uBAAuB,KAAK,CAAC,WAAW,KACtC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GACvC,EAAE,CACH,CAAA;QACH,CAAC;IACH,CAAC;CACF;AAsBD,4EAA4E;AAC5E,2EAA2E;AAC3E,4DAA4D;AAC5D,MAAM,uBAAuB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,CAAC,CAAA;AAC1E,MAAM,kBAAkB,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,eAAe,CAAC,CAAA;AAClE,yEAAyE;AACzE,8EAA8E;AAC9E,iFAAiF;AACjF,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;AAEtD,MAAM,UAAU,mBAAmB,CAAC,OAA8B;IAChE,OAAO;QACL,KAAK,CAAC,OAAO;YACX,MAAM,QAAQ,GAAgB,EAAE,CAAA;YAChC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YAErE,MAAM,SAAS,GACb,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAyB,CAAC,CAAA;YAE9E,MAAM,QAAQ,GAAG,KAAK,EACpB,IAAY,EACZ,SAAkB,EAClB,YAAoB,EACpB,WAAmB,EACnB,UAAsC,EACtC,EAAE;gBACF,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;oBAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;wBAAE,OAAM;gBACnD,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAM;gBACR,CAAC;gBAED,MAAM,OAAO,GAAG,CAAC,UAAkB,EAAE,QAAuB,EAAE,EAAE;oBAC9D,IAAI,CAAC,QAAQ;wBAAE,OAAM;oBACrB,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;wBAAE,OAAM;oBAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;oBACzC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;oBACtE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;oBACrE,gEAAgE;oBAChE,sEAAsE;oBACtE,kEAAkE;oBAClE,8DAA8D;oBAC9D,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC;wBAAE,OAAM;oBACzE,OAAO,CAAC;wBACN,IAAI,EAAE,QAAQ;wBACd,YAAY;wBACZ,WAAW;wBACX,WAAW;qBACZ,CAAC,CAAA;gBACJ,CAAC,CAAA;gBAED,IAAI,CAAC;oBACH,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;gBACxD,CAAC;gBAAC,MAAM,CAAC;oBACP,kEAAkE;oBAClE,gEAAgE;oBAChE,2CAA2C;gBAC7C,CAAC;YACH,CAAC,CAAA;YAED,mEAAmE;YACnE,sEAAsE;YACtE,qEAAqE;YACrE,mEAAmE;YACnE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,uBAAuB,CAAC,CAAA;YAC7D,KAAK,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YAE3E,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;gBACrC,KAAK,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACvD,CAAC;YACD,IAAI,IAAI,EAAE,CAAC;gBACT,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;oBACpC,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,CAAC,CAAA;gBACvD,CAAC;YACH,CAAC;YAED,OAAO,KAAK,IAAI,EAAE;gBAChB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACzB,IAAI,CAAC;wBACH,CAAC,CAAC,KAAK,EAAE,CAAA;oBACX,CAAC;oBAAC,MAAM,CAAC;wBACP,yCAAyC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ export declare const SKILL_MD = "---\nname: auden\ndescription: >-\n Invoke when the user asks about Auden, evaluation results, or what happened\n in the last session. Surfaces the current guide cache, lets the user inspect\n or manually record verdicts, and shows pending guide suggestions. Do NOT call\n this automatically before or after actions \u2014 Auden evaluates sessions\n post-hoc; guides already flow into the agent's context via AGENTS.md and\n CLAUDE.md.\nuser-invocable: true\n---\n\n# Auden\n\nAuden is an on-device agent analytics layer. After each Claude Code session the Stop hook runs `auden eval`, which scores the session against your active guides and prints an alignment summary. Evaluation is post-hoc and happens once per session \u2014 not per action.\n\n## When To Invoke This Skill\n\nOnly when the user explicitly asks. Examples:\n\n- \"What did Auden say about the last session?\"\n- \"Show me the active guides\"\n- \"Did the agent follow the guides?\"\n- \"Run auden suggest\"\n\nDo NOT call `auden` commands during normal task execution. Guides already reach you through `AGENTS.md` / `CLAUDE.md` / `.cursorrules` \u2014 Auden's job is to evaluate what happened afterwards, not to gate each action.\n\n## Commands\n\n### `auden guides active`\n\nLists all currently enabled guides for this project, read from the local cache.\n\n```bash\nauden guides active\n```\n\n### `auden guides search <query>`\n\nSearches active guides by keyword.\n\n```bash\nauden guides search \"TypeScript\"\nauden guides search \"testing\"\n```\n\n### `auden verdict record`\n\nManually records an alignment verdict and queues it for the next `auden sync`. Use when the user wants to log a specific outcome. The Stop hook (`auden eval`) evaluates sessions but does not enqueue verdicts automatically.\n\n```bash\nauden verdict record --verdict aligned --summary \"ran tests before committing\"\nauden verdict record --verdict misaligned --summary \"used var instead of const\"\nauden verdict record --verdict unguided --summary \"added a new pattern with no existing rule\"\n```\n\n**Verdict values:** `aligned` | `misaligned` | `unguided`\n\n### `auden suggest`\n\nSurfaces guide suggestions extracted from recent session history.\n\n```bash\nauden suggest\n```\n\n### `auden sync`\n\nPushes queued verdicts and extracted guide/skill suggestions to the dashboard, and pulls the latest guide bundle. Verdicts recorded with `auden verdict record` are transmitted on the next `auden sync`.\n\n```bash\nauden sync\n```\n\n## Notes\n\n- Guides are cached in `~/.auden/guides.json` after `auden sync`. `guides active` and `guides search` read from cache \u2014 no network requests.\n- Verdicts are queued locally in `~/.auden/queue/` and sent to the dashboard on the next `auden sync` (queue files are deleted after a successful send).\n- The Stop hook (`auden eval`) is installed by `auden init` and runs once when the Claude Code session ends.\n";
2
+ export declare const AUDEN_CONTEXT_SKILL_MD = "---\nname: auden-context\ndescription: >-\n Use when the user refers to their notes, context, inbox, or bundles saved in\n Auden \u2014 e.g. \"pull my notes from Auden\", \"what's in my inbox\", \"save this to\n my context\", \"sync this back\". Reads and writes the Auden context layer over\n the Auden MCP server so context follows the user across every repo and agent.\nuser-invocable: true\n---\n\n# Auden Context\n\nAuden's context layer is a portable store of the user's canonical documents,\nnotes, and reference material. It lives on the Auden dashboard and is reachable\nfrom any repo through the **Auden MCP server** (`auden mcp`, configured once per\nagent). Items are *canonical, not copies*: a document can belong to many bundles,\nand editing it once propagates the change everywhere it is a member. Plain\nMarkdown/text is the source of truth.\n\nTwo surfaces sit on top of it:\n\n- **Bundles** \u2014 named collections (`notes`, `travel-log`, \u2026) you pull scoped\n context from and push canonical results into.\n- **Inbox** \u2014 a reserved bundle the user captures raw notes into (from the phone,\n the app, or a share sheet). Agents pull recent inbox items, transform them, and\n archive what they consumed.\n\n## When To Use\n\nInvoke when the user references their own saved context, for example:\n\n- \"Pull my notes from the last day and summarize them.\"\n- \"What context do I have on <topic>?\" / \"Search my Auden bundles for <x>.\"\n- \"Save this document to my `notes` bundle.\" / \"Sync this back to Auden.\"\n- \"Clear my inbox once you've used it.\"\n\nDo NOT use it for guide/verdict inspection \u2014 that is the `auden` skill. This\nskill is about reading and writing *context*, not evaluating sessions.\n\n## Tools (Auden MCP server)\n\nIf these tools are missing, the Auden MCP server is not configured. Tell the user\nto run `auden mcp` and add it to their agent's MCP config (`.mcp.json` / Claude\nCode / Cursor). `auden mcp --read-only` disables the write tools; `auden mcp\n--bundles a,b` restricts which bundles are visible.\n\n| Tool | Input | Use |\n|---|---|---|\n| `list_bundles` | `{}` | Discover which bundles exist before pulling or pushing. |\n| `pull_context` | `{ bundle, query?, types?, limit?, writeToDir? }` | Pull *scoped* items from a bundle. Filter with `types` (`document`/`reference`/`asset`/`guide`), a `query` substring, and `limit`. Pass `writeToDir` to also write each item to disk. |\n| `push_context` | `{ bundle, name, content, contentType?, itemId?, origin?, sourceItemIds? }` | Push a canonical item. Omit `itemId` to create; pass `itemId` to update in place (propagates to every bundle it belongs to). `contentType` defaults to `document`. When the item was produced from other context items, cite their ids as `sourceItemIds`. |\n| `list_inbox` | `{ since?, types? }` | List unarchived inbox items. `since` takes an ISO timestamp or a relative window (`\"24h\"`, `\"7d\"`, `\"30m\"`). |\n| `pull_inbox` | `{ since?, types?, writeToDir? }` | Like `list_inbox` but also supports `writeToDir` \u2014 the round-trip entry point. |\n| `archive_inbox` | `{ ids }` | Archive inbox items once consumed so they drop out of future pulls (reversible on the dashboard). |\n\n## How To Use It Well\n\n- **Pull scoped, not everything.** Reach for `query`/`types`/`limit` so you only\n load what the task needs \u2014 the context layer can be large.\n- **Pushes are canonical and cross-repo.** A pushed document is visible from every\n other repo, so name it clearly and target the right bundle. When refining\n something you pulled, pass its `itemId` to `push_context` to update it in place\n rather than creating a duplicate.\n- **Close the loop on the inbox.** After you turn inbox items into a saved\n document, call `archive_inbox` with the ids you consumed so the user's inbox\n reflects that they were processed.\n- **Cite your sources when transforming.** When a pushed document was produced\n from other context items (inbox captures, bundle items), pass their ids as\n `sourceItemIds` on `push_context`. The citation is optional provenance; if\n one of the user's own guides covers the transform (its trigger matches, and\n it carries eval criteria), Auden grades the round-trip against *that guide's*\n criteria and the verdict lands in the user's feed. Auden has no built-in\n quality bar \u2014 the user's guidance is the standard. Report the verdict from\n the response's `transform` field when present.\n- **Preserve the user's facts.** These are the user's own notes \u2014 never drop or\n invent detail when you restructure them.\n";
3
+ /**
4
+ * Skills bundled into a repo by \`auden init\` (written under .claude/skills/<name>/SKILL.md).
5
+ * The \`auden\` skill covers evaluation/verdict inspection; \`auden-context\` covers
6
+ * the context layer over the Auden MCP server.
7
+ *
8
+ * Deliberately mechanics-only: Auden ships the mechanics (pull/push/inbox/
9
+ * grading), users bring the use cases — a concrete transform skill (e.g. notes
10
+ * cleanup) plus the guide with eval criteria that grades it is *user* content.
11
+ * A copy-paste example lives in docs/examples/notes-cleanup-skill.md; a user
12
+ * skill dropped into .claude/skills/ is discovered and graded like anything
13
+ * else they author (L3).
14
+ */
15
+ export declare const BUNDLED_SKILLS: ReadonlyArray<{
16
+ name: string;
17
+ content: string;
18
+ }>;
19
+ //# sourceMappingURL=skill-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-template.d.ts","sourceRoot":"","sources":["../src/skill-template.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,u3FA+EpB,CAAA;AAED,eAAO,MAAM,sBAAsB,0hJA4ElC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAG3E,CAAA"}