@hivelore/core 0.30.0

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.
@@ -0,0 +1,2752 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const MemoryScopeSchema: z.ZodEnum<["personal", "team", "module", "shared"]>;
4
+ declare const MemoryStatusSchema: z.ZodEnum<["draft", "proposed", "validated", "deprecated", "stale", "rejected"]>;
5
+ declare const MemoryTypeSchema: z.ZodEnum<["convention", "decision", "gotcha", "architecture", "glossary", "skill", "attempt", "session_recap"]>;
6
+ declare const AnchorSchema: z.ZodObject<{
7
+ commit: z.ZodOptional<z.ZodString>;
8
+ paths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
9
+ symbols: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ paths: string[];
12
+ symbols: string[];
13
+ commit?: string | undefined;
14
+ }, {
15
+ commit?: string | undefined;
16
+ paths?: string[] | undefined;
17
+ symbols?: string[] | undefined;
18
+ }>;
19
+ /**
20
+ * An executable check derived from a memory — the "feedback computational" layer.
21
+ *
22
+ * A `gotcha`/`attempt` is normally feedforward (text the agent reads). A sensor turns
23
+ * that lesson into a deterministic check: when a touched file matches `pattern`, the
24
+ * memory's warning fires regardless of semantic ranking. This closes the harness loop —
25
+ * a documented mistake becomes a permanent guardrail.
26
+ *
27
+ * Phase 1 implements `kind: "regex"` only. `shell`/`test` are reserved for a later phase
28
+ * (they require I/O and must run from the CLI, not core).
29
+ */
30
+ declare const SensorSchema: z.ZodObject<{
31
+ kind: z.ZodDefault<z.ZodEnum<["regex", "shell", "test"]>>;
32
+ /** Regex source (for kind=regex), matched against added diff lines / file content. */
33
+ pattern: z.ZodOptional<z.ZodString>;
34
+ /**
35
+ * Optional "correct-usage" regex (kind=regex). When `pattern` (the risky call) matches but this
36
+ * regex ALSO appears within a small window around the match, the catch is SUPPRESSED — the diff
37
+ * already includes the required companion. Encodes "X without Y": `pattern`=X (e.g. the API call),
38
+ * `absent`=Y (e.g. the required option). This is what lets an autogenerated sensor discriminate the
39
+ * faulty usage from the correct one instead of firing on every call — and makes it safe to promote.
40
+ */
41
+ absent: z.ZodOptional<z.ZodString>;
42
+ /** Regex flags (e.g. "i", "m"). Ignored for non-regex kinds. */
43
+ flags: z.ZodOptional<z.ZodString>;
44
+ /** Shell/test command to run (for kind=shell|test). Executed by the CLI, never by core. */
45
+ command: z.ZodOptional<z.ZodString>;
46
+ /** Glob-ish path prefixes the sensor applies to. Falls back to the memory's anchor paths when empty. */
47
+ paths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
48
+ /** LLM-facing self-correction message: what was done wrong and what to do instead. */
49
+ message: z.ZodString;
50
+ /** `warn` surfaces in review; `block` can hard-block the commit (only when the gate opts in). */
51
+ severity: z.ZodDefault<z.ZodEnum<["warn", "block"]>>;
52
+ /** True when Hivelore generated this sensor automatically (vs. hand-authored). */
53
+ autogen: z.ZodDefault<z.ZodBoolean>;
54
+ /** ISO timestamp of the last time this sensor matched a diff. */
55
+ last_fired: z.ZodDefault<z.ZodNullable<z.ZodString>>;
56
+ }, "strip", z.ZodTypeAny, {
57
+ message: string;
58
+ paths: string[];
59
+ kind: "regex" | "shell" | "test";
60
+ severity: "warn" | "block";
61
+ autogen: boolean;
62
+ last_fired: string | null;
63
+ pattern?: string | undefined;
64
+ absent?: string | undefined;
65
+ flags?: string | undefined;
66
+ command?: string | undefined;
67
+ }, {
68
+ message: string;
69
+ paths?: string[] | undefined;
70
+ kind?: "regex" | "shell" | "test" | undefined;
71
+ pattern?: string | undefined;
72
+ absent?: string | undefined;
73
+ flags?: string | undefined;
74
+ command?: string | undefined;
75
+ severity?: "warn" | "block" | undefined;
76
+ autogen?: boolean | undefined;
77
+ last_fired?: string | null | undefined;
78
+ }>;
79
+ /**
80
+ * Progressive-disclosure activation triggers for a `skill` memory.
81
+ *
82
+ * A skill is a reusable playbook (feedforward harness guide). Injecting every skill
83
+ * on every briefing bloats the context and dilutes signal (the "instruction budget"
84
+ * problem). An `activation` block makes a skill surface ONLY when it is relevant:
85
+ * its keywords match the task, or its globs match the files being edited. A skill
86
+ * that defines `activation` and matches none of it is suppressed from the briefing;
87
+ * a skill with no `activation` block keeps the legacy always-eligible behavior.
88
+ */
89
+ declare const ActivationSchema: z.ZodObject<{
90
+ /** Case-insensitive substrings matched against the task text. */
91
+ keywords: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
92
+ /** Glob-ish path patterns matched against the files being edited. */
93
+ globs: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
94
+ /** Always activate (rare — for truly universal playbooks). */
95
+ always: z.ZodDefault<z.ZodBoolean>;
96
+ }, "strip", z.ZodTypeAny, {
97
+ keywords: string[];
98
+ globs: string[];
99
+ always: boolean;
100
+ }, {
101
+ keywords?: string[] | undefined;
102
+ globs?: string[] | undefined;
103
+ always?: boolean | undefined;
104
+ }>;
105
+ declare const MemoryFrontmatterSchema: z.ZodEffects<z.ZodObject<{
106
+ id: z.ZodString;
107
+ scope: z.ZodDefault<z.ZodEnum<["personal", "team", "module", "shared"]>>;
108
+ module: z.ZodOptional<z.ZodString>;
109
+ type: z.ZodEnum<["convention", "decision", "gotcha", "architecture", "glossary", "skill", "attempt", "session_recap"]>;
110
+ status: z.ZodDefault<z.ZodEnum<["draft", "proposed", "validated", "deprecated", "stale", "rejected"]>>;
111
+ anchor: z.ZodDefault<z.ZodObject<{
112
+ commit: z.ZodOptional<z.ZodString>;
113
+ paths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
114
+ symbols: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
115
+ }, "strip", z.ZodTypeAny, {
116
+ paths: string[];
117
+ symbols: string[];
118
+ commit?: string | undefined;
119
+ }, {
120
+ commit?: string | undefined;
121
+ paths?: string[] | undefined;
122
+ symbols?: string[] | undefined;
123
+ }>>;
124
+ /** Optional executable check derived from this memory (feedback computational layer). */
125
+ sensor: z.ZodOptional<z.ZodObject<{
126
+ kind: z.ZodDefault<z.ZodEnum<["regex", "shell", "test"]>>;
127
+ /** Regex source (for kind=regex), matched against added diff lines / file content. */
128
+ pattern: z.ZodOptional<z.ZodString>;
129
+ /**
130
+ * Optional "correct-usage" regex (kind=regex). When `pattern` (the risky call) matches but this
131
+ * regex ALSO appears within a small window around the match, the catch is SUPPRESSED — the diff
132
+ * already includes the required companion. Encodes "X without Y": `pattern`=X (e.g. the API call),
133
+ * `absent`=Y (e.g. the required option). This is what lets an autogenerated sensor discriminate the
134
+ * faulty usage from the correct one instead of firing on every call — and makes it safe to promote.
135
+ */
136
+ absent: z.ZodOptional<z.ZodString>;
137
+ /** Regex flags (e.g. "i", "m"). Ignored for non-regex kinds. */
138
+ flags: z.ZodOptional<z.ZodString>;
139
+ /** Shell/test command to run (for kind=shell|test). Executed by the CLI, never by core. */
140
+ command: z.ZodOptional<z.ZodString>;
141
+ /** Glob-ish path prefixes the sensor applies to. Falls back to the memory's anchor paths when empty. */
142
+ paths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
143
+ /** LLM-facing self-correction message: what was done wrong and what to do instead. */
144
+ message: z.ZodString;
145
+ /** `warn` surfaces in review; `block` can hard-block the commit (only when the gate opts in). */
146
+ severity: z.ZodDefault<z.ZodEnum<["warn", "block"]>>;
147
+ /** True when Hivelore generated this sensor automatically (vs. hand-authored). */
148
+ autogen: z.ZodDefault<z.ZodBoolean>;
149
+ /** ISO timestamp of the last time this sensor matched a diff. */
150
+ last_fired: z.ZodDefault<z.ZodNullable<z.ZodString>>;
151
+ }, "strip", z.ZodTypeAny, {
152
+ message: string;
153
+ paths: string[];
154
+ kind: "regex" | "shell" | "test";
155
+ severity: "warn" | "block";
156
+ autogen: boolean;
157
+ last_fired: string | null;
158
+ pattern?: string | undefined;
159
+ absent?: string | undefined;
160
+ flags?: string | undefined;
161
+ command?: string | undefined;
162
+ }, {
163
+ message: string;
164
+ paths?: string[] | undefined;
165
+ kind?: "regex" | "shell" | "test" | undefined;
166
+ pattern?: string | undefined;
167
+ absent?: string | undefined;
168
+ flags?: string | undefined;
169
+ command?: string | undefined;
170
+ severity?: "warn" | "block" | undefined;
171
+ autogen?: boolean | undefined;
172
+ last_fired?: string | null | undefined;
173
+ }>>;
174
+ /** Optional progressive-disclosure triggers — only meaningful for `type: skill`. */
175
+ activation: z.ZodOptional<z.ZodObject<{
176
+ /** Case-insensitive substrings matched against the task text. */
177
+ keywords: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
178
+ /** Glob-ish path patterns matched against the files being edited. */
179
+ globs: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
180
+ /** Always activate (rare — for truly universal playbooks). */
181
+ always: z.ZodDefault<z.ZodBoolean>;
182
+ }, "strip", z.ZodTypeAny, {
183
+ keywords: string[];
184
+ globs: string[];
185
+ always: boolean;
186
+ }, {
187
+ keywords?: string[] | undefined;
188
+ globs?: string[] | undefined;
189
+ always?: boolean | undefined;
190
+ }>>;
191
+ tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
192
+ domain: z.ZodOptional<z.ZodString>;
193
+ author: z.ZodOptional<z.ZodString>;
194
+ created_at: z.ZodPipeline<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodDate]>, string, string | Date>, z.ZodString>;
195
+ expires_when: z.ZodDefault<z.ZodNullable<z.ZodString>>;
196
+ verified_at: z.ZodDefault<z.ZodNullable<z.ZodString>>;
197
+ stale_reason: z.ZodDefault<z.ZodNullable<z.ZodString>>;
198
+ related_ids: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
199
+ last_read_at: z.ZodDefault<z.ZodNullable<z.ZodString>>;
200
+ topic: z.ZodOptional<z.ZodString>;
201
+ revision_count: z.ZodDefault<z.ZodNumber>;
202
+ /**
203
+ * When true, the AI MUST NOT act on this memory autonomously.
204
+ * It must surface the information to the human developer and wait
205
+ * for explicit confirmation before modifying any code.
206
+ * Used for cross-repo breaking changes, dependency bumps, contract diffs.
207
+ */
208
+ requires_human_approval: z.ZodDefault<z.ZodBoolean>;
209
+ /**
210
+ * Provenance of the memory's `validated` status — who/what last trusted it:
211
+ * "human" — a person explicitly approved it (CLI `memory approve`)
212
+ * "agent" — an AI agent explicitly approved it (MCP `mem_approve`)
213
+ * "auto" — an automatic rule trusted it without review (auto-promotion by read
214
+ * count/time, or `defaultStatus: validated` on creation)
215
+ * null when the memory is not yet validated, or on legacy memories written before this field.
216
+ * Lets a human distinguish reviewed knowledge from AI/auto-trusted knowledge.
217
+ */
218
+ validated_by: z.ZodDefault<z.ZodNullable<z.ZodEnum<["human", "agent", "auto"]>>>;
219
+ }, "strip", z.ZodTypeAny, {
220
+ type: "convention" | "decision" | "gotcha" | "architecture" | "glossary" | "skill" | "attempt" | "session_recap";
221
+ status: "draft" | "proposed" | "validated" | "deprecated" | "stale" | "rejected";
222
+ id: string;
223
+ scope: "personal" | "team" | "module" | "shared";
224
+ anchor: {
225
+ paths: string[];
226
+ symbols: string[];
227
+ commit?: string | undefined;
228
+ };
229
+ tags: string[];
230
+ created_at: string;
231
+ expires_when: string | null;
232
+ verified_at: string | null;
233
+ stale_reason: string | null;
234
+ related_ids: string[];
235
+ last_read_at: string | null;
236
+ revision_count: number;
237
+ requires_human_approval: boolean;
238
+ validated_by: "human" | "agent" | "auto" | null;
239
+ module?: string | undefined;
240
+ sensor?: {
241
+ message: string;
242
+ paths: string[];
243
+ kind: "regex" | "shell" | "test";
244
+ severity: "warn" | "block";
245
+ autogen: boolean;
246
+ last_fired: string | null;
247
+ pattern?: string | undefined;
248
+ absent?: string | undefined;
249
+ flags?: string | undefined;
250
+ command?: string | undefined;
251
+ } | undefined;
252
+ activation?: {
253
+ keywords: string[];
254
+ globs: string[];
255
+ always: boolean;
256
+ } | undefined;
257
+ domain?: string | undefined;
258
+ author?: string | undefined;
259
+ topic?: string | undefined;
260
+ }, {
261
+ type: "convention" | "decision" | "gotcha" | "architecture" | "glossary" | "skill" | "attempt" | "session_recap";
262
+ id: string;
263
+ created_at: string | Date;
264
+ module?: string | undefined;
265
+ status?: "draft" | "proposed" | "validated" | "deprecated" | "stale" | "rejected" | undefined;
266
+ scope?: "personal" | "team" | "module" | "shared" | undefined;
267
+ anchor?: {
268
+ commit?: string | undefined;
269
+ paths?: string[] | undefined;
270
+ symbols?: string[] | undefined;
271
+ } | undefined;
272
+ sensor?: {
273
+ message: string;
274
+ paths?: string[] | undefined;
275
+ kind?: "regex" | "shell" | "test" | undefined;
276
+ pattern?: string | undefined;
277
+ absent?: string | undefined;
278
+ flags?: string | undefined;
279
+ command?: string | undefined;
280
+ severity?: "warn" | "block" | undefined;
281
+ autogen?: boolean | undefined;
282
+ last_fired?: string | null | undefined;
283
+ } | undefined;
284
+ activation?: {
285
+ keywords?: string[] | undefined;
286
+ globs?: string[] | undefined;
287
+ always?: boolean | undefined;
288
+ } | undefined;
289
+ tags?: string[] | undefined;
290
+ domain?: string | undefined;
291
+ author?: string | undefined;
292
+ expires_when?: string | null | undefined;
293
+ verified_at?: string | null | undefined;
294
+ stale_reason?: string | null | undefined;
295
+ related_ids?: string[] | undefined;
296
+ last_read_at?: string | null | undefined;
297
+ topic?: string | undefined;
298
+ revision_count?: number | undefined;
299
+ requires_human_approval?: boolean | undefined;
300
+ validated_by?: "human" | "agent" | "auto" | null | undefined;
301
+ }>, {
302
+ type: "convention" | "decision" | "gotcha" | "architecture" | "glossary" | "skill" | "attempt" | "session_recap";
303
+ status: "draft" | "proposed" | "validated" | "deprecated" | "stale" | "rejected";
304
+ id: string;
305
+ scope: "personal" | "team" | "module" | "shared";
306
+ anchor: {
307
+ paths: string[];
308
+ symbols: string[];
309
+ commit?: string | undefined;
310
+ };
311
+ tags: string[];
312
+ created_at: string;
313
+ expires_when: string | null;
314
+ verified_at: string | null;
315
+ stale_reason: string | null;
316
+ related_ids: string[];
317
+ last_read_at: string | null;
318
+ revision_count: number;
319
+ requires_human_approval: boolean;
320
+ validated_by: "human" | "agent" | "auto" | null;
321
+ module?: string | undefined;
322
+ sensor?: {
323
+ message: string;
324
+ paths: string[];
325
+ kind: "regex" | "shell" | "test";
326
+ severity: "warn" | "block";
327
+ autogen: boolean;
328
+ last_fired: string | null;
329
+ pattern?: string | undefined;
330
+ absent?: string | undefined;
331
+ flags?: string | undefined;
332
+ command?: string | undefined;
333
+ } | undefined;
334
+ activation?: {
335
+ keywords: string[];
336
+ globs: string[];
337
+ always: boolean;
338
+ } | undefined;
339
+ domain?: string | undefined;
340
+ author?: string | undefined;
341
+ topic?: string | undefined;
342
+ }, {
343
+ type: "convention" | "decision" | "gotcha" | "architecture" | "glossary" | "skill" | "attempt" | "session_recap";
344
+ id: string;
345
+ created_at: string | Date;
346
+ module?: string | undefined;
347
+ status?: "draft" | "proposed" | "validated" | "deprecated" | "stale" | "rejected" | undefined;
348
+ scope?: "personal" | "team" | "module" | "shared" | undefined;
349
+ anchor?: {
350
+ commit?: string | undefined;
351
+ paths?: string[] | undefined;
352
+ symbols?: string[] | undefined;
353
+ } | undefined;
354
+ sensor?: {
355
+ message: string;
356
+ paths?: string[] | undefined;
357
+ kind?: "regex" | "shell" | "test" | undefined;
358
+ pattern?: string | undefined;
359
+ absent?: string | undefined;
360
+ flags?: string | undefined;
361
+ command?: string | undefined;
362
+ severity?: "warn" | "block" | undefined;
363
+ autogen?: boolean | undefined;
364
+ last_fired?: string | null | undefined;
365
+ } | undefined;
366
+ activation?: {
367
+ keywords?: string[] | undefined;
368
+ globs?: string[] | undefined;
369
+ always?: boolean | undefined;
370
+ } | undefined;
371
+ tags?: string[] | undefined;
372
+ domain?: string | undefined;
373
+ author?: string | undefined;
374
+ expires_when?: string | null | undefined;
375
+ verified_at?: string | null | undefined;
376
+ stale_reason?: string | null | undefined;
377
+ related_ids?: string[] | undefined;
378
+ last_read_at?: string | null | undefined;
379
+ topic?: string | undefined;
380
+ revision_count?: number | undefined;
381
+ requires_human_approval?: boolean | undefined;
382
+ validated_by?: "human" | "agent" | "auto" | null | undefined;
383
+ }>;
384
+ declare const CrossRepoProvenanceSchema: z.ZodOptional<z.ZodObject<{
385
+ source_name: z.ZodString;
386
+ source_path: z.ZodString;
387
+ source_id: z.ZodString;
388
+ imported_at: z.ZodString;
389
+ }, "strip", z.ZodTypeAny, {
390
+ source_name: string;
391
+ source_path: string;
392
+ source_id: string;
393
+ imported_at: string;
394
+ }, {
395
+ source_name: string;
396
+ source_path: string;
397
+ source_id: string;
398
+ imported_at: string;
399
+ }>>;
400
+
401
+ type MemoryScope = z.infer<typeof MemoryScopeSchema>;
402
+ type MemoryStatus = z.infer<typeof MemoryStatusSchema>;
403
+ type MemoryType = z.infer<typeof MemoryTypeSchema>;
404
+ type Anchor = z.infer<typeof AnchorSchema>;
405
+ type Sensor = z.infer<typeof SensorSchema>;
406
+ type Activation = z.infer<typeof ActivationSchema>;
407
+ type MemoryFrontmatter = z.infer<typeof MemoryFrontmatterSchema>;
408
+ interface Memory {
409
+ frontmatter: MemoryFrontmatter;
410
+ body: string;
411
+ }
412
+
413
+ declare function stripPrivate(body: string): string;
414
+ declare function parseMemory(raw: string): Memory;
415
+ declare function serializeMemory(memory: Memory): string;
416
+ declare function newMemoryId(type: string, slug: string, date?: Date): string;
417
+ declare function buildFrontmatter(input: {
418
+ type: MemoryFrontmatter["type"];
419
+ slug: string;
420
+ scope?: MemoryFrontmatter["scope"];
421
+ module?: string;
422
+ tags?: string[];
423
+ domain?: string;
424
+ author?: string;
425
+ paths?: string[];
426
+ symbols?: string[];
427
+ commit?: string;
428
+ topic?: string;
429
+ status?: MemoryFrontmatter["status"];
430
+ relatedIds?: string[];
431
+ sensor?: Sensor;
432
+ activation?: Activation;
433
+ }): MemoryFrontmatter;
434
+
435
+ declare const HAIVE_DIR = ".ai";
436
+ declare function findProjectRoot(startDir?: string): string;
437
+ declare const PROJECT_CONTEXT_FILE = "project-context.md";
438
+ declare const MEMORIES_DIR = "memories";
439
+ interface HaivePaths {
440
+ root: string;
441
+ haiveDir: string;
442
+ /** Disposable local layer (session journal, caches). Not team truth — see `.ai/.runtime/` layout. */
443
+ runtimeDir: string;
444
+ projectContext: string;
445
+ memoriesDir: string;
446
+ personalDir: string;
447
+ teamDir: string;
448
+ sharedDir: string;
449
+ moduleDir: string;
450
+ modulesContextDir: string;
451
+ }
452
+ declare function resolveHaivePaths(projectRoot: string): HaivePaths;
453
+ declare function memoryFilePath(paths: HaivePaths, scope: "personal" | "team" | "module" | "shared", id: string, module?: string): string;
454
+
455
+ interface LoadedMemory {
456
+ memory: Memory;
457
+ filePath: string;
458
+ }
459
+ declare function listMarkdownFilesRecursive(dir: string): Promise<string[]>;
460
+ declare function loadMemory(filePath: string): Promise<LoadedMemory>;
461
+ declare function loadMemoriesFromDir(dir: string): Promise<LoadedMemory[]>;
462
+
463
+ declare function tokenizeQuery(query: string): string[];
464
+ declare function literalMatchesAllTokens(memory: Memory, tokens: string[]): boolean;
465
+ /**
466
+ * OR-based fallback: returns true if the memory matches at least one token.
467
+ * Used when all-tokens (AND) search returns 0 results.
468
+ */
469
+ declare function literalMatchesAnyToken(memory: Memory, tokens: string[]): boolean;
470
+ declare function pickSnippetNeedle(query: string): string;
471
+ declare function extractSnippet(body: string, needle: string, radius?: number): string;
472
+
473
+ interface VerifyResult {
474
+ stale: boolean;
475
+ reason: string | null;
476
+ checkedPaths: string[];
477
+ checkedSymbols: string[];
478
+ possibleRenames: string[];
479
+ }
480
+ interface VerifyOptions {
481
+ /** Project root used to resolve relative anchor paths. */
482
+ projectRoot: string;
483
+ }
484
+ /**
485
+ * Verify that a memory's anchor still matches the current code.
486
+ * - Every anchor.paths entry must exist on disk
487
+ * - Every anchor.symbols entry must appear at least once across the anchor.paths
488
+ * files (or any tracked file if no paths are recorded)
489
+ *
490
+ * Anchorless memories (no paths and no symbols) are always considered fresh —
491
+ * staleness only applies to memories that opted into anchoring.
492
+ */
493
+ declare function verifyAnchor(memory: Memory, options: VerifyOptions): Promise<VerifyResult>;
494
+
495
+ interface MemoryUsage {
496
+ read_count: number;
497
+ last_read_at: string | null;
498
+ rejected_count: number;
499
+ last_rejected_at: string | null;
500
+ rejection_reason: string | null;
501
+ /**
502
+ * Number of times the memory was explicitly confirmed *useful* — i.e. an agent
503
+ * or human recorded that it changed what they did (the closed-loop "applied"
504
+ * outcome, recorded via `mem_feedback`). A far stronger utility signal than a
505
+ * read: a memory can be surfaced many times and ignored, but `applied` means it
506
+ * demonstrably steered work. Drives impact scoring in {@link ./impact.js}.
507
+ */
508
+ applied_count: number;
509
+ last_applied_at: string | null;
510
+ /**
511
+ * Number of *prevention* events — times this memory's sensor actually fired on a scanned diff,
512
+ * intercepting a known mistake before it landed. This is an OUTCOME signal (defect prevented),
513
+ * the closest proxy Hivelore has to "did the knowledge stop a real problem?", distinct from
514
+ * retrieval (read) and self-reported usefulness (applied). Recorded by `hivelore sensors check`.
515
+ */
516
+ prevented_count: number;
517
+ last_prevented_at: string | null;
518
+ }
519
+ interface UsageIndex {
520
+ version: 1;
521
+ updated_at: string;
522
+ by_id: Record<string, MemoryUsage>;
523
+ }
524
+ declare const USAGE_FILE = "usage.json";
525
+ declare function emptyUsage(): MemoryUsage;
526
+ declare function emptyUsageIndex(): UsageIndex;
527
+ declare function usagePath(paths: HaivePaths): string;
528
+ declare function loadUsageIndex(paths: HaivePaths): Promise<UsageIndex>;
529
+ declare function saveUsageIndex(paths: HaivePaths, index: UsageIndex): Promise<void>;
530
+ declare function getUsage(index: UsageIndex, id: string): MemoryUsage;
531
+ declare function bumpRead(index: UsageIndex, ids: string[]): UsageIndex;
532
+ declare function recordRejection(index: UsageIndex, id: string, reason: string | null): UsageIndex;
533
+ /**
534
+ * Record that a memory was *applied* — explicitly confirmed to have changed what
535
+ * the agent/human did. This is the closed-loop utility signal that distinguishes
536
+ * a memory that merely got surfaced from one that demonstrably steered work.
537
+ */
538
+ declare function recordApplied(index: UsageIndex, id: string): UsageIndex;
539
+ /** Debounce window so re-scanning the same diff within a few minutes doesn't inflate prevention
540
+ * counts (a pre-commit hook can run the check several times for one commit). */
541
+ declare const PREVENTION_DEBOUNCE_MS: number;
542
+ /**
543
+ * Record a *prevention* event: a memory's sensor fired on a scanned diff, intercepting a known
544
+ * mistake before it landed. Outcome signal (defect prevented), stronger than a read. Debounced by
545
+ * {@link PREVENTION_DEBOUNCE_MS}. Returns true if a NEW event was recorded (false if debounced).
546
+ */
547
+ declare function recordPrevention(index: UsageIndex, id: string, now?: number): boolean;
548
+ declare const DECAY_DAYS = 90;
549
+ declare function isDecaying(usage: MemoryUsage, createdAt: string): boolean;
550
+ declare function trackReads(paths: HaivePaths, ids: string[]): Promise<UsageIndex>;
551
+
552
+ /**
553
+ * Closed-loop memory-utility scoring — the "did this memory actually help?" layer.
554
+ *
555
+ * Hivelore already tracks reads ({@link ./usage.js}) and derives a trust level from
556
+ * status + read_count ({@link ./confidence.js}). But a read only means a memory was
557
+ * *surfaced*, not that it *helped* — a memory can be injected on every briefing and
558
+ * silently ignored. Harness engineering's core loop (Fowler / LangChain) is to
559
+ * measure what demonstrably steers work and let that feed back into recall.
560
+ *
561
+ * `computeImpact` combines the signals Hivelore already records but never correlated:
562
+ * POSITIVE reads · applied outcomes (mem_feedback) · a sensor that actually fired
563
+ * NEGATIVE rejections · stale/deprecated/rejected status · dormancy
564
+ * into a single 0..1 utility score, a tier, and a prune-candidate flag. It is a pure
565
+ * function (no I/O), unit-tested in `packages/core/test/impact.test.ts`.
566
+ */
567
+ type ImpactTier = "high" | "medium" | "low" | "dormant";
568
+ interface ImpactScore {
569
+ /** Normalized utility score in [0, 1]. */
570
+ score: number;
571
+ tier: ImpactTier;
572
+ /** Human-readable breakdown of the signals that produced the score. */
573
+ signals: string[];
574
+ /**
575
+ * True when the memory looks like dead weight worth reviewing/pruning:
576
+ * more rejections than reads, or never used with no guardrail, or already
577
+ * stale/deprecated/rejected. A memory carrying a `sensor` or with `applied`
578
+ * outcomes is never a prune candidate — it earns its keep as a guardrail.
579
+ */
580
+ pruneCandidate: boolean;
581
+ }
582
+ interface ImpactOptions {
583
+ /** Days with no read AND no applied outcome after which a memory is "dormant". */
584
+ dormantDays?: number;
585
+ now?: Date;
586
+ }
587
+ /** Default dormancy window — half the confidence hard-decay (365d), so impact reacts sooner. */
588
+ declare const DEFAULT_DORMANT_DAYS = 120;
589
+ /**
590
+ * Compute the demonstrated utility of a single memory from its frontmatter + usage.
591
+ * Pure and deterministic given `now`.
592
+ */
593
+ declare function computeImpact(fm: MemoryFrontmatter, usage: MemoryUsage, options?: ImpactOptions): ImpactScore;
594
+ /** Sort comparator: highest impact first, prune candidates last on ties. */
595
+ declare function compareImpact(a: ImpactScore, b: ImpactScore): number;
596
+ interface ImpactSummary {
597
+ total: number;
598
+ high: number;
599
+ medium: number;
600
+ low: number;
601
+ dormant: number;
602
+ prune_candidates: number;
603
+ }
604
+ /** Roll up a set of impact scores into tier counts. */
605
+ declare function summarizeImpact(scores: ImpactScore[]): ImpactSummary;
606
+ type FeedbackAdjustmentAction = "none" | "downgrade-block-sensor" | "deprecate-memory";
607
+ interface FeedbackAdjustment {
608
+ action: FeedbackAdjustmentAction;
609
+ reason: string;
610
+ }
611
+ interface FeedbackAdjustmentOptions {
612
+ /** Rejections needed before deprecating a memory with no positive outcomes. Defaults to 2. */
613
+ rejectionThreshold?: number;
614
+ }
615
+ /**
616
+ * Turn explicit human rejection (`mem_feedback outcome=rejected`) into a deterministic
617
+ * noise-reduction action. Pure: callers decide whether to persist the returned change.
618
+ */
619
+ declare function recommendFeedbackAdjustment(fm: MemoryFrontmatter, usage: MemoryUsage, options?: FeedbackAdjustmentOptions): FeedbackAdjustment;
620
+ declare function applyFeedbackAdjustment(fm: MemoryFrontmatter, adjustment: FeedbackAdjustment, now?: Date): MemoryFrontmatter;
621
+
622
+ type PreventionSource = "sensor" | "anti-pattern";
623
+ interface PreventionEvent {
624
+ /** ISO timestamp of the catch. */
625
+ at: string;
626
+ /** Memory id whose lesson fired. */
627
+ id: string;
628
+ /** Which gate path recorded it. */
629
+ source: PreventionSource;
630
+ }
631
+ declare function preventionLogPath(paths: HaivePaths): string;
632
+ /** Append one catch to the log. Best-effort, creates the dir on demand. */
633
+ declare function appendPreventionEvent(paths: HaivePaths, event: PreventionEvent): Promise<void>;
634
+ /**
635
+ * THE single recorder for "a documented lesson intercepted a real mistake". Every gate path —
636
+ * the installed git-hook gate (`enforce check`), the standalone `hivelore sensors check`, and the
637
+ * `anti_patterns_check` MCP tool — funnels its fired memory ids through here so prevention is
638
+ * recorded once and identically, not bolted onto each entry point (it used to leak: the git-hook
639
+ * gate blocked but never recorded — see the harness-positioning gotcha).
640
+ *
641
+ * Bumps `prevented_count` in usage.json (debounced per memory via {@link recordPrevention}) AND
642
+ * appends one timestamped event per NEW catch to the prevention log. Best-effort: a telemetry
643
+ * write must never break a commit, so failures are swallowed. Returns the ids actually recorded
644
+ * (i.e. not debounced), so callers can report "caught for you" without re-counting.
645
+ */
646
+ declare function recordPreventionHits(paths: HaivePaths, firedIds: string[], source: PreventionSource, now?: Date): Promise<string[]>;
647
+ /** Read all catch events (skips malformed lines). */
648
+ declare function loadPreventionEvents(paths: HaivePaths): Promise<PreventionEvent[]>;
649
+ interface PreventionTrend {
650
+ /** Catches in the last 7 days. */
651
+ last_7d: number;
652
+ /** Catches in the last 30 days. */
653
+ last_30d: number;
654
+ /** Catch counts per ISO week, oldest → newest, for the last N weeks (default 6). */
655
+ weekly: number[];
656
+ }
657
+ declare function computePreventionTrend(events: PreventionEvent[], now?: Date, weeks?: number): PreventionTrend;
658
+ interface RecurrenceRow {
659
+ id: string;
660
+ /** Total catches for this memory. */
661
+ catches: number;
662
+ /** Number of distinct UTC days the lesson fired — the recurrence signal. */
663
+ distinct_days: number;
664
+ last_at: string;
665
+ }
666
+ interface RecurrenceReport {
667
+ /**
668
+ * Memories whose lesson was caught on >= 2 distinct days — i.e. the mistake was RE-INTRODUCED
669
+ * after it had already been captured and caught once. A high count means a recurring problem the
670
+ * team keeps reintroducing (the guardrail is earning its keep, and the root cause may need a
671
+ * stronger fix than a memory).
672
+ */
673
+ recurring_count: number;
674
+ top: RecurrenceRow[];
675
+ }
676
+ declare function computeRecurrence(events: PreventionEvent[]): RecurrenceReport;
677
+ interface BriefingProofLineOptions {
678
+ /** End of the reporting window. Defaults to now. */
679
+ now?: Date;
680
+ /** Window size in days. Defaults to 30 ("this month" in product copy). */
681
+ days?: number;
682
+ }
683
+ /**
684
+ * Coordination point for Lot C: turn prevention events into one compact proof line
685
+ * suitable for get_briefing, without coupling this lot to the MCP tool.
686
+ */
687
+ declare function briefingProofLine(events: PreventionEvent[], options?: BriefingProofLineOptions): string | null;
688
+ interface CaughtForYouOptions {
689
+ /** Only include events at or after this instant. */
690
+ since?: string | Date;
691
+ /** Only include events at or before this instant. Defaults to now. */
692
+ now?: Date;
693
+ /** Max rows in the summary. Defaults to 5. */
694
+ limit?: number;
695
+ }
696
+ interface CaughtForYouRow {
697
+ id: string;
698
+ title: string;
699
+ source: PreventionSource;
700
+ catches: number;
701
+ previous_count: number;
702
+ current_count: number;
703
+ last_at: string;
704
+ }
705
+ interface CaughtForYouSummary {
706
+ total_catches: number;
707
+ since: string | null;
708
+ until: string;
709
+ rows: CaughtForYouRow[];
710
+ }
711
+ /** Build the end-of-session "caught for you" scene from prevention events. Pure. */
712
+ declare function summarizeCaughtForYou(events: PreventionEvent[], memories: LoadedMemory[], usage: UsageIndex, options?: CaughtForYouOptions): CaughtForYouSummary;
713
+ /** Render a compact human-readable block for CLI/session recaps. */
714
+ declare function renderCaughtForYou(summary: CaughtForYouSummary): string | null;
715
+
716
+ /** How long an emitted project context is considered "still fresh in the agent's context". */
717
+ declare const PROJECT_CONTEXT_THROTTLE_MS: number;
718
+ declare function hashProjectContext(content: string): string;
719
+ /** True if an identical project-context body was already emitted within the throttle window. */
720
+ declare function projectContextRecentlyEmitted(paths: HaivePaths, hash: string, now?: number): Promise<boolean>;
721
+ /** Record that this exact project-context body was just emitted. Best-effort. */
722
+ declare function recordProjectContextEmission(paths: HaivePaths, hash: string, now?: number): Promise<void>;
723
+
724
+ /**
725
+ * A rigorous, model-free, repeatable evaluation of Hivelore's core promise: surfacing
726
+ * the right knowledge and guardrails at the right moment. Unlike the agent benchmark
727
+ * (which parses human-written reports), this is deterministic and CI-runnable — it
728
+ * produces a numeric quality score from labeled cases, so a regression in ranking or
729
+ * sensor coverage fails the build instead of silently degrading every agent session.
730
+ *
731
+ * Two case families:
732
+ * - RETRIEVAL — given a task (+optional files/symbols), do the expected memories
733
+ * surface in the briefing top-k? Measured by recall and mean reciprocal rank.
734
+ * - SENSORS — given a known-bad diff, does the expected memory's sensor fire?
735
+ * Measured by catch-rate.
736
+ *
737
+ * This module is pure: it defines the case/result types, the scoring math, and case
738
+ * synthesis from a repo's own anchored memories. Orchestration (calling get_briefing
739
+ * / anti_patterns_check) lives in the CLI, since core cannot depend on the MCP layer.
740
+ */
741
+ interface RetrievalCase {
742
+ name: string;
743
+ task: string;
744
+ files?: string[];
745
+ symbols?: string[];
746
+ /** Memory ids that SHOULD surface in the briefing for this case. */
747
+ expect_ids: string[];
748
+ }
749
+ interface SensorCase {
750
+ name: string;
751
+ /** Unified diff (or added-line text) the sensors run against. */
752
+ diff: string;
753
+ paths?: string[];
754
+ /** Memory ids whose sensor SHOULD fire on this diff. */
755
+ expect_fire_ids: string[];
756
+ }
757
+ interface EvalSpec {
758
+ retrieval?: RetrievalCase[];
759
+ sensors?: SensorCase[];
760
+ }
761
+ interface RetrievalCaseResult {
762
+ name: string;
763
+ expect_ids: string[];
764
+ /** Surfaced memory ids, in ranked order, capped at k. */
765
+ surfaced_ids: string[];
766
+ hits: string[];
767
+ misses: string[];
768
+ precision: number;
769
+ recall: number;
770
+ /** 1-based rank of the first expected id among surfaced ids; null if none surfaced. */
771
+ best_rank: number | null;
772
+ }
773
+ interface SensorCaseResult {
774
+ name: string;
775
+ expect_fire_ids: string[];
776
+ fired_ids: string[];
777
+ hits: string[];
778
+ misses: string[];
779
+ recall: number;
780
+ }
781
+ interface RetrievalAggregate {
782
+ cases: RetrievalCaseResult[];
783
+ /**
784
+ * Top-k precision = expected hits ÷ surfaced results. Inherently LOW when only ~1 memory is
785
+ * expected per case but k results are surfaced (e.g. 1/8 ≈ 0.12) — this is a top-k artifact, not
786
+ * a quality defect. Retrieval quality is judged by `mean_recall` and `mrr`; precision is NOT part
787
+ * of the headline eval score (see `scoreEval`). Reported for completeness only.
788
+ */
789
+ mean_precision: number;
790
+ mean_recall: number;
791
+ /** Mean reciprocal rank of the first expected hit — rewards ranking the right memory high. */
792
+ mrr: number;
793
+ }
794
+ interface SensorAggregate {
795
+ cases: SensorCaseResult[];
796
+ catch_rate: number;
797
+ }
798
+ interface EvalReport {
799
+ retrieval: RetrievalAggregate | null;
800
+ sensors: SensorAggregate | null;
801
+ /** Overall quality score 0..100. */
802
+ score: number;
803
+ }
804
+ /**
805
+ * Score one retrieval case from the (ranked) ids the briefing surfaced.
806
+ * `surfacedRanked` should already be capped to the top-k the caller cares about.
807
+ */
808
+ declare function scoreRetrievalCase(name: string, expectIds: string[], surfacedRanked: string[]): RetrievalCaseResult;
809
+ declare function aggregateRetrieval(cases: RetrievalCaseResult[]): RetrievalAggregate;
810
+ declare function scoreSensorCase(name: string, expectFireIds: string[], firedIds: string[]): SensorCaseResult;
811
+ declare function aggregateSensors(cases: SensorCaseResult[]): SensorAggregate;
812
+ /** Combine retrieval + sensor aggregates into a single 0..100 quality score. */
813
+ declare function overallScore(retrieval: RetrievalAggregate | null, sensors: SensorAggregate | null): number;
814
+ declare function buildReport(retrieval: RetrievalAggregate | null, sensors: SensorAggregate | null): EvalReport;
815
+ /**
816
+ * Baseline / compare — makes the "Hivelore improves retrieval by N%" claim reproducible.
817
+ *
818
+ * `hivelore eval --baseline` snapshots a report; `--compare` re-runs and diffs against it,
819
+ * so a ranking/sensor regression is a number, not a vibe. Pure math here; the CLI does I/O.
820
+ */
821
+ interface MetricDelta {
822
+ baseline: number;
823
+ current: number;
824
+ /** current − baseline (positive = improvement for all these metrics). */
825
+ delta: number;
826
+ }
827
+ interface EvalDelta {
828
+ score: MetricDelta;
829
+ mean_recall: MetricDelta | null;
830
+ mrr: MetricDelta | null;
831
+ catch_rate: MetricDelta | null;
832
+ /** True when the overall score dropped vs the baseline. */
833
+ regressed: boolean;
834
+ /** True when the overall score rose vs the baseline. */
835
+ improved: boolean;
836
+ }
837
+ /** Diff a current report against a baseline. Pure. */
838
+ declare function compareEvalReports(baseline: EvalReport, current: EvalReport): EvalDelta;
839
+ /** Extract a short task-like title from a memory body (first heading or first line). */
840
+ declare function titleFromBody(body: string): string;
841
+ interface SelfEvalOptions {
842
+ /** Include each memory's anchor paths as the case files (tests anchored retrieval). */
843
+ includeFiles?: boolean;
844
+ /** Skip memories with these statuses (default: stale/deprecated/rejected). */
845
+ skipStatuses?: string[];
846
+ }
847
+ /**
848
+ * Synthesize retrieval cases from a repo's own anchored memories — zero-setup eval.
849
+ * Each anchored, non-recap, non-dead memory becomes a case: "when working on the
850
+ * file(s) this memory anchors, with its title as the task, does Hivelore surface it?".
851
+ * With `includeFiles: false` it becomes a harder semantic-only probe (title alone).
852
+ */
853
+ declare function synthesizeSelfEvalCases(memories: LoadedMemory[], options?: SelfEvalOptions): RetrievalCase[];
854
+
855
+ type ConfidenceLevel = "unverified" | "low" | "trusted" | "authoritative" | "stale";
856
+ interface ConfidenceThresholds {
857
+ trustedReads: number;
858
+ authoritativeReads: number;
859
+ /** Days without a read after which confidence drops one tier (authoritative → trusted). */
860
+ decayDays: number;
861
+ /** Days without a read after which confidence drops two tiers (e.g. authoritative → low). */
862
+ hardDecayDays: number;
863
+ }
864
+ declare const DEFAULT_CONFIDENCE_THRESHOLDS: ConfidenceThresholds;
865
+ /**
866
+ * Compute the trust level of a memory.
867
+ *
868
+ * Base tier is derived from `status + read_count`:
869
+ * - draft → unverified
870
+ * - proposed (low reads) → low
871
+ * - proposed (3+ reads) → trusted
872
+ * - validated (low reads) → trusted
873
+ * - validated (10+ reads) → authoritative
874
+ * - stale / deprecated / rejected → stale
875
+ *
876
+ * On top of the base tier, a TIME DECAY is applied: a memory that has not been
877
+ * read in `decayDays` (default 180) drops one tier, and one not read in
878
+ * `hardDecayDays` (default 365) drops two tiers. The clock starts at
879
+ * `last_read_at` if any, otherwise `created_at` from the frontmatter.
880
+ *
881
+ * The decay never crosses into `stale` (we keep that signal reserved for the
882
+ * verifier). The intent is to surface "this used to be authoritative but
883
+ * nobody has touched it in a year — verify before quoting it" without
884
+ * pretending the memory is wrong.
885
+ */
886
+ declare function deriveConfidence(fm: MemoryFrontmatter, usage: MemoryUsage, thresholds?: ConfidenceThresholds, now?: Date): ConfidenceLevel;
887
+ interface AutoPromoteRule {
888
+ /** Minimum read_count to promote proposed → validated. */
889
+ minReads: number;
890
+ /** Maximum rejected_count tolerated (memories with more rejections never auto-promote). */
891
+ maxRejections: number;
892
+ }
893
+ declare const DEFAULT_AUTO_PROMOTE_RULE: AutoPromoteRule;
894
+ declare function isAutoPromoteEligible(fm: MemoryFrontmatter, usage: MemoryUsage, rule?: AutoPromoteRule): boolean;
895
+
896
+ /**
897
+ * Tag stamped on memories that were pre-seeded from a stack pack at `hivelore init`
898
+ * (generic framework knowledge the model already largely knows, not repo-specific
899
+ * institutional knowledge). Briefing ranking caps these at `background` priority so
900
+ * a generic seed never displaces a repo-specific memory — unless the seed has been
901
+ * anchored to a file the agent is actually editing.
902
+ */
903
+ declare const STACK_PACK_TAG = "stack-pack";
904
+ /** True when a memory was pre-seeded from a stack pack (carries {@link STACK_PACK_TAG}). */
905
+ declare function isStackPackSeed(fm: {
906
+ tags?: string[];
907
+ } | null | undefined): boolean;
908
+ /**
909
+ * Tags that mark a memory as a *local dev-environment workaround* (hot-swap, nested node_modules,
910
+ * global-install quirks) rather than repo-specific team policy. These are real, but they describe
911
+ * tooling debt, not unguessable team knowledge — and because they get read on almost every session
912
+ * their read_count inflates and they crowd the briefing. Ranking caps them at `background` UNLESS
913
+ * they directly anchor a file being edited, so they stop displacing actual policy. The fix for a
914
+ * recurring one is to repair the environment, not to keep surfacing the note.
915
+ */
916
+ declare const ENV_WORKAROUND_TAGS: Set<string>;
917
+ /** True when a memory is tagged as a local dev-environment workaround (see {@link ENV_WORKAROUND_TAGS}). */
918
+ declare function isEnvWorkaroundMemory(fm: {
919
+ tags?: string[];
920
+ } | null | undefined): boolean;
921
+ declare function extractReferencedPaths(text: string): string[];
922
+ /**
923
+ * True when a memory carries any tag in `excludeTags` (case-insensitive) — used to keep
924
+ * strategy/positioning memories OUT of automatic briefing surfacing while leaving them searchable.
925
+ * See `HaiveConfig.briefingExcludeTags`. Empty/undefined list ⇒ never excluded.
926
+ */
927
+ declare function memoryHasExcludedTag(fm: {
928
+ tags?: string[];
929
+ } | null | undefined, excludeTags: string[] | null | undefined): boolean;
930
+ /**
931
+ * Best-effort inference: given a list of file paths, infer module names from
932
+ * conventional layouts (packages/X/, apps/X/, modules/X/, src/X/).
933
+ */
934
+ declare function inferModulesFromPaths(filePaths: string[]): string[];
935
+ /**
936
+ * Path overlap: returns true if `a` and `b` refer to the same path or one is a
937
+ * parent of the other. Both inputs are treated as POSIX-style relative paths.
938
+ */
939
+ declare function pathsOverlap(a: string, b: string): boolean;
940
+ declare function memoryMatchesAnchorPaths(memory: LoadedMemory["memory"], inputPaths: string[]): boolean;
941
+ declare function isGlobPath(p: string): boolean;
942
+ declare function globToRegExp(pattern: string): RegExp;
943
+ declare function relPathFrom(root: string, abs: string): string;
944
+
945
+ /**
946
+ * Distinctive-token corroboration for the anti-pattern gate.
947
+ *
948
+ * The pre-commit gate used to hard-block whenever a diff shared ANY ≥4-char token
949
+ * with an anchored gotcha's body. That fires on ubiquitous domain words ("memory",
950
+ * "sensor", "scope", "input", "version") and on version-bump diffs — blocking agents
951
+ * for nothing. The fix: a `literal` overlap only corroborates a BLOCK when at least
952
+ * one shared token is *distinctive* to that gotcha — i.e. rare across the gotcha
953
+ * corpus (low document frequency), like `BigInt`, `open-in-view`, `rec_7`. Common
954
+ * words can still surface the warning for review; they just can't hard-block.
955
+ *
956
+ * Pure module (no I/O), TF-IDF-style. Unit-tested in `test/distinctive.test.ts`.
957
+ */
958
+ /**
959
+ * Language keywords + ubiquitous code words that would match almost any memory body
960
+ * and so carry no distinguishing signal. Shared by the diff tokenizer and the
961
+ * distinctiveness check so "literal" stays meaningful.
962
+ */
963
+ declare const CODE_STOPWORDS: Set<string>;
964
+ /** Minimum token length kept for word-level matching (shorter tokens are too noisy). */
965
+ declare const MIN_WORD_LEN = 4;
966
+ /** Split text into lowercase word tokens (>= MIN_WORD_LEN, excluding code stopwords). */
967
+ declare function tokenizeWords(text: string): string[];
968
+ interface DocFrequency {
969
+ /** token -> number of documents (memory bodies) it appears in */
970
+ df: Map<string, number>;
971
+ /** total number of documents */
972
+ total: number;
973
+ }
974
+ /** Build per-token document frequency across a corpus of memory bodies. */
975
+ declare function buildDocFrequency(bodies: string[]): DocFrequency;
976
+ /**
977
+ * Document-frequency cap at/below which a token counts as distinctive. Deliberately
978
+ * strict — "distinctive" means *rare* (≈ the bottom 10% of the corpus), with a floor
979
+ * of 1 so a token appearing in a single memory is always distinctive. Strictness is
980
+ * intentional: blocking is the aggressive action, so we under-block rather than fire
981
+ * on a word that several gotchas happen to share.
982
+ */
983
+ declare function distinctiveCap(total: number): number;
984
+ /** True when `token` is distinctive (rare) within the corpus. */
985
+ declare function isDistinctiveToken(token: string, freq: DocFrequency): boolean;
986
+ /**
987
+ * True when the added diff text shares at least one *distinctive* word token with the
988
+ * memory body. This is the precise corroboration the block decision should require:
989
+ * "the change actually contains the specific thing this gotcha warns about", not
990
+ * "the change happens to mention a common domain word".
991
+ */
992
+ declare function diffHasDistinctiveOverlap(addedDiffText: string, memoryBody: string, freq: DocFrequency): boolean;
993
+
994
+ /**
995
+ * Progressive disclosure for `skill` memories.
996
+ *
997
+ * Skills are reusable playbooks. Surfacing all of them on every briefing wastes the
998
+ * instruction budget and buries the relevant one. A skill with an `activation` block
999
+ * is disclosed ONLY when it is relevant to the current task/files; a skill without
1000
+ * one keeps the legacy always-eligible behavior. This module is pure (no I/O).
1001
+ */
1002
+ interface ActivationContext {
1003
+ task?: string;
1004
+ files?: string[];
1005
+ }
1006
+ interface SkillActivation {
1007
+ applicable: boolean;
1008
+ activated: boolean;
1009
+ reasons: string[];
1010
+ }
1011
+ declare function isSkill(fm: Pick<MemoryFrontmatter, "type">): boolean;
1012
+ /**
1013
+ * Decide whether a skill should be disclosed for the given context.
1014
+ * For non-skills, or skills with no `activation` block, returns `activated: true`
1015
+ * (never suppress them). Otherwise activates on `always`, a keyword substring match
1016
+ * against the task, or a glob match against the edited files.
1017
+ */
1018
+ declare function evaluateSkillActivation(fm: Pick<MemoryFrontmatter, "type" | "activation">, ctx: ActivationContext): SkillActivation;
1019
+ /** Convenience: true when a skill defines activation triggers that the context does NOT satisfy. */
1020
+ declare function isSkillSuppressed(fm: Pick<MemoryFrontmatter, "type" | "activation">, ctx: ActivationContext): boolean;
1021
+
1022
+ /**
1023
+ * Specificity ("surprise") scoring for memories.
1024
+ *
1025
+ * Hivelore's measured value is preventing agents from reinventing — wrongly — the team's
1026
+ * NON-OBVIOUS, arbitrary decisions (e.g. "public ids are internal id + 100000 prefixed AC-",
1027
+ * "the status field must be 'OK'/'KO'"). A capable model already knows generic best practice
1028
+ * ("use Decimal for money", "validate input"), so surfacing that is pure token overhead.
1029
+ *
1030
+ * `specificityScore` is a cheap, deterministic heuristic that estimates how *unguessable* a
1031
+ * memory is: high when it contains concrete, arbitrary signal (string literals, code
1032
+ * identifiers, magic numbers, paths, ALLCAPS constants), low when it is generic prose.
1033
+ *
1034
+ * It is intentionally a heuristic, not a model call — used to (1) bias briefing ranking toward
1035
+ * unguessable knowledge, (2) keep a near-empty briefing cheap when nothing team-specific
1036
+ * matches, (3) lint low-value memories, and (4) filter auto-capture candidates.
1037
+ */
1038
+ /**
1039
+ * Estimate how unguessable / team-specific a memory body is, in [0, 1].
1040
+ * ~0 = generic advice a model already follows by default.
1041
+ * ~1 = arbitrary, repo-specific knowledge no model can infer.
1042
+ */
1043
+ declare function specificityScore(body: string): number;
1044
+ /**
1045
+ * True when a body uses generic best-practice phrasing a capable model already follows.
1046
+ * Used to SCOPE the LOW_VALUE lint: a low-density body is only "guessable noise" when it also
1047
+ * reads like generic advice. An arbitrary team *policy* can be prose-y yet unguessable (e.g.
1048
+ * "UI text in English, user content in any language") — that must NOT be flagged. Positive
1049
+ * evidence (a generic phrase) keeps the lint high-precision and kills that false positive.
1050
+ */
1051
+ declare function looksLikeGenericAdvice(body: string): boolean;
1052
+ /** Default threshold below which a memory is considered likely-guessable (low marginal value). */
1053
+ declare const GUESSABLE_THRESHOLD = 0.3;
1054
+ /** True when a memory body looks like generic knowledge a capable model already has. */
1055
+ declare function isLikelyGuessable(body: string, threshold?: number): boolean;
1056
+ /**
1057
+ * Quality floor for SEEDED memories (stack packs, ingested findings) — the guard against shipping
1058
+ * low-value "use const not var" starter content. A seed earns its place only if it is either:
1059
+ * - ENFORCEABLE: it carries a hand-authored sensor (its value is the gate, not its prose), or
1060
+ * - SPECIFIC: it reads as a concrete framework/repo trap (specificity >= floor) and is NOT
1061
+ * generic best-practice prose a capable model already follows.
1062
+ * Used both at seed time (skip a memory that fails) and as a CI guard over the shipped pack library.
1063
+ *
1064
+ * The floor (0.2) is intentionally LOWER than {@link GUESSABLE_THRESHOLD} (0.3, used to lint claimed
1065
+ * team knowledge): a seed is explicitly background-priority framework REFERENCE, not a claim of
1066
+ * non-guessable team policy, so a concrete framework gotcha with a code example clears it — while
1067
+ * genuine garbage ("use const", "write tests") still scores ~0 and/or trips looksLikeGenericAdvice.
1068
+ */
1069
+ declare const SEED_QUALITY_FLOOR = 0.2;
1070
+ declare function meetsSeedQualityFloor(body: string, hasSensor: boolean, floor?: number): boolean;
1071
+
1072
+ /**
1073
+ * Token budgeting helpers. We use the standard heuristic of ~4 chars per token,
1074
+ * which is conservative for English/code/markdown. Callers that need exact
1075
+ * counts should plug in a real tokenizer; this module only ever over-estimates,
1076
+ * so the user's hard limits are respected.
1077
+ */
1078
+ declare const CHARS_PER_TOKEN = 4;
1079
+ declare function estimateTokens(text: string): number;
1080
+ interface TruncateOptions {
1081
+ /** Maximum tokens allowed in the result (inclusive). */
1082
+ maxTokens: number;
1083
+ /** Marker inserted where content was dropped. */
1084
+ marker?: string;
1085
+ /** Where to keep characters from when truncating. Default: head. */
1086
+ mode?: "head" | "tail" | "middle";
1087
+ }
1088
+ interface TruncateResult {
1089
+ text: string;
1090
+ truncated: boolean;
1091
+ estimatedTokens: number;
1092
+ originalTokens: number;
1093
+ }
1094
+ declare function truncateToTokens(input: string, options: TruncateOptions): TruncateResult;
1095
+ /**
1096
+ * Allocate a global token budget across N parts with relative weights, then
1097
+ * truncate each part to its share. Returns parts in input order, paired with
1098
+ * truncate metadata.
1099
+ */
1100
+ interface BudgetPart {
1101
+ key: string;
1102
+ text: string;
1103
+ weight: number;
1104
+ mode?: TruncateOptions["mode"];
1105
+ }
1106
+ interface BudgetSlice {
1107
+ key: string;
1108
+ text: string;
1109
+ truncated: boolean;
1110
+ estimatedTokens: number;
1111
+ originalTokens: number;
1112
+ allocatedTokens: number;
1113
+ }
1114
+ declare function allocateBudget(parts: BudgetPart[], maxTokens: number): BudgetSlice[];
1115
+
1116
+ declare const CODE_MAP_FILE = "code-map.json";
1117
+ type CodeExportKind = "function" | "class" | "interface" | "type" | "const" | "enum" | "default";
1118
+ interface CodeExport {
1119
+ name: string;
1120
+ kind: CodeExportKind;
1121
+ description?: string;
1122
+ line: number;
1123
+ }
1124
+ interface CodeFileEntry {
1125
+ summary?: string;
1126
+ exports: CodeExport[];
1127
+ loc: number;
1128
+ }
1129
+ interface CodeMap {
1130
+ version: 1;
1131
+ generated_at: string;
1132
+ root: string;
1133
+ files: Record<string, CodeFileEntry>;
1134
+ }
1135
+ interface BuildCodeMapOptions {
1136
+ includeExtensions?: string[];
1137
+ excludeDirs?: string[];
1138
+ /** Include untracked files that are not ignored by git. Default: false when the root is a git repo. */
1139
+ includeUntracked?: boolean;
1140
+ }
1141
+ declare function codeMapPath(paths: HaivePaths): string;
1142
+ declare function loadCodeMap(paths: HaivePaths): Promise<CodeMap | null>;
1143
+ declare function saveCodeMap(paths: HaivePaths, map: CodeMap): Promise<void>;
1144
+ declare function buildCodeMap(root: string, options?: BuildCodeMapOptions): Promise<CodeMap>;
1145
+ /**
1146
+ * Count source files physically present on disk (FS walk, excluding node_modules/build/hidden dirs),
1147
+ * regardless of git tracking. Used by `hivelore doctor` to detect a code-map that captured far fewer
1148
+ * files than the repo actually holds (untracked source, or a structure the indexer missed).
1149
+ */
1150
+ declare function countSourceFilesOnDisk(root: string, options?: {
1151
+ excludeDirs?: string[];
1152
+ }): Promise<number>;
1153
+ interface CodeMapQueryOptions {
1154
+ file?: string;
1155
+ symbol?: string;
1156
+ }
1157
+ declare function queryCodeMap(map: CodeMap, options: CodeMapQueryOptions): {
1158
+ files: Array<{
1159
+ path: string;
1160
+ entry: CodeFileEntry;
1161
+ }>;
1162
+ };
1163
+
1164
+ interface AstExport {
1165
+ name: string;
1166
+ kind: CodeExportKind;
1167
+ /** 1-based line of the declaration (or the `export`/assignment that introduces it). */
1168
+ line: number;
1169
+ }
1170
+ /**
1171
+ * Parse a source file into its exported symbols using a real AST. Returns null when AST parsing is
1172
+ * unavailable for this file (unsupported extension, runtime init failure, or grammar load failure),
1173
+ * which signals the caller to use the regex fallback. An empty array means "parsed fine, no exports".
1174
+ */
1175
+ declare function parseFileAst(source: string, ext: string): Promise<AstExport[] | null>;
1176
+
1177
+ declare const CONFIG_FILE = "haive.config.json";
1178
+ /** A remote or local repo to pull shared memories from. */
1179
+ interface CrossRepoSource {
1180
+ /** Human-readable name for this source (used in imported memory tags). */
1181
+ name: string;
1182
+ /** Local filesystem path to the other project's root (relative or absolute). */
1183
+ path?: string;
1184
+ /** Git URL — clone/fetch performed automatically. */
1185
+ git?: string;
1186
+ /** Only import memories matching all of these filters. */
1187
+ filter?: {
1188
+ /** Only import memories with these tags. */
1189
+ tags?: string[];
1190
+ /** Only import memories of these types. */
1191
+ types?: string[];
1192
+ };
1193
+ }
1194
+ /** An API contract file to snapshot and monitor for breaking changes. */
1195
+ interface ContractFile {
1196
+ /** Human-readable name for this contract. */
1197
+ name: string;
1198
+ /** Path to the contract file, relative to the project root. */
1199
+ path: string;
1200
+ /** Format of the contract file. */
1201
+ format: "openapi" | "graphql" | "proto" | "typescript" | "json-schema";
1202
+ }
1203
+ interface HaiveConfig {
1204
+ /** Autopilot mode: maximum autonomy, minimum human intervention. Default: false. */
1205
+ autopilot?: boolean;
1206
+ /**
1207
+ * Adaptive briefing: when get_briefing finds no team-specific (unguessable) memory for the
1208
+ * task/files, trim the auto-generated project context so the call stays near-zero-cost.
1209
+ * A capable model needs nothing extra in that case. Curated context is never trimmed.
1210
+ * Default: true.
1211
+ */
1212
+ adaptiveBriefing?: boolean;
1213
+ /**
1214
+ * Memory tags that are EXCLUDED from automatic surfacing in `get_briefing` / `mem_relevant_to`.
1215
+ * Purpose: break the self-reinforcing bias loop where strategy/positioning memories get auto-injected
1216
+ * into every agent's context and shape its *opinions* (not just its facts). Excluded memories are
1217
+ * still fully searchable via explicit `mem_search` / `memory search` — they just don't auto-load.
1218
+ * Matching is case-insensitive on frontmatter tags. Default targets clearly-meta tags; override
1219
+ * (set to `[]` to disable). Note: this filters by TAG, so tag strategy notes accordingly.
1220
+ */
1221
+ briefingExcludeTags?: string[];
1222
+ /** Default scope for new memories. Default: "personal". Autopilot sets "team". */
1223
+ defaultScope?: "personal" | "team";
1224
+ /**
1225
+ * Default status for new memories saved via mem_save.
1226
+ * Autopilot sets "validated" — skips the approval cycle entirely.
1227
+ * Default: "draft".
1228
+ */
1229
+ defaultStatus?: "draft" | "validated";
1230
+ /** Auto-approve proposed memories after N hours without rejection. Default: null (disabled). */
1231
+ autoApproveDelayHours?: number | null;
1232
+ /**
1233
+ * Auto-promote proposed→validated after N reads (overrides DEFAULT_AUTO_PROMOTE_RULE).
1234
+ * Autopilot sets 1 (immediate on first use).
1235
+ */
1236
+ autoPromoteMinReads?: number;
1237
+ /** Auto-save session recap on MCP server exit. Default: true in autopilot, false otherwise. */
1238
+ autoSessionEnd?: boolean;
1239
+ /**
1240
+ * Persist an auto-generated `session_recap` MEMORY into the `.ai/` corpus on automatic
1241
+ * session end (MCP exit / SessionEnd hook). Default: true (preserves historical behavior).
1242
+ * Set false to stop the low-signal recap dump from accumulating in — and biasing — the corpus;
1243
+ * pair with `sessionHandoff` for an ephemeral NEXT.md handoff instead. Has no effect on a
1244
+ * manual `hivelore session end --goal ...` (an explicit recap is always honored).
1245
+ */
1246
+ autoSessionRecap?: boolean;
1247
+ /**
1248
+ * On automatic session end, write/overwrite an ephemeral `NEXT.md` handoff at the repo root
1249
+ * (open threads + next steps). Default: false. Meant to be gitignored — one overwritten file,
1250
+ * not an accumulating corpus memory. Surfaced as `last_session` when no recap memory exists.
1251
+ */
1252
+ sessionHandoff?: boolean;
1253
+ /**
1254
+ * Auto-generate a minimal project context from code-map when project-context.md is still
1255
+ * the template. Default: true in autopilot, false otherwise.
1256
+ */
1257
+ autoContext?: boolean;
1258
+ /**
1259
+ * Safe self-maintenance performed automatically in autopilot mode.
1260
+ * These repairs are intentionally conservative: no guessed anchor is applied
1261
+ * without strong evidence, but headings/tags/indexes/context metadata can be
1262
+ * kept fresh by the tool itself.
1263
+ */
1264
+ autoRepair?: {
1265
+ /** Keep .ai/project-context.md version metadata aligned with package.json. */
1266
+ context?: boolean;
1267
+ /** Apply safe memory lint fixes: headings and `needs_anchor` tags. */
1268
+ corpus?: boolean;
1269
+ /** Refresh .ai/code-map.json during sync when needed. */
1270
+ codeMap?: boolean;
1271
+ /** Best-effort build of code-search embeddings when @hivelore/embeddings is available. */
1272
+ codeSearch?: boolean;
1273
+ };
1274
+ /**
1275
+ * Other repos to pull `shared`-scoped memories from during `hivelore sync`.
1276
+ * Each source must have either `path` (local) or `git` (remote URL).
1277
+ *
1278
+ * Example:
1279
+ * { "name": "backend", "path": "../repo-backend", "filter": { "tags": ["api-contract"] } }
1280
+ */
1281
+ crossRepoSources?: CrossRepoSource[];
1282
+ /**
1283
+ * API contract files to snapshot and watch for breaking changes.
1284
+ * `hivelore sync` compares the current file against `.ai/contracts/<name>.lock`
1285
+ * and creates a `gotcha` memory if a breaking change is detected.
1286
+ *
1287
+ * Example:
1288
+ * { "name": "payment-api", "path": "docs/openapi.yaml", "format": "openapi" }
1289
+ */
1290
+ contractFiles?: ContractFile[];
1291
+ /**
1292
+ * Local path to a shared team-knowledge hub repo.
1293
+ * Used by `hivelore hub pull` and `hivelore hub push`.
1294
+ * Can be relative (resolved from project root) or absolute.
1295
+ */
1296
+ hubPath?: string;
1297
+ /**
1298
+ * Lock file paths to watch for dependency version changes.
1299
+ * Auto-detected if not specified (package.json, pom.xml, go.mod, etc.).
1300
+ * Set to [] to disable dependency tracking entirely.
1301
+ */
1302
+ dependencyFiles?: string[];
1303
+ /**
1304
+ * Agent-enforcement settings. Enabled by default so initialized projects
1305
+ * treat Hivelore as infrastructure, not an optional convention.
1306
+ */
1307
+ enforcement?: {
1308
+ /** Enforcement posture: advisory reports only, warn in hooks, or block workflow gates. */
1309
+ mode?: "off" | "advisory" | "strict";
1310
+ /** Require get_briefing / mem_relevant_to before state-changing MCP tools. */
1311
+ requireBriefingFirst?: boolean;
1312
+ /**
1313
+ * Pre-edit (PreToolUse) behaviour when a file's anchored policy was not yet surfaced:
1314
+ * - "advise" (default): inject the relevant memory content into the agent's context and record
1315
+ * it in the briefing marker, then ALLOW the edit — no round-trip, no separate briefing command.
1316
+ * - "block": hard-block the edit until a briefing covers the file (the legacy strict behaviour).
1317
+ * The commit-time decision-coverage gate and CI enforcement remain the hard backstops either way.
1318
+ */
1319
+ preEditGate?: "advise" | "block";
1320
+ /** Require a session recap before pre-push / CI gates pass. */
1321
+ requireSessionRecap?: boolean;
1322
+ /** Require memory anchor verification before pre-commit / CI gates pass. */
1323
+ requireMemoryVerify?: boolean;
1324
+ /** Block changes when anchored decisions/gotchas have become stale. */
1325
+ blockStaleDecisionChanges?: boolean;
1326
+ /** Require changed files to be covered by relevant surfaced decisions/policies. */
1327
+ requireDecisionCoverage?: boolean;
1328
+ /**
1329
+ * How hard the pre-commit anti-pattern gate blocks a matching attempt/gotcha:
1330
+ * - off: never block on anti-patterns (report only)
1331
+ * - review: block only on a very strong semantic match (score ≥ 0.75) — soft, legacy default
1332
+ * - anchored: ALSO block when a high-confidence anti-pattern is anchored to a touched file
1333
+ * and corroborated by the diff (literal token or semantic ≥ 0.45). High precision.
1334
+ * - strict: block on any high-confidence anti-pattern match (anchor, literal, or semantic)
1335
+ * Config/docs-only commits are always downgraded regardless of this setting.
1336
+ * Default: "anchored" — makes "known bad approaches are blocked" true for the precise case.
1337
+ */
1338
+ antiPatternGate?: "off" | "review" | "anchored" | "strict";
1339
+ /**
1340
+ * First-agent bootstrap gate. The trigger is the COLD STATE of the corpus, not a command or flag:
1341
+ * when the knowledge layer is empty, the very first agent is forced to fill the baseline — a filled
1342
+ * project-context, a module context per component, an anchored memory per main code area, and a
1343
+ * sensor per main code area — before its commit / `enforce finish` can pass. Once the baseline
1344
+ * exists the gate is silent for every later agent, so only the first agent ever pays.
1345
+ * - off: never gate on bootstrap completeness
1346
+ * - warn: surface the missing baseline as a warning (advisory)
1347
+ * - block: hard-fail commit/finish until the baseline exists (default)
1348
+ * Config/docs-only commits (no production code changed) are downgraded to a warning regardless.
1349
+ */
1350
+ bootstrapGate?: "off" | "warn" | "block";
1351
+ /**
1352
+ * Pre-commit/pre-push decision-coverage behaviour. When true (default), the gate SURFACES the
1353
+ * relevant anchored decisions/policies itself and records them in the session marker at commit
1354
+ * time — no separate `hivelore briefing` step required. Set false for the strict legacy behaviour
1355
+ * where the commit is blocked until a prior briefing covered those decisions.
1356
+ */
1357
+ autoBrief?: boolean;
1358
+ /**
1359
+ * Execute `kind: "shell" | "test"` memory sensors during `hivelore sensors check`.
1360
+ * These run arbitrary repo-authored commands, so they are OFF by default; turn on per repo
1361
+ * (or pass `--commands`) once the team trusts the sensors. Regex sensors always run. Default false.
1362
+ */
1363
+ runCommandSensors?: boolean;
1364
+ /**
1365
+ * How `hivelore enforce finish` reacts to hard failures observed this session that were never
1366
+ * captured as a lesson (`mem_tried`):
1367
+ * - off: ignore
1368
+ * - warn: surface them as an info finding (default — failure detection has false positives)
1369
+ * - block: hard-block finish until each is captured
1370
+ * Default: "warn".
1371
+ */
1372
+ failureCaptureGate?: "off" | "warn" | "block";
1373
+ /**
1374
+ * How `hivelore eval --ci` reacts to a harness-quality regression vs the recorded baseline:
1375
+ * - off: never block
1376
+ * - warn: report the drop (default)
1377
+ * - block: exit non-zero on any score drop
1378
+ * Default: "warn".
1379
+ */
1380
+ evalRegressionGate?: "off" | "warn" | "block";
1381
+ /**
1382
+ * Default unread-age window (in days) for `hivelore memory archive` corpus decay.
1383
+ * A noisy or stale corpus is actively harmful — it makes the agent follow outdated policy.
1384
+ * Default: 180.
1385
+ */
1386
+ decayAfterDays?: number;
1387
+ /** Minimum score required for strict enforcement gates. */
1388
+ scoreThreshold?: number;
1389
+ /** Remove generated Hivelore runtime/cache files during cleanup gates. */
1390
+ cleanupGeneratedArtifacts?: boolean;
1391
+ /**
1392
+ * MCP tool surface:
1393
+ * - enforcement: compact default harness for coding agents
1394
+ * - maintenance: corpus/admin tools for humans and team stewards
1395
+ * - experimental: research/diagnostic tools that are not core product surface
1396
+ * - full: legacy alias for experimental
1397
+ */
1398
+ toolProfile?: "enforcement" | "maintenance" | "experimental" | "full";
1399
+ /** Named memory/policy families enabled for this project. */
1400
+ policyPacks?: string[];
1401
+ /**
1402
+ * Branch on which `enforce finish` enforces the release discipline (lockstep version bump +
1403
+ * matching pushed tag) as a HARD gate. On any other branch — feature/* or an integration branch
1404
+ * like `develop` — those same checks are advisory (warn), since the version/tag are produced when
1405
+ * releasing from this branch, not on every integration commit. Default: "main".
1406
+ */
1407
+ releaseBranch?: string;
1408
+ };
1409
+ }
1410
+ /**
1411
+ * Tags excluded from automatic briefing surfacing by default. These are "meta" tags — strategy,
1412
+ * positioning, competitive analysis, roadmaps — whose memories bias an agent's opinions rather than
1413
+ * inform a concrete coding task. Still searchable via explicit mem_search.
1414
+ */
1415
+ declare const DEFAULT_BRIEFING_EXCLUDE_TAGS: string[];
1416
+ declare const DEFAULT_CONFIG: HaiveConfig;
1417
+ declare const AUTOPILOT_DEFAULTS: HaiveConfig;
1418
+ /** The pre-commit anti-pattern gate hardness levels. */
1419
+ type AntiPatternGate = "off" | "review" | "anchored" | "strict";
1420
+ /**
1421
+ * Single source of truth mapping a configured `antiPatternGate` to the
1422
+ * `pre_commit_check` parameters that implement it. Both the git-hook path
1423
+ * (`hivelore enforce check`) and the standalone `hivelore precommit` command derive
1424
+ * their behavior from this so the two surfaces can never drift apart.
1425
+ */
1426
+ declare function antiPatternGateParams(gate: AntiPatternGate): {
1427
+ block_on: "any" | "high-confidence" | "never";
1428
+ anchored_blocks: boolean;
1429
+ };
1430
+ declare function configPath(paths: HaivePaths): string;
1431
+ declare function loadConfig(paths: HaivePaths): Promise<HaiveConfig>;
1432
+ declare function loadConfigSync(paths: HaivePaths): HaiveConfig;
1433
+ declare function saveConfig(paths: HaivePaths, config: HaiveConfig): Promise<void>;
1434
+
1435
+ interface CrossRepoReport {
1436
+ source: string;
1437
+ imported: string[];
1438
+ updated: string[];
1439
+ skipped: string[];
1440
+ errors: string[];
1441
+ }
1442
+ /**
1443
+ * Pull shared memories from all configured cross-repo sources.
1444
+ * Returns one report per source.
1445
+ */
1446
+ declare function pullCrossRepoSources(paths: HaivePaths, config: HaiveConfig, projectRoot: string): Promise<CrossRepoReport[]>;
1447
+
1448
+ interface DependencySnapshot {
1449
+ file: string;
1450
+ format: string;
1451
+ captured_at: string;
1452
+ deps: Record<string, string>;
1453
+ }
1454
+ interface DepChange {
1455
+ name: string;
1456
+ from: string;
1457
+ to: string;
1458
+ /** true if the major version number changed */
1459
+ isMajorBump: boolean;
1460
+ }
1461
+ interface DepTrackResult {
1462
+ file: string;
1463
+ changes: DepChange[];
1464
+ }
1465
+ /**
1466
+ * Resolve which manifest files to track.
1467
+ * Uses config.dependencyFiles if set, otherwise auto-detects from KNOWN_MANIFESTS.
1468
+ */
1469
+ declare function resolveManifestFiles(projectRoot: string, configuredFiles?: string[]): string[];
1470
+ /**
1471
+ * Check all manifest files for version changes since last snapshot.
1472
+ * Returns one result per file that has changes.
1473
+ */
1474
+ declare function trackDependencies(projectRoot: string, haiveDir: string, manifestFiles: string[]): Promise<DepTrackResult[]>;
1475
+
1476
+ interface ContractSnapshot {
1477
+ name: string;
1478
+ path: string;
1479
+ format: string;
1480
+ captured_at: string;
1481
+ hash: string;
1482
+ endpoints?: string[];
1483
+ types?: string[];
1484
+ fields?: Record<string, string[]>;
1485
+ raw_lines?: string[];
1486
+ }
1487
+ interface BreakingChange {
1488
+ kind: "endpoint_removed" | "endpoint_added" | "type_removed" | "type_added" | "field_removed" | "field_added" | "content_changed";
1489
+ description: string;
1490
+ severity: "breaking" | "additive" | "unknown";
1491
+ }
1492
+ interface ContractDiffResult {
1493
+ contract: string;
1494
+ file: string;
1495
+ changes: BreakingChange[];
1496
+ unchanged: boolean;
1497
+ }
1498
+ declare function contractLockPath(haiveDir: string, name: string): string;
1499
+ /**
1500
+ * Take a snapshot of a contract file and save it to .ai/contracts/<name>.lock.
1501
+ * Returns the snapshot.
1502
+ */
1503
+ declare function snapshotContract(projectRoot: string, haiveDir: string, contract: ContractFile): Promise<ContractSnapshot>;
1504
+ /**
1505
+ * Compare a contract file against its stored snapshot.
1506
+ * Returns the diff result. If no snapshot exists, creates one and returns unchanged.
1507
+ */
1508
+ declare function diffContract(projectRoot: string, haiveDir: string, contract: ContractFile): Promise<ContractDiffResult>;
1509
+ /**
1510
+ * Check all configured contract files for changes.
1511
+ */
1512
+ declare function watchContracts(projectRoot: string, haiveDir: string, contractFiles: ContractFile[]): Promise<ContractDiffResult[]>;
1513
+
1514
+ declare const USAGE_LOG_FILE = "tool-usage.jsonl";
1515
+ declare const USAGE_LOG_DIR = ".usage";
1516
+ interface UsageEvent {
1517
+ /** ISO timestamp */
1518
+ at: string;
1519
+ /** Tool name (MCP tool or CLI command) */
1520
+ tool: string;
1521
+ /** Truncated, non-sensitive snapshot of the input */
1522
+ summary?: string;
1523
+ }
1524
+ declare function usageLogPath(paths: HaivePaths): string;
1525
+ /**
1526
+ * Append a single usage event to the rolling log. Best-effort: failures are
1527
+ * swallowed since logging must never block tool execution.
1528
+ */
1529
+ declare function appendUsageEvent(paths: HaivePaths, event: UsageEvent): Promise<void>;
1530
+ /**
1531
+ * Read all usage events from disk. Skips malformed lines silently.
1532
+ * For very large logs (>50k lines), prefer `streamUsageEvents` (not implemented yet).
1533
+ */
1534
+ declare function readUsageEvents(paths: HaivePaths): Promise<UsageEvent[]>;
1535
+ interface UsageAggregate {
1536
+ total: number;
1537
+ by_tool: Array<{
1538
+ tool: string;
1539
+ count: number;
1540
+ last_used: string;
1541
+ }>;
1542
+ /** Most-frequently called tools first */
1543
+ top: Array<{
1544
+ tool: string;
1545
+ count: number;
1546
+ }>;
1547
+ window_start: string | null;
1548
+ window_end: string | null;
1549
+ }
1550
+ /**
1551
+ * Bucket events by tool, optionally filtered by a since cutoff (ISO date or relative like '7d').
1552
+ */
1553
+ declare function aggregateUsage(events: UsageEvent[], since?: Date): UsageAggregate;
1554
+ /**
1555
+ * Parse a since string: ISO date, or relative like '7d', '24h', '30m'.
1556
+ * Returns null when input is empty/undefined.
1557
+ */
1558
+ declare function parseSince(input: string | undefined): Date | null;
1559
+ declare function usageLogSize(paths: HaivePaths): Promise<{
1560
+ exists: boolean;
1561
+ size_bytes: number;
1562
+ lines: number;
1563
+ }>;
1564
+
1565
+ /**
1566
+ * Named budgets for get_briefing so agents choose quality vs token cost intentionally.
1567
+ */
1568
+ type BriefingBudgetPreset = "quick" | "balanced" | "deep";
1569
+ interface BriefingBudgetNumbers {
1570
+ max_tokens: number;
1571
+ max_memories: number;
1572
+ include_module_contexts: boolean;
1573
+ }
1574
+ declare const BRIEFING_PRESET_DEFAULTS: Record<BriefingBudgetPreset, BriefingBudgetNumbers>;
1575
+ /**
1576
+ * Merge preset-derived numbers with caller overrides when no preset was selected.
1577
+ */
1578
+ declare function resolveBriefingBudget(preset: BriefingBudgetPreset | undefined, overrides: BriefingBudgetNumbers): BriefingBudgetNumbers;
1579
+
1580
+ /**
1581
+ * Strip memory markdown down to actionable bullet lines — cheaper for briefing payloads.
1582
+ */
1583
+ /**
1584
+ * Prefer markdown list lines; fall back to the first substantive paragraph block.
1585
+ */
1586
+ declare function extractActionsBriefBody(markdown: string, maxChars?: number): string;
1587
+
1588
+ interface ResolveProjectInfo {
1589
+ cwd: string;
1590
+ resolved_root: string;
1591
+ haive_project_root_env: string | null;
1592
+ explicit_root: boolean;
1593
+ haive_dir_exists: boolean;
1594
+ memories_dir_exists: boolean;
1595
+ runtime_dir: string;
1596
+ /** Which of `.ai`, `.git`, `package.json` exist at `resolved_root`. */
1597
+ markers_found: string[];
1598
+ }
1599
+ /**
1600
+ * Resolve the Hivelore project root for diagnostics (MCP / CLI). Never throws.
1601
+ */
1602
+ declare function resolveProjectInfo(opts?: {
1603
+ cwd?: string;
1604
+ env?: NodeJS.ProcessEnv;
1605
+ }): ResolveProjectInfo;
1606
+
1607
+ /**
1608
+ * Suggest a stable `topic` frontmatter key (topic-upsert) from type + title.
1609
+ */
1610
+ declare function suggestTopicKey(type: string, titleOrPhrase: string): {
1611
+ topic_key: string;
1612
+ family: string;
1613
+ };
1614
+
1615
+ interface LexicalRankResult {
1616
+ ranked: LoadedMemory[];
1617
+ scores: number[];
1618
+ }
1619
+ /**
1620
+ * Okapi-BM25–style ranking over a small in-memory corpus (no extra index file).
1621
+ */
1622
+ declare function rankMemoriesLexical(loadedMemories: LoadedMemory[], query: string, limit: number): LexicalRankResult;
1623
+
1624
+ declare function firstMemoryOneLine(body: string): string;
1625
+ interface TimelineEntry {
1626
+ id: string;
1627
+ type: string;
1628
+ scope: string;
1629
+ created_at: string;
1630
+ one_line: string;
1631
+ topic?: string;
1632
+ }
1633
+ interface CollectTimelineOpts {
1634
+ memoryId?: string;
1635
+ topic?: string;
1636
+ limit: number;
1637
+ }
1638
+ /**
1639
+ * Memories related by id seed (related_ids, shared topic, anchor overlap) or by topic alone.
1640
+ */
1641
+ declare function collectTimelineEntries(all: LoadedMemory[], opts: CollectTimelineOpts): {
1642
+ entries: TimelineEntry[];
1643
+ notice?: string;
1644
+ };
1645
+
1646
+ interface ConflictCandidatesOpts {
1647
+ sinceDays: number;
1648
+ types: string[];
1649
+ minJaccard: number;
1650
+ maxPairs: number;
1651
+ /** Hard cap on memories considered ( avoids O(n²) explosions). */
1652
+ maxScan: number;
1653
+ }
1654
+ interface ConflictCandidatePair {
1655
+ id_a: string;
1656
+ id_b: string;
1657
+ jaccard: number;
1658
+ }
1659
+ interface TopicStatusPair {
1660
+ id_a: string;
1661
+ id_b: string;
1662
+ topic: string;
1663
+ status_a: string;
1664
+ status_b: string;
1665
+ }
1666
+ /**
1667
+ * Same `topic` key with opposed trust (validated vs rejected) — advisory; use `mem_conflicts_with` per id next.
1668
+ */
1669
+ declare function findTopicStatusConflictPairs(memories: LoadedMemory[], maxPairs: number): TopicStatusPair[];
1670
+ /**
1671
+ * Bulk heuristic: lexical similarity pairs for human review → often followed by `mem_conflicts_with`.
1672
+ */
1673
+ declare function findLexicalConflictPairs(memories: LoadedMemory[], opts: ConflictCandidatesOpts): {
1674
+ pairs: ConflictCandidatePair[];
1675
+ scanned: number;
1676
+ truncated: boolean;
1677
+ };
1678
+
1679
+ declare const RUNTIME_JOURNAL_FILENAME = "session-journal.ndjson";
1680
+ interface RuntimeJournalEntry {
1681
+ ts: string;
1682
+ kind: "note" | "session_end" | "mcp";
1683
+ /** Short human or agent message */
1684
+ message: string;
1685
+ /** Optional MCP tool name for kind=mcp */
1686
+ tool?: string;
1687
+ /** Arbitrary JSON-serializable metadata */
1688
+ meta?: Record<string, unknown>;
1689
+ }
1690
+ declare function runtimeJournalPath(paths: HaivePaths): string;
1691
+ /**
1692
+ * Append one NDJSON line under `.ai/.runtime/` (untracked by default).
1693
+ * Never throws to callers of shutdown hooks — wraps internally.
1694
+ */
1695
+ declare function appendRuntimeJournalEntry(paths: HaivePaths, entry: Omit<RuntimeJournalEntry, "ts"> & {
1696
+ ts?: string;
1697
+ }): Promise<void>;
1698
+ /** Read last N valid JSON lines (oldest-first in returned array). */
1699
+ declare function readRuntimeJournalTail(paths: HaivePaths, limit: number): Promise<RuntimeJournalEntry[]>;
1700
+
1701
+ declare const BRIEFING_MARKER_TTL_MS: number;
1702
+ declare const SESSION_RECAP_TTL_MS: number;
1703
+ interface BriefingMarker {
1704
+ session_id: string;
1705
+ task?: string;
1706
+ source: string;
1707
+ created_at: string;
1708
+ root: string;
1709
+ memory_ids?: string[];
1710
+ files?: string[];
1711
+ }
1712
+ declare function enforcementDir(paths: HaivePaths): string;
1713
+ declare function briefingMarkersDir(paths: HaivePaths): string;
1714
+ declare function normalizeSessionId(sessionId?: string): string;
1715
+ declare function briefingMarkerPath(paths: HaivePaths, sessionId?: string): string;
1716
+ declare function writeBriefingMarker(paths: HaivePaths, input: {
1717
+ sessionId?: string;
1718
+ task?: string;
1719
+ source: string;
1720
+ memoryIds?: string[];
1721
+ files?: string[];
1722
+ /**
1723
+ * Accumulate memory_ids/files with the existing fresh marker for THIS session instead of
1724
+ * overwriting (default true). This is what lets decision-coverage build up as the agent works:
1725
+ * every get_briefing call, every pre-edit injection, every `hivelore briefing` ADDS to the
1726
+ * session's consulted set — so a broad commit no longer requires one giant briefing covering
1727
+ * every relevant decision at once. Pass false to replace (e.g. starting a brand-new session).
1728
+ */
1729
+ accumulate?: boolean;
1730
+ }): Promise<BriefingMarker>;
1731
+ declare function hasRecentBriefingMarker(paths: HaivePaths, sessionId?: string, ttlMs?: number): Promise<boolean>;
1732
+ declare function readRecentBriefingMarker(paths: HaivePaths, sessionId?: string, ttlMs?: number): Promise<BriefingMarker | null>;
1733
+ declare function isFreshIsoDate(value: string | Date, ttlMs: number, now?: number): boolean;
1734
+
1735
+ interface RetirementSignal {
1736
+ retired: boolean;
1737
+ reason?: string;
1738
+ }
1739
+ /**
1740
+ * Explicit lifecycle gate for records that should not be fed back to agents as active policy.
1741
+ *
1742
+ * `status=deprecated/rejected/stale` is already the hard lifecycle signal. This helper covers
1743
+ * softer signals that teams naturally write while curating a corpus: an `expires_when` date,
1744
+ * a `superseded`/`obsolete` tag, or a short body note saying the attempt is now obsolete.
1745
+ *
1746
+ * Note: a plain `fixed` tag is intentionally NOT retired by itself. Many teams keep fixed
1747
+ * gotchas active as regression guards. To retire one, mark it deprecated, set expires_when,
1748
+ * use `obsolete`/`superseded`, or write that the fixed record is kept for audit/history only.
1749
+ */
1750
+ declare function retirementSignal(fm: MemoryFrontmatter, body?: string, now?: Date): RetirementSignal;
1751
+ declare function isRetiredMemory(fm: MemoryFrontmatter, body?: string, now?: Date): boolean;
1752
+
1753
+ /**
1754
+ * Is a regex sensor pattern brittle — over-fit to incident-specific literals that rot when code
1755
+ * shifts (hardcoded line numbers / ranges like `1131-1186`)? High-precision by design: digits that
1756
+ * live inside a character class (`[0-9]`) or quantifier (`{2,}`) generalize and are NOT flagged, so
1757
+ * durable patterns like `v[0-9]+\.[0-9]+` or `:\s*any\b` stay clean. Returns a short reason or null.
1758
+ *
1759
+ * Used to keep brittle legacy sensors from being counted as real protection or promoted to `block`.
1760
+ */
1761
+ declare function sensorPatternBrittleness(pattern: string): string | null;
1762
+ /**
1763
+ * Sensors — the feedback *computational* layer of the harness.
1764
+ *
1765
+ * A memory's `sensor` turns a documented lesson (gotcha/attempt) into a deterministic
1766
+ * check. Unlike semantic anti-pattern matching (probabilistic, warmup-sensitive), a
1767
+ * regex sensor fires the same way every time, so a known mistake becomes a permanent
1768
+ * guardrail. Phase 1 supports `kind: "regex"` only — pure, no I/O. `shell`/`test`
1769
+ * sensors are recognized but not executed here (they must run from the CLI).
1770
+ */
1771
+ interface SensorHit {
1772
+ /** The memory id whose sensor matched. */
1773
+ memory_id: string;
1774
+ /** The sensor that matched. */
1775
+ sensor: Sensor;
1776
+ /** Project-relative file the match was found in (when known). */
1777
+ file?: string;
1778
+ /** The matched line (trimmed, capped) — useful for review output. */
1779
+ matched_line?: string;
1780
+ /** LLM-facing self-correction message carried from the sensor. */
1781
+ message: string;
1782
+ severity: Sensor["severity"];
1783
+ }
1784
+ /** A unit of code to scan: a file path plus the text to match against. */
1785
+ interface SensorTarget {
1786
+ /** Project-relative path (used for path scoping and reporting). */
1787
+ path: string;
1788
+ /**
1789
+ * Text to scan. For a diff, pass only the added lines (callers should pre-filter)
1790
+ * so a sensor fires on "you introduced the bad pattern", not "you touched a file
1791
+ * that merely mentions it".
1792
+ */
1793
+ content: string;
1794
+ }
1795
+ /**
1796
+ * Does this sensor apply to `path`? A sensor with no explicit `paths` (and whose
1797
+ * memory has no anchor paths) applies everywhere. Otherwise it applies only to the
1798
+ * exact file or directory prefix. Use an explicit directory path (`src/foo/`) when a
1799
+ * sensor should cover a whole subtree.
1800
+ */
1801
+ declare function sensorAppliesToPath(sensor: Sensor, anchorPaths: string[], path: string): boolean;
1802
+ /**
1803
+ * Window (in added lines) searched for the `absent` (correct-usage) marker around a trigger match.
1804
+ *
1805
+ * FORWARD-biased on purpose: a risky call's required companion (e.g. an option object) is part of the
1806
+ * call's ARGUMENTS, which follow the call across the next few lines — so we look mostly ahead.
1807
+ * The lookback is tiny (catches an options-object hoisted to the line just above) but small enough
1808
+ * that a *separate* correct call sitting above a faulty one does NOT mask the faulty one (the live
1809
+ * failure that a symmetric window caused). Asymmetry > a single big symmetric window.
1810
+ */
1811
+ declare const SENSOR_ABSENT_WINDOW = 6;
1812
+ declare const SENSOR_ABSENT_LOOKBACK = 2;
1813
+ /**
1814
+ * Compile a regex sensor. Returns null when the sensor is not a runnable regex
1815
+ * (wrong kind, missing/invalid pattern) so callers can skip it safely.
1816
+ */
1817
+ declare function compileRegexSensor(sensor: Sensor): RegExp | null;
1818
+ /**
1819
+ * Run a single regex sensor over one target. Returns the first matching line as a hit,
1820
+ * or null. Deterministic and side-effect-free.
1821
+ */
1822
+ declare function runRegexSensor(memoryId: string, sensor: Sensor, target: SensorTarget): SensorHit | null;
1823
+ /**
1824
+ * Run every memory's regex sensor against every applicable target.
1825
+ *
1826
+ * Memories without a sensor, or with a non-regex sensor, are skipped (non-regex kinds
1827
+ * are the CLI's responsibility). At most one hit per (memory, file) pair is returned.
1828
+ */
1829
+ declare function runSensors(memories: Memory[], targets: SensorTarget[]): SensorHit[];
1830
+ /**
1831
+ * A shell/test sensor selected for execution — the feedback *computational* layer that a regex
1832
+ * can't express. The schema reserves `kind: "shell" | "test"`; this picks the ones whose memory
1833
+ * applies to the changed paths so the CLI can run `command` (core stays pure — it never executes).
1834
+ */
1835
+ interface CommandSensorSpec {
1836
+ memory_id: string;
1837
+ /** Command to execute (shell or test runner invocation). */
1838
+ command: string;
1839
+ kind: "shell" | "test";
1840
+ severity: Sensor["severity"];
1841
+ /** LLM-facing self-correction message carried from the sensor. */
1842
+ message: string;
1843
+ /** Anchor/scoped paths this sensor cares about (for reporting). */
1844
+ paths: string[];
1845
+ }
1846
+ /**
1847
+ * Select the shell/test sensors that apply to `changedPaths`. With no changed paths (or a sensor
1848
+ * scoped to everywhere) the sensor is selected unconditionally. Pure: the caller executes commands.
1849
+ */
1850
+ declare function selectCommandSensors(memories: Memory[], changedPaths: string[]): CommandSensorSpec[];
1851
+ /** Split a unified diff into per-file targets containing only added lines. */
1852
+ declare function sensorTargetsFromDiff(diff: string): SensorTarget[];
1853
+ /**
1854
+ * Files Hivelore itself owns/generates — scanning them with sensors self-matches the very memories
1855
+ * they mirror (a memory body documenting a bad pattern literally contains that pattern, and a
1856
+ * generated bridge re-states the block sensors). Mirrors `isHaiveOwnedPath` in the MCP
1857
+ * anti-pattern check; centralized here so the git-hook gate (`enforce check`) and the standalone
1858
+ * `sensors check` CLI can never drift apart on what counts as scannable code.
1859
+ */
1860
+ declare const HAIVE_OWNED_FILES: ReadonlySet<string>;
1861
+ /**
1862
+ * A diff target is scannable by sensors only when it is real source — never the `.ai/` knowledge
1863
+ * base or a Hivelore-generated bridge/config file. Without this guard, staging an `.ai/memories/*.md`
1864
+ * file (whose body quotes the bad pattern) makes the sensor fire on itself — a false positive.
1865
+ */
1866
+ declare function isSensorScannablePath(p: string): boolean;
1867
+ /**
1868
+ * Filter raw diff targets down to scannable source files. Falls back to scanning the whole diff as
1869
+ * one anonymous blob ONLY when the diff carried no file headers at all (e.g. a hand-fed `--diff-file`
1870
+ * with bare content) — never when every header was a Hivelore-owned path, so `.ai/`-only diffs scan nothing.
1871
+ */
1872
+ declare function scannableSensorTargets(diff: string): SensorTarget[];
1873
+ interface SensorSelfCheck {
1874
+ /** The sensor stays SILENT on the current, presumed-correct code — i.e. it won't false-positive. */
1875
+ silent_on_current: boolean;
1876
+ /** Did it fire on a known-bad example from the lesson? null when no example was available. */
1877
+ fires_on_bad: boolean | null;
1878
+ /** Files whose CURRENT content the sensor matched — evidence of a false positive. */
1879
+ fired_on: string[];
1880
+ /**
1881
+ * Safe to hard-block: silent on the current code AND (fires on the bad example, or there was no
1882
+ * example to test). A sensor that fires on correct code is exactly what trains agents to ignore the
1883
+ * gate — this is the gate that keeps the auto-generation layer honest.
1884
+ */
1885
+ passed: boolean;
1886
+ }
1887
+ /**
1888
+ * Validate a sensor before it is trusted to hard-block. Pure: the caller supplies the CURRENT
1889
+ * (presumed-correct) file contents and any bad examples lifted from the lesson body.
1890
+ *
1891
+ * - silent_on_current: the sensor must NOT match the current code (else it false-positives).
1892
+ * - fires_on_bad: if the lesson carried a bad code example, the sensor SHOULD match it.
1893
+ */
1894
+ declare function sensorSelfCheck(sensor: Sensor, input: {
1895
+ currentTargets: SensorTarget[];
1896
+ badExamples: string[];
1897
+ }): SensorSelfCheck;
1898
+ interface ProposedSensorVerdict {
1899
+ /** Safe to store at the requested severity. */
1900
+ accepted: boolean;
1901
+ /** Why a block proposal was rejected (so the agent can revise and re-propose). */
1902
+ reason?: "fires-on-current" | "missed-bad-example" | "brittle";
1903
+ self_check: SensorSelfCheck;
1904
+ /** Brittleness reason (hardcoded line numbers, etc.) or null. */
1905
+ brittle: string | null;
1906
+ }
1907
+ /**
1908
+ * Decide whether a PROPOSED sensor may be trusted at its severity. This is the deterministic gate
1909
+ * behind "the agent (LLM) proposes the sensor, core validates it": a `block` sensor is accepted only
1910
+ * if it is NOT brittle, stays SILENT on the current (presumed-correct) code, and FIRES on the bad
1911
+ * example (when one is available). A `warn` sensor is always accepted (advisory). Pure.
1912
+ */
1913
+ declare function judgeProposedSensor(sensor: Sensor, input: {
1914
+ currentTargets: SensorTarget[];
1915
+ badExamples: string[];
1916
+ }): ProposedSensorVerdict;
1917
+ /**
1918
+ * Pull candidate bad-code examples from a lesson body: fenced code blocks and inline code spans that
1919
+ * look like code (contain a call/dot/assignment). Used to confirm a generated sensor actually fires
1920
+ * on the mistake it describes.
1921
+ */
1922
+ declare function extractSensorExamples(body: string): string[];
1923
+ /**
1924
+ * Extract the added lines from a unified diff (lines starting with a single `+`,
1925
+ * excluding the `+++` file header). Mirrors the diff-handling already used by the
1926
+ * anti-pattern tokenizer so sensors fire on introductions, not mere mentions.
1927
+ */
1928
+ declare function addedLinesFromDiff(diff: string): string;
1929
+
1930
+ interface SensorSuggestionOptions {
1931
+ /** Extra paths to put on the sensor. Defaults to the memory anchor paths. */
1932
+ paths?: string[];
1933
+ }
1934
+ /**
1935
+ * A non-persisted sensor *seed*: a candidate pattern (and optional discriminating `absent` companion)
1936
+ * extracted heuristically from a lesson body, handed to the agent to PRE-FILL a `propose_sensor` call.
1937
+ *
1938
+ * A seed is NOT a live guardrail. The agent-in-the-loop write paths no longer persist heuristic
1939
+ * sensors onto frontmatter; instead they surface this seed so the agent can refine it and let
1940
+ * `propose_sensor` validate it (silent on current code, fires on the bad example) before it is trusted
1941
+ * to block. This is the "generate-then-validate via the LLM" pipeline — the heuristic only proposes.
1942
+ */
1943
+ interface SensorSeed {
1944
+ /** Regex matching the faulty usage. */
1945
+ pattern: string;
1946
+ /** Regex for the correct-usage marker (discriminating sensor) — present for "X without Y" lessons. */
1947
+ absent?: string;
1948
+ /** LLM-facing fix message derived from the lesson. */
1949
+ message: string;
1950
+ /** Scope paths for the eventual sensor (the lesson's anchor paths). */
1951
+ paths: string[];
1952
+ }
1953
+ /**
1954
+ * Conservatively extract a sensor SEED from a gotcha/attempt body — a candidate pattern for the agent
1955
+ * to validate via `propose_sensor`, never a persisted live sensor.
1956
+ *
1957
+ * This helper intentionally returns null more often than it guesses: a wrong seed wastes an agent's
1958
+ * attention, so when no distinctive token / discriminating companion is found it yields nothing and
1959
+ * the agent is simply told to author the pattern itself.
1960
+ */
1961
+ declare function suggestSensorSeed(body: string, anchorPaths: string[], options?: SensorSuggestionOptions): SensorSeed | null;
1962
+ /**
1963
+ * @deprecated The agent-in-the-loop write paths no longer persist heuristic sensors — they surface a
1964
+ * {@link SensorSeed} for `propose_sensor` to validate instead. This wrapper remains only for
1965
+ * back-compat (and the scanner-ingestion draft path, where the sensor lands on a human-reviewed
1966
+ * `proposed` draft and can never hard-block). It builds the old `autogen: true, severity: "warn"`
1967
+ * sensor from a seed. Prefer {@link suggestSensorSeed}.
1968
+ */
1969
+ declare function suggestSensorFromMemory(body: string, anchorPaths: string[], options?: SensorSuggestionOptions): Sensor | null;
1970
+
1971
+ /**
1972
+ * First-agent bootstrap state — is the repo's knowledge layer filled enough for later agents to rely on?
1973
+ *
1974
+ * The trigger for forcing a bootstrap is NOT an agent identity or a flag: it is the COLD STATE of the
1975
+ * corpus itself. The very first agent on a fresh `hivelore init` faces an empty knowledge layer; this
1976
+ * assessment turns "fill everything that must be filled" into a FINITE, repo-derived checklist so the
1977
+ * gate has a precise, reachable DONE state. Once the baseline exists the assessment returns `ready`
1978
+ * and every gate that consults it goes silent — so only the first agent ever pays the cost.
1979
+ *
1980
+ * Pure domain logic: no I/O. Callers load memories / code-map / module dirs and pass them in.
1981
+ */
1982
+
1983
+ type BootstrapGate = "off" | "warn" | "block";
1984
+ type BootstrapState = "cold" | "partial" | "ready";
1985
+ interface BootstrapGap {
1986
+ kind: "project-context" | "module-context" | "memory-coverage" | "sensor-coverage" | "index-code";
1987
+ /** Human/agent-readable description of what is missing. */
1988
+ detail: string;
1989
+ /** Concrete items the gap applies to (component names / areas). */
1990
+ items: string[];
1991
+ /** Exact tool/command call that closes the gap. */
1992
+ fix: string;
1993
+ }
1994
+ interface BootstrapMetrics {
1995
+ projectContextFilled: boolean;
1996
+ components: string[];
1997
+ modulesCovered: number;
1998
+ modulesRequired: number;
1999
+ memoryCoveredAreas: number;
2000
+ sensorCoveredAreas: number;
2001
+ mainAreas: number;
2002
+ teamMemories: number;
2003
+ sensors: number;
2004
+ }
2005
+ interface BootstrapAssessment {
2006
+ state: BootstrapState;
2007
+ /** Empty exactly when state === "ready". */
2008
+ gaps: BootstrapGap[];
2009
+ metrics: BootstrapMetrics;
2010
+ }
2011
+ interface BootstrapStateInput {
2012
+ /** Raw project-context.md content ("" if absent). */
2013
+ projectContextRaw: string;
2014
+ /** All memories loaded from .ai/memories. */
2015
+ memories: LoadedMemory[];
2016
+ /** Code file paths from the code-map (raw; this module filters out non-production files). */
2017
+ codeFiles: string[];
2018
+ /** Module names present under .ai/modules/<name>/ (directory names). */
2019
+ existingModules: string[];
2020
+ }
2021
+ /**
2022
+ * project-context is still the auto-generated template / stub rather than real content.
2023
+ * Matches the canonical detection used in briefing.ts / get-briefing: the auto-context marker counts
2024
+ * ONLY when the unfilled `TODO —` placeholders are still present (>=2). A filled context that merely
2025
+ * mentions "auto-generated by `hivelore init`" in prose (e.g. a glossary line) is NOT a template.
2026
+ */
2027
+ declare function isTemplateProjectContext(raw: string): boolean;
2028
+ /** Derive the component (main code area) a file belongs to. */
2029
+ declare function componentOf(file: string): string;
2030
+ /** The module-context directory name for a component (its last path segment). */
2031
+ declare function moduleNameOf(component: string): string;
2032
+ /**
2033
+ * Assess whether the repo knowledge layer is filled enough (the EXHAUSTIVE bar):
2034
+ * 1. project-context.md is filled (not the template, and substantial)
2035
+ * 2. every detected component (≥2) has a module context
2036
+ * 3. every main code area has at least one anchored memory (knowledge coverage)
2037
+ * 4. every main code area has at least one memory carrying a sensor (guardrail coverage)
2038
+ */
2039
+ declare function assessBootstrapState(input: BootstrapStateInput): BootstrapAssessment;
2040
+ /** Render the assessment's gaps as a numbered checklist for an agent (action_required / gate message). */
2041
+ declare function renderBootstrapChecklist(assessment: BootstrapAssessment): string;
2042
+
2043
+ /**
2044
+ * Findings ingestion — the self-feeding half of the sensors story (feature B).
2045
+ *
2046
+ * Phase 1/2 turned a documented mistake into an executable `sensor`. But someone still has
2047
+ * to *document* the mistake. Findings ingestion closes the review↔memory loop: a real defect
2048
+ * reported by a scanner (SonarQube, or any SARIF-emitting tool like ESLint/Semgrep/CodeQL)
2049
+ * becomes an anchored `gotcha`/`convention` memory, pre-filled with a conservative autogen
2050
+ * sensor, so the *next* agent is steered away from it before it writes the same code.
2051
+ *
2052
+ * This module is pure: parsers + draft synthesis, no I/O. The CLI (`hivelore ingest`) and the
2053
+ * MCP tool (`ingest_findings`) read files / write memories around these functions.
2054
+ *
2055
+ * Safety: every draft is `status: proposed` and every suggested sensor is `severity: warn`
2056
+ * + `autogen: true`. Ingestion never auto-validates and never auto-blocks (safety rules +
2057
+ * `2026-05-07-attempt-strict-precommit-gate-on-haive`). A human promotes both.
2058
+ */
2059
+ type FindingSeverity = "info" | "minor" | "major" | "critical" | "blocker";
2060
+ interface Finding {
2061
+ /** Source tool, e.g. "sonar", "eslint", "semgrep". */
2062
+ tool: string;
2063
+ /** Rule key, e.g. "typescript:S1234" or "no-unused-vars". */
2064
+ ruleId: string;
2065
+ /** Human-readable description of the problem. */
2066
+ message: string;
2067
+ severity: FindingSeverity;
2068
+ /** Project-relative file path. */
2069
+ path: string;
2070
+ /** 1-based line number, when known. */
2071
+ line?: number;
2072
+ /** Offending source snippet, when the report provides one. */
2073
+ snippet?: string;
2074
+ /**
2075
+ * Stable dedup key: `tool:ruleId:path`. Deliberately excludes the line so re-running a
2076
+ * scan after unrelated edits (which shift line numbers) does not re-propose the same memory.
2077
+ */
2078
+ key: string;
2079
+ }
2080
+ interface MemoryDraft {
2081
+ key: string;
2082
+ /** `ingest:<key>` — used as the memory `topic` so re-ingestion upserts instead of duplicating. */
2083
+ topic: string;
2084
+ frontmatter: MemoryFrontmatter;
2085
+ body: string;
2086
+ finding: Finding;
2087
+ /** True when a conservative sensor could be derived from the finding. */
2088
+ has_sensor: boolean;
2089
+ }
2090
+ interface DraftOptions {
2091
+ /** Memory type for the draft. Default "gotcha". */
2092
+ type?: "gotcha" | "convention";
2093
+ /** Scope for the draft. Default "team". */
2094
+ scope?: "personal" | "team" | "module";
2095
+ module?: string;
2096
+ author?: string;
2097
+ }
2098
+ interface DraftsOptions extends DraftOptions {
2099
+ /** Cap on number of drafts produced (after in-batch dedup). */
2100
+ limit?: number;
2101
+ /** Only ingest findings at or above this severity. Default: none (all). */
2102
+ minSeverity?: FindingSeverity;
2103
+ /** Include auto-fixable stylistic rules (semi/quotes/indent/prefer-const…). Default false — they are
2104
+ * linter-autofix noise, not lessons worth a memory. */
2105
+ includeStylistic?: boolean;
2106
+ }
2107
+ /** True when a finding's rule is pure auto-fixable formatting / naming convention (no lesson value as a seed). */
2108
+ declare function isStylisticRule(ruleId: string): boolean;
2109
+ /** Normalize a tool-specific severity string to the shared scale. */
2110
+ declare function normalizeFindingSeverity(raw: string | undefined | null): FindingSeverity;
2111
+ /**
2112
+ * Parse SARIF 2.1.0 (`runs[].results[]`). Works for any SARIF emitter (ESLint, Semgrep,
2113
+ * CodeQL, etc.). The tool name comes from `runs[].tool.driver.name`.
2114
+ */
2115
+ declare function parseSarif(input: string | unknown): Finding[];
2116
+ /**
2117
+ * Parse the SonarQube issues payload (`issues[]` from `/api/issues/search`). The file path
2118
+ * lives in `component` as `projectKey:relative/path`; we strip the project key.
2119
+ */
2120
+ declare function parseSonar(input: string | unknown): Finding[];
2121
+ /**
2122
+ * Parse the ESLint JSON formatter output (`eslint --format json`): an array of
2123
+ * `{ filePath, messages: [{ ruleId, severity, message, line }] }`. No SARIF formatter
2124
+ * package needed — this is ESLint's built-in format. `severity` is 2=error, 1=warning.
2125
+ * `opts.cwd`, when given, makes absolute `filePath`s project-relative so anchoring works.
2126
+ */
2127
+ declare function parseEslintJson(input: string | unknown, opts?: {
2128
+ cwd?: string;
2129
+ }): Finding[];
2130
+ /**
2131
+ * Parse `npm audit --json` output (`vulnerabilities` map). Each vulnerable package becomes one
2132
+ * finding anchored to `package.json` (vulnerabilities are dependency-level, not file-level), so
2133
+ * the next agent is warned before re-introducing or ignoring the advisory.
2134
+ */
2135
+ declare function parseNpmAudit(input: string | unknown): Finding[];
2136
+ type FindingFormat = "sarif" | "sonar" | "eslint" | "npm-audit";
2137
+ /** Dispatch to the right parser by declared format. */
2138
+ declare function parseFindings(format: FindingFormat, input: string | unknown, opts?: {
2139
+ cwd?: string;
2140
+ }): Finding[];
2141
+ /** Build the markdown body for a finding-derived memory. */
2142
+ declare function findingBody(finding: Finding): string;
2143
+ /** Convert one finding into a proposed memory draft (with a conservative sensor when derivable). */
2144
+ declare function findingToDraft(finding: Finding, options?: DraftOptions): MemoryDraft;
2145
+ /** Convert a batch of findings into drafts, deduped within the batch and capped/filtered. */
2146
+ declare function draftsFromFindings(findings: Finding[], options?: DraftsOptions): MemoryDraft[];
2147
+ /** Drop drafts whose topic already exists in the corpus (cross-run dedup). */
2148
+ declare function filterNewDrafts(drafts: MemoryDraft[], existingTopics: Iterable<string>): MemoryDraft[];
2149
+
2150
+ /**
2151
+ * Gate signal-quality — is the inferential (anti-pattern) gate earning trust or crying wolf?
2152
+ *
2153
+ * Hivelore's anti-pattern gate is probabilistic and warmup-sensitive, so it is deliberately calibrated
2154
+ * NOT to hard-block on weak matches. But a team needs to SEE whether the gate's signal is precise:
2155
+ * are its catches turning out to be real (prevented mistakes, applied lessons) or noise (rejected by
2156
+ * humans via `mem_feedback`)? This module turns the signals Hivelore already records — prevention events
2157
+ * (by source) and per-memory rejection counts — into a precision indicator and an actionable tuning
2158
+ * suggestion for `enforcement.antiPatternGate`. Pure: no I/O.
2159
+ */
2160
+
2161
+ interface GatePrecision {
2162
+ /** Catches recorded by deterministic regex/command sensors. */
2163
+ sensor_catches: number;
2164
+ /** Catches recorded by the inferential anti-pattern gate. */
2165
+ anti_pattern_catches: number;
2166
+ /** Total "useful" outcomes (catches + human-applied lessons). */
2167
+ useful: number;
2168
+ /** Total human rejections (mem_feedback "not useful"). Proxy for false positives. */
2169
+ rejections: number;
2170
+ /** useful / (useful + rejections), 0..1. Null when there is no signal yet. */
2171
+ precision: number | null;
2172
+ /** A tuning recommendation for enforcement.antiPatternGate, or null when current looks right. */
2173
+ suggestion: GateTuningSuggestion | null;
2174
+ }
2175
+ interface GateTuningSuggestion {
2176
+ recommended: AntiPatternGate;
2177
+ reason: string;
2178
+ }
2179
+ interface GatePrecisionMetricDelta {
2180
+ baseline: number | null;
2181
+ current: number | null;
2182
+ delta: number | null;
2183
+ }
2184
+ interface GatePrecisionDelta {
2185
+ precision: GatePrecisionMetricDelta;
2186
+ rejections: GatePrecisionMetricDelta;
2187
+ /** True when humans rejected more gate output than the baseline run. */
2188
+ false_positives_increased: boolean;
2189
+ /** True when precision is known on both sides and dropped. */
2190
+ precision_regressed: boolean;
2191
+ /** CI-friendly rollup: either more false positives or lower known precision. */
2192
+ regressed: boolean;
2193
+ }
2194
+ /**
2195
+ * Compute the gate's signal quality from prevention events + usage.
2196
+ * @param currentGate the configured antiPatternGate, used to decide whether to suggest a change.
2197
+ */
2198
+ declare function computeGatePrecision(events: PreventionEvent[], usage: UsageIndex, currentGate?: AntiPatternGate): GatePrecision;
2199
+ /**
2200
+ * Suggest loosening the gate when it is noisy (low precision with real rejection volume), or
2201
+ * tightening it when it is precise but currently soft. Returns null when current looks right or
2202
+ * there isn't enough signal to act on.
2203
+ */
2204
+ declare function suggestGate(precision: number | null, rejections: number, currentGate: AntiPatternGate): GateTuningSuggestion | null;
2205
+ /** Compare gate signal quality against a baseline for CI regression gates. Pure. */
2206
+ declare function compareGatePrecision(baseline: GatePrecision, current: GatePrecision): GatePrecisionDelta;
2207
+
2208
+ interface DashboardOptions {
2209
+ /** How many rows to include in each "top" list. Default 10. */
2210
+ top?: number;
2211
+ /** Dormancy window for impact scoring. Defaults to impact's own default. */
2212
+ dormantDays?: number;
2213
+ now?: Date;
2214
+ /** Prevention event log (from `loadPreventionEvents`) — powers the trend + recurrence rollups. */
2215
+ preventionEvents?: PreventionEvent[];
2216
+ /** Configured anti-pattern gate — lets the gate-precision rollup suggest tightening/loosening. */
2217
+ antiPatternGate?: AntiPatternGate;
2218
+ }
2219
+ interface ImpactRow {
2220
+ id: string;
2221
+ score: number;
2222
+ tier: ImpactScore["tier"];
2223
+ signals: string[];
2224
+ prune_candidate: boolean;
2225
+ }
2226
+ interface SensorRow {
2227
+ id: string;
2228
+ severity: "warn" | "block";
2229
+ last_fired: string;
2230
+ }
2231
+ interface DormantRow {
2232
+ id: string;
2233
+ last_read_at: string | null;
2234
+ age_days: number;
2235
+ }
2236
+ interface PreventionRow {
2237
+ id: string;
2238
+ type: string;
2239
+ prevented_count: number;
2240
+ last_prevented_at: string | null;
2241
+ }
2242
+ interface DashboardReport {
2243
+ generated_at: string;
2244
+ inventory: {
2245
+ /** Policy corpus size (excludes session_recap). */
2246
+ total: number;
2247
+ session_recaps: number;
2248
+ active: number;
2249
+ retired: number;
2250
+ by_scope: Record<string, number>;
2251
+ by_type: Record<string, number>;
2252
+ by_status: Record<string, number>;
2253
+ };
2254
+ /** OUTCOME measurement: prevention events = times a memory's sensor/anti-pattern fired on a real
2255
+ * diff, intercepting a known mistake. Distinct from retrieval (reads) — demonstrated value. */
2256
+ prevention: {
2257
+ total_events: number;
2258
+ memories_with_catches: number;
2259
+ top: PreventionRow[];
2260
+ /** Catch volume over time (from the prevention event log). */
2261
+ trend: PreventionTrend;
2262
+ /** Lessons re-introduced after capture (caught on >= 2 distinct days). */
2263
+ recurrence: RecurrenceReport;
2264
+ };
2265
+ /** Inferential-gate signal quality: are catches real (useful) or noise (rejected)? + tuning hint. */
2266
+ gate_precision: GatePrecision;
2267
+ impact: ImpactSummary & {
2268
+ top: ImpactRow[];
2269
+ };
2270
+ sensors: {
2271
+ total: number;
2272
+ warn: number;
2273
+ block: number;
2274
+ autogen: number;
2275
+ fired: number;
2276
+ recently_fired: SensorRow[];
2277
+ };
2278
+ health: {
2279
+ stale: number;
2280
+ retired: number;
2281
+ /** Validated decision/gotcha/architecture memories with no anchor paths or symbols. */
2282
+ anchorless: number;
2283
+ /** Memories awaiting review (draft/proposed). */
2284
+ pending: number;
2285
+ prune_candidates: number;
2286
+ };
2287
+ decay: {
2288
+ decay_days: number;
2289
+ decaying: number;
2290
+ top_dormant: DormantRow[];
2291
+ };
2292
+ corpus: {
2293
+ /** Number of memory files (policy corpus, excludes session_recap). */
2294
+ memory_files: number;
2295
+ body_chars: number;
2296
+ /** Rough token estimate (~chars/4) — how heavy the corpus is to inject. */
2297
+ est_tokens: number;
2298
+ };
2299
+ }
2300
+ /** Build the full observability rollup from the loaded corpus + usage index. Pure. */
2301
+ declare function buildDashboard(memories: LoadedMemory[], usage: UsageIndex, options?: DashboardOptions): DashboardReport;
2302
+
2303
+ /**
2304
+ * Failure-capture coverage — the gate behind Hivelore's "never silently fix the same mistake" loop.
2305
+ *
2306
+ * `hivelore observe` (the PostToolUse hook) appends an observation per tool call to
2307
+ * `.ai/.cache/observations.jsonl`, tagging hard failures with `failure_hint: true`
2308
+ * (non-zero Bash exit, `error TSxxxx`, ENOENT, …). Those failures are exactly the
2309
+ * `mem_tried` candidates the harness wants captured — otherwise the next session repeats them.
2310
+ *
2311
+ * This module is the pure decision layer: given the failure observations and the corpus's
2312
+ * `attempt`/`gotcha` memories, which failures look UNCAPTURED (no lesson recorded after them)?
2313
+ * The CLI reads the files and turns the result into an `enforce finish` finding. No I/O here.
2314
+ */
2315
+ interface FailureObservation {
2316
+ /** ISO timestamp of the observation. */
2317
+ ts: string;
2318
+ /** Tool that failed (Bash / Edit / …). */
2319
+ tool: string;
2320
+ /** Short human-readable summary of what was attempted. */
2321
+ summary: string;
2322
+ }
2323
+ interface UncapturedFailure {
2324
+ ts: string;
2325
+ tool: string;
2326
+ summary: string;
2327
+ }
2328
+ interface FailureCoverageOptions {
2329
+ /** Only consider failures newer than this many hours (avoid stale observations blocking forever). Default 24. */
2330
+ windowHours?: number;
2331
+ /** Collapse near-identical failures (same normalized summary) to one row. Default true. */
2332
+ dedupe?: boolean;
2333
+ now?: Date;
2334
+ }
2335
+ /**
2336
+ * A failure is CAPTURED when an `attempt`/`gotcha` lesson was recorded at or after it
2337
+ * (within the window) — the agent stopped and wrote the lesson down. Failures that pre-date
2338
+ * every recent capture are uncaptured: the gate should nudge (or block) on those.
2339
+ *
2340
+ * @param failures failure-tagged observations (any order)
2341
+ * @param captureTimes ISO created_at of every attempt/gotcha memory in the corpus
2342
+ */
2343
+ declare function findUncapturedFailures(failures: FailureObservation[], captureTimes: string[], options?: FailureCoverageOptions): UncapturedFailure[];
2344
+
2345
+ /**
2346
+ * Harness coverage-gap detection — "which churny files have NO team knowledge on them?".
2347
+ *
2348
+ * Hivelore's `eval` synthesizes cases from the memories that EXIST (does the corpus surface
2349
+ * correctly?). It cannot tell you what knowledge is MISSING. This module answers the inverse,
2350
+ * proactive question Fowler frames as an open challenge: of the files the team edits most, which
2351
+ * carry no covering decision/convention/gotcha/architecture memory? Those are the blind spots
2352
+ * where a confident agent is most likely to violate an unwritten rule.
2353
+ *
2354
+ * Pure: the caller supplies hot files (from git history / briefing-radar) and the loaded corpus.
2355
+ */
2356
+
2357
+ /** Where a file's "heat" came from: committed git churn, agent edits this/recent sessions, or both. */
2358
+ type HotFileSource = "git" | "agent" | "both";
2359
+ interface HotFile {
2360
+ path: string;
2361
+ /** Number of times the file changed in the lookback window (the "heat"). */
2362
+ changes: number;
2363
+ /** Provenance of the heat. Optional for back-compat with git-only callers. */
2364
+ source?: HotFileSource;
2365
+ }
2366
+ interface CoverageGap {
2367
+ path: string;
2368
+ changes: number;
2369
+ /** Provenance of the heat that made this file a blind spot. */
2370
+ source?: HotFileSource;
2371
+ }
2372
+ interface CoverageOptions {
2373
+ /** Only flag files with at least this many changes. Default 3. */
2374
+ minChanges?: number;
2375
+ /** Memory types that count as "covering" a file. Default decision/convention/gotcha/architecture. */
2376
+ coveringTypes?: string[];
2377
+ /** Cap on returned gaps. Default 20. */
2378
+ limit?: number;
2379
+ }
2380
+ /**
2381
+ * Build the set of path prefixes the corpus covers: every anchor path of a non-dead,
2382
+ * non-recap covering memory. A file is covered if it equals, or sits under, one of them.
2383
+ */
2384
+ declare function buildCoverageIndex(memories: LoadedMemory[], coveringTypes?: string[]): Set<string>;
2385
+ /** True when `file` equals or is nested under any covered path prefix. */
2386
+ declare function isCovered(file: string, coverage: Set<string>): boolean;
2387
+ /**
2388
+ * Cross hot files with the coverage index → the uncovered, frequently-edited files.
2389
+ * Highest heat first. These are the highest-value places to add a memory or sensor.
2390
+ */
2391
+ declare function findCoverageGaps(hotFiles: HotFile[], memories: LoadedMemory[], options?: CoverageOptions): CoverageGap[];
2392
+ /**
2393
+ * Tally a flat list of edited file paths into HotFiles — the agent-edit heat signal from the
2394
+ * PostToolUse observation log (files agents actually touch), complementary to committed git churn.
2395
+ * Pure: the caller reads/normalizes the observation paths.
2396
+ */
2397
+ declare function tallyHotFiles(paths: string[], source?: HotFileSource): HotFile[];
2398
+ /**
2399
+ * Merge two HotFile lists, summing heat per path. A file hot in both lists is tagged `both` so the
2400
+ * report can show that agents AND git churn both point at the same uncovered file (the strongest gap).
2401
+ */
2402
+ declare function mergeHotFiles(a: HotFile[], b: HotFile[]): HotFile[];
2403
+
2404
+ interface EvalHistoryEntry {
2405
+ /** ISO timestamp of the eval run. */
2406
+ at: string;
2407
+ /** Overall 0..100 score. */
2408
+ score: number;
2409
+ /** Optional component metrics for richer trend views. */
2410
+ mean_recall?: number;
2411
+ mrr?: number;
2412
+ catch_rate?: number;
2413
+ /** Optional version/commit the run was taken at. */
2414
+ ref?: string;
2415
+ }
2416
+ declare function evalHistoryPath(paths: HaivePaths): string;
2417
+ /** Append one eval run to the history. Best-effort, creates the dir on demand. */
2418
+ declare function appendEvalHistory(paths: HaivePaths, entry: EvalHistoryEntry): Promise<void>;
2419
+ /** Read all eval runs (skips malformed lines). */
2420
+ declare function loadEvalHistory(paths: HaivePaths): Promise<EvalHistoryEntry[]>;
2421
+ interface EvalTrend {
2422
+ /** Most recent score, or null when there is no history. */
2423
+ latest: number | null;
2424
+ /** Score before the latest, or null. */
2425
+ previous: number | null;
2426
+ /** latest − previous (positive = improving). */
2427
+ delta: number | null;
2428
+ /** Best score ever recorded. */
2429
+ best: number | null;
2430
+ /** Number of runs recorded. */
2431
+ runs: number;
2432
+ /** Last N scores oldest → newest for a sparkline. */
2433
+ recent: number[];
2434
+ /** True when the latest run dropped vs the previous one. */
2435
+ regressed: boolean;
2436
+ }
2437
+ /** Pure trend over the history (chronological order is enforced internally). */
2438
+ declare function computeEvalTrend(entries: EvalHistoryEntry[], recentN?: number): EvalTrend;
2439
+
2440
+ /**
2441
+ * Contradiction resolution planning — turns "two memories conflict" into "do THIS".
2442
+ *
2443
+ * `conflict-candidates.ts` surfaces pairs (same topic with opposed status, or lexically near-
2444
+ * duplicate). That's detection, not resolution — and Fowler lists incoherence-at-scale (a harness
2445
+ * full of contradictory guides) as a core open challenge. This module decides, deterministically,
2446
+ * which memory of a pair should WIN and which should be superseded (deprecated), so the CLI can
2447
+ * apply it. Pure: no I/O, unit-tested.
2448
+ *
2449
+ * Decision order (strongest signal first):
2450
+ * 1. status — a `validated` memory beats a `rejected`/`deprecated`/`stale` one.
2451
+ * 2. revision — higher `revision_count` (more refined via topic-upsert) wins.
2452
+ * 3. recency — newer `created_at` wins (the team's latest word).
2453
+ */
2454
+
2455
+ interface ConflictResolution {
2456
+ /** Memory id to keep authoritative. */
2457
+ keep_id: string;
2458
+ /** Memory id to deprecate (superseded). */
2459
+ supersede_id: string;
2460
+ /** Human-readable reason the winner was chosen. */
2461
+ reason: string;
2462
+ /** stale_reason to stamp on the superseded memory. */
2463
+ stale_reason: string;
2464
+ }
2465
+ /** Compare two memories; returns the one that should WIN plus the reason. Pure. */
2466
+ declare function planConflictResolution(a: LoadedMemory, b: LoadedMemory): ConflictResolution;
2467
+ interface AppliedConflictResolution {
2468
+ /** Updated frontmatter for the memory to keep (promoted). */
2469
+ winner: MemoryFrontmatter;
2470
+ /** Updated frontmatter for the memory to supersede (deprecated). */
2471
+ loser: MemoryFrontmatter;
2472
+ /** Topic the winner now carries — the consolidation target for future `mem_save` upserts. Null when neither carried one. */
2473
+ topic: string | null;
2474
+ /** True when the winner adopted the loser's topic because it had none. */
2475
+ topic_adopted: boolean;
2476
+ }
2477
+ /**
2478
+ * Turn a {@link ConflictResolution} plan into the two concrete frontmatter updates — the guided
2479
+ * supersede the backlog called for, wired into topic-upsert/revision_count:
2480
+ * - loser → deprecated, stamped with stale_reason + a related_ids link to the winner.
2481
+ * - winner → revision_count++ (it absorbed a contradiction), verified now, linked to the loser,
2482
+ * and it ADOPTS the loser's topic when it had none — so the next `mem_save` on this subject
2483
+ * upserts into the winner instead of spawning a third conflicting memory. An existing winner
2484
+ * topic is never overwritten. Pure: the caller persists both.
2485
+ */
2486
+ declare function applyConflictResolution(winner: LoadedMemory, loser: LoadedMemory, plan: ConflictResolution, now?: Date): AppliedConflictResolution;
2487
+
2488
+ /**
2489
+ * Cold-start seeding from git history — the harness has value only once the corpus is populated,
2490
+ * and a fresh repo starts empty (Fowler's "harnessability": greenfield is easy, legacy is hard).
2491
+ *
2492
+ * Reverts and fixups are the cheapest signal of a real, repo-specific mistake: a commit that had to
2493
+ * be undone or hot-fixed encodes a lesson the team already paid for. This module parses a list of
2494
+ * commits (the CLI runs `git log`) and proposes DRAFT `attempt` seeds — never validated, always
2495
+ * human-reviewed. Pure: the caller does the git I/O and the memory writes.
2496
+ */
2497
+ interface GitCommit {
2498
+ sha: string;
2499
+ subject: string;
2500
+ /** Files touched by the commit (optional — improves anchoring). */
2501
+ files?: string[];
2502
+ }
2503
+ interface SeedProposal {
2504
+ /** Kebab-ish slug derived from the reverted subject. */
2505
+ slug: string;
2506
+ /** What was tried (the thing that had to be reverted/fixed). */
2507
+ what: string;
2508
+ /** Why it failed (inferred from the revert/fixup). */
2509
+ why_failed: string;
2510
+ /** Suggested anchor paths (from the commit's files). */
2511
+ paths: string[];
2512
+ /** The source commit, for provenance. */
2513
+ source_sha: string;
2514
+ /** Detected signal kind. */
2515
+ kind: "revert" | "fixup" | "workaround";
2516
+ }
2517
+ /** True when a reverted/fixed subject is mechanical noise (merge/bump/deps/wip/format), not a lesson. */
2518
+ declare function isNoiseSubject(subject: string): boolean;
2519
+ /**
2520
+ * Turn commits into seed proposals. A `Revert "X"` commit proposes an attempt about X; an obvious
2521
+ * hotfix/fixup commit proposes an attempt about the fixed area. Deduped by slug. Pure.
2522
+ */
2523
+ declare function proposeSeedsFromCommits(commits: GitCommit[], limit?: number): SeedProposal[];
2524
+
2525
+ /**
2526
+ * Pure stack-detection helpers for cold-start seeding.
2527
+ *
2528
+ * Multi-language: reads package.json deps (JS/TS), requirements.txt (Python),
2529
+ * go.mod (Go), and pom.xml (Java/Spring) to produce the list of detected stacks.
2530
+ * No I/O — the caller reads the files and passes contents in, making this fully testable.
2531
+ */
2532
+ interface DetectStacksInput {
2533
+ /** Merged deps from package.json (dependencies + devDependencies). */
2534
+ packageJsonDeps?: Record<string, string>;
2535
+ /** Raw text of requirements.txt (or any requirements file). */
2536
+ requirementsTxt?: string;
2537
+ /** Raw text of go.mod. */
2538
+ goMod?: string;
2539
+ /** Raw text of pom.xml. */
2540
+ pomXml?: string;
2541
+ /** Raw text of composer.json (PHP). */
2542
+ composerJson?: string;
2543
+ /** Raw text of Gemfile (Ruby). */
2544
+ gemfile?: string;
2545
+ /** True when at least one .csproj/.sln file is present (.NET). */
2546
+ hasCsproj?: boolean;
2547
+ /** True when a Dockerfile is present. */
2548
+ hasDockerfile?: boolean;
2549
+ /** True when turbo.json is present (Turborepo). */
2550
+ hasTurboJson?: boolean;
2551
+ /** True when nx.json is present (Nx). */
2552
+ hasNxJson?: boolean;
2553
+ }
2554
+ type DetectableStack = "nestjs" | "nextjs" | "remix" | "react" | "express" | "fastify" | "prisma" | "drizzle" | "zustand" | "redux" | "reactquery" | "trpc" | "mongoose" | "graphql" | "vue" | "tailwind" | "vite" | "sveltekit" | "astro" | "typescript" | "monorepo" | "fastapi" | "django" | "flask" | "go" | "spring" | "laravel" | "rails" | "dotnet" | "docker";
2555
+ /**
2556
+ * Detect stacks present in a project from the raw contents of its manifest files.
2557
+ * Pure — no I/O. Pass what you have; omit what you don't.
2558
+ */
2559
+ declare function detectStacksFromManifests(input: DetectStacksInput): DetectableStack[];
2560
+
2561
+ interface MergeResult {
2562
+ /** The chosen file content. */
2563
+ content: string;
2564
+ /** Which side won. */
2565
+ winner: "ours" | "theirs";
2566
+ /** Why (for logging). */
2567
+ reason: string;
2568
+ }
2569
+ /**
2570
+ * Resolve two versions of the same memory file. Returns the winning content and the rationale.
2571
+ * Falls back to "ours" when either side can't be parsed (never throws — a merge driver must not).
2572
+ */
2573
+ declare function mergeMemoryVersions(ours: string, theirs: string): MergeResult;
2574
+
2575
+ /**
2576
+ * Recap compaction — keep the auto-generated session recap from dominating the briefing head.
2577
+ *
2578
+ * The MCP server auto-saves a minimal recap on exit (goal = "Auto-captured session (N tool calls)",
2579
+ * body = a raw tool-call/file dump). It's low signal, yet get_briefing shows the freshest recap's
2580
+ * full body at the very top of every briefing. A human/post_task recap (with a real Discoveries
2581
+ * section) is far richer. This module detects an auto recap and compresses it to its useful core
2582
+ * (the Discoveries, if any) so it informs without crowding. Pure, unit-tested.
2583
+ */
2584
+ /**
2585
+ * True when a recap body looks auto-generated (vs. a human/post_task recap). Auto recaps come in a
2586
+ * couple of shapes, all low-signal: the session-tracker's "Auto-captured session (N tool calls)" and
2587
+ * the run-wrapper's "Edited N files across M tool calls". The common tell is a raw tool-call count.
2588
+ */
2589
+ declare function isAutoRecap(body: string): boolean;
2590
+ /**
2591
+ * Return a compact version of an auto recap body: a one-line header (the Goal line) plus the
2592
+ * Discoveries section when it carries real content (e.g. detected failures). Non-auto recaps are
2593
+ * returned unchanged.
2594
+ */
2595
+ declare function compactAutoRecapBody(body: string, maxChars?: number): string;
2596
+
2597
+ /** Filename of the ephemeral handoff at the repo root. */
2598
+ declare const HANDOFF_FILENAME = "NEXT.md";
2599
+ /** Absolute path to the handoff file for a given project root. */
2600
+ declare function handoffFilePath(root: string): string;
2601
+ interface SessionHandoffData {
2602
+ /** One-line focus of the session that just ended. */
2603
+ goal: string;
2604
+ /** Short work summary (e.g. tool/file rollup) — optional. */
2605
+ summary?: string;
2606
+ /** Unresolved items the next session should pick up (failures, attempts, TODOs). */
2607
+ openThreads?: string[];
2608
+ /** Files touched during the session. */
2609
+ filesTouched?: string[];
2610
+ /** What should happen next, free text. */
2611
+ nextSteps?: string;
2612
+ /** Optional `git diff --stat` style block to show what is uncommitted. */
2613
+ diffStat?: string;
2614
+ /** Timestamp; defaults to now. */
2615
+ at?: Date;
2616
+ }
2617
+ /**
2618
+ * Build the markdown body of the ephemeral handoff. Pure — no I/O.
2619
+ * Deliberately compact: focus + open threads + next steps are the load-bearing parts.
2620
+ */
2621
+ declare function buildHandoffMarkdown(data: SessionHandoffData): string;
2622
+ /** Write (overwrite) the ephemeral handoff. Returns the file path. Best-effort caller should catch. */
2623
+ declare function writeSessionHandoff(root: string, data: SessionHandoffData): Promise<string>;
2624
+ /** Read the handoff body if present, else null. */
2625
+ declare function readSessionHandoff(root: string): Promise<string | null>;
2626
+ /** Age of the handoff file in milliseconds (by mtime), or null if it does not exist. */
2627
+ declare function handoffAgeMs(root: string, now?: Date): Promise<number | null>;
2628
+
2629
+ type MemoryPriority = "must_read" | "useful" | "background";
2630
+ /**
2631
+ * Normalized priority evidence. A caller fills only the signals it can compute; unknown ones default
2632
+ * to false (see {@link DEFAULT_PRIORITY_SIGNALS}). The MCP path has semantic scores; the CLI path has
2633
+ * lexical scores — both reduce to these booleans.
2634
+ */
2635
+ interface PrioritySignals {
2636
+ /** Memory type (attempt, gotcha, skill, decision, …). */
2637
+ type: string;
2638
+ /** Memory tags — used for the stack-pack / env-workaround down-rank. */
2639
+ tags: string[];
2640
+ /** The memory demands explicit human approval — always surface first. */
2641
+ requiresHumanApproval: boolean;
2642
+ /** Anchored to a file the agent is editing. */
2643
+ directAnchor: boolean;
2644
+ /** Anchored to a symbol the agent requested. */
2645
+ directSymbol: boolean;
2646
+ /** Exact/literal task match (semantic match_quality "exact", or an exact lexical task hit). */
2647
+ exactTaskMatch: boolean;
2648
+ /** Strong semantic relevance (cosine ≥ 0.65). CLI has no embeddings → passes false. */
2649
+ strongSemantic: boolean;
2650
+ /** Useful-level relevance: semantic ≥ 0.35, a partial task hit, or a high lexical score. */
2651
+ usefulSemantic: boolean;
2652
+ /** Matched an inferred module or domain from the touched files. */
2653
+ moduleOrDomainMatch: boolean;
2654
+ /** A memory tag matched a task token. */
2655
+ tagTaskMatch: boolean;
2656
+ }
2657
+ declare const DEFAULT_PRIORITY_SIGNALS: PrioritySignals;
2658
+ /** Convenience: build a full signal set from a partial one. */
2659
+ declare function prioritySignals(partial: Partial<PrioritySignals>): PrioritySignals;
2660
+ /**
2661
+ * Classify a memory's briefing priority from its signals. Order matters:
2662
+ * 1. must_read — human-approval gates, direct anchor/symbol matches, and exact/strong hits on
2663
+ * negative (attempt) or skill memories: the things an agent must not miss.
2664
+ * 2. background (down-rank) — generic stack-pack seeds and local dev-environment workarounds never
2665
+ * claim `useful` on a semantic/tag match alone; they'd crowd out repo-specific knowledge. (A
2666
+ * direct anchor already promoted them to must_read above, so genuinely-relevant ones still rank.)
2667
+ * 3. useful — skills, module/domain matches, exact hits, and useful-level relevance.
2668
+ * 4. background — everything else.
2669
+ */
2670
+ declare function classifyMemoryPriority(signals: PrioritySignals): MemoryPriority;
2671
+ declare function priorityRank(priority: MemoryPriority): number;
2672
+
2673
+ /**
2674
+ * Native bridge generator — produces agent-harness-specific config files
2675
+ * from the Hivelore corpus (validated memories + block sensors).
2676
+ *
2677
+ * One pure formatter per target; no I/O.
2678
+ * The CLI command (cli/commands/bridges.ts) handles file writes and
2679
+ * idempotent marker-based updates.
2680
+ *
2681
+ * Exposed for Lot A (init.ts): call generateBridges() from hivelore init
2682
+ * to seed all bridges at initialisation time.
2683
+ */
2684
+
2685
+ type BridgeTarget = "claude" | "cursor" | "cline" | "windsurf" | "continue" | "cody" | "zed" | "roo" | "gemini" | "aider" | "agents" | "copilot";
2686
+ /** Canonical relative path from project root for each target. */
2687
+ declare const BRIDGE_TARGET_PATH: Record<BridgeTarget, string>;
2688
+ declare const BRIDGE_TARGETS: BridgeTarget[];
2689
+ /**
2690
+ * Condensed sensor shape for bridge injection.
2691
+ * Callers extract this from Memory.frontmatter.sensor — no sensor-module import needed.
2692
+ */
2693
+ interface BridgeSensor {
2694
+ id: string;
2695
+ severity: "block" | "warn";
2696
+ message: string;
2697
+ /** Regex pattern, present when sensor.kind === "regex". */
2698
+ pattern?: string;
2699
+ /** Scoped file paths (sensor.paths ?? anchor.paths). */
2700
+ paths: string[];
2701
+ }
2702
+ interface BridgeMemoryEntry {
2703
+ id: string;
2704
+ scope: string;
2705
+ type: string;
2706
+ summary: string;
2707
+ /** Anchor paths the memory applies to (for path-scoped display / Cursor globs). */
2708
+ paths: string[];
2709
+ }
2710
+ interface GenerateBridgesOptions {
2711
+ /** Max memories to inject per bridge (default: 8). */
2712
+ maxMemories?: number;
2713
+ /** Restrict generation to these targets. Defaults to all BRIDGE_TARGETS. */
2714
+ targets?: BridgeTarget[];
2715
+ }
2716
+ interface BridgeFileOutput {
2717
+ target: BridgeTarget;
2718
+ /** Relative path from project root. */
2719
+ path: string;
2720
+ content: string;
2721
+ }
2722
+ declare const BRIDGE_MARKERS: {
2723
+ readonly bridgeStart: "<!-- haive:bridge-start -->";
2724
+ readonly bridgeEnd: "<!-- haive:bridge-end -->";
2725
+ readonly memoriesStart: "<!-- haive:memories-start -->";
2726
+ readonly memoriesEnd: "<!-- haive:memories-end -->";
2727
+ readonly sensorsStart: "<!-- haive:sensors-start -->";
2728
+ readonly sensorsEnd: "<!-- haive:sensors-end -->";
2729
+ };
2730
+ /** First meaningful line of a memory body, condensed for bridge display. */
2731
+ declare function bridgeMemorySummary(body: string): string;
2732
+ /**
2733
+ * Filter and rank memories + sensors for bridge injection.
2734
+ * Pure — callers load data; this function does not read files.
2735
+ */
2736
+ declare function prepareBridgeData(memories: Memory[], sensors: BridgeSensor[], opts?: Pick<GenerateBridgesOptions, "maxMemories">): {
2737
+ topMemories: BridgeMemoryEntry[];
2738
+ blockSensors: BridgeSensor[];
2739
+ };
2740
+ /**
2741
+ * Generate bridge file content for the requested targets.
2742
+ *
2743
+ * Pure: accepts loaded memories + sensors, returns file content strings.
2744
+ * The CLI command handles I/O and idempotent marker-based updates.
2745
+ *
2746
+ * **Lot A integration point**: call this from `hivelore init` to seed bridges at initialisation.
2747
+ * Signature is intentionally stable — init.ts should call:
2748
+ * `generateBridges(memories, sensors, { targets: BRIDGE_TARGETS })`
2749
+ */
2750
+ declare function generateBridges(memories: Memory[], sensors: BridgeSensor[], opts?: GenerateBridgesOptions): BridgeFileOutput[];
2751
+
2752
+ export { AUTOPILOT_DEFAULTS, type Activation, type ActivationContext, ActivationSchema, type Anchor, AnchorSchema, type AntiPatternGate, type AppliedConflictResolution, type AstExport, type AutoPromoteRule, BRIDGE_MARKERS, BRIDGE_TARGETS, BRIDGE_TARGET_PATH, BRIEFING_MARKER_TTL_MS, BRIEFING_PRESET_DEFAULTS, type BootstrapAssessment, type BootstrapGap, type BootstrapGate, type BootstrapMetrics, type BootstrapState, type BootstrapStateInput, type BreakingChange, type BridgeFileOutput, type BridgeMemoryEntry, type BridgeSensor, type BridgeTarget, type BriefingBudgetNumbers, type BriefingBudgetPreset, type BriefingMarker, type BriefingProofLineOptions, type BudgetPart, type BudgetSlice, type BuildCodeMapOptions, CHARS_PER_TOKEN, CODE_MAP_FILE, CODE_STOPWORDS, CONFIG_FILE, type CaughtForYouOptions, type CaughtForYouRow, type CaughtForYouSummary, type CodeExport, type CodeExportKind, type CodeFileEntry, type CodeMap, type CodeMapQueryOptions, type CollectTimelineOpts, type CommandSensorSpec, type ConfidenceLevel, type ConfidenceThresholds, type ConflictCandidatePair, type ConflictCandidatesOpts, type ConflictResolution, type ContractDiffResult, type ContractFile, type ContractSnapshot, type CoverageGap, type CoverageOptions, CrossRepoProvenanceSchema, type CrossRepoReport, type CrossRepoSource, DECAY_DAYS, DEFAULT_AUTO_PROMOTE_RULE, DEFAULT_BRIEFING_EXCLUDE_TAGS, DEFAULT_CONFIDENCE_THRESHOLDS, DEFAULT_CONFIG, DEFAULT_DORMANT_DAYS, DEFAULT_PRIORITY_SIGNALS, type DashboardOptions, type DashboardReport, type DepChange, type DepTrackResult, type DependencySnapshot, type DetectStacksInput, type DetectableStack, type DocFrequency, type DormantRow, type DraftOptions, type DraftsOptions, ENV_WORKAROUND_TAGS, type EvalDelta, type EvalHistoryEntry, type EvalReport, type EvalSpec, type EvalTrend, type FailureCoverageOptions, type FailureObservation, type FeedbackAdjustment, type FeedbackAdjustmentAction, type FeedbackAdjustmentOptions, type Finding, type FindingFormat, type FindingSeverity, GUESSABLE_THRESHOLD, type GatePrecision, type GatePrecisionDelta, type GatePrecisionMetricDelta, type GateTuningSuggestion, type GenerateBridgesOptions, type GitCommit, HAIVE_DIR, HAIVE_OWNED_FILES, HANDOFF_FILENAME, type HaiveConfig, type HaivePaths, type HotFile, type HotFileSource, type ImpactOptions, type ImpactRow, type ImpactScore, type ImpactSummary, type ImpactTier, type LexicalRankResult, type LoadedMemory, MEMORIES_DIR, MIN_WORD_LEN, type Memory, type MemoryDraft, type MemoryFrontmatter, MemoryFrontmatterSchema, type MemoryPriority, type MemoryScope, MemoryScopeSchema, type MemoryStatus, MemoryStatusSchema, type MemoryType, MemoryTypeSchema, type MemoryUsage, type MergeResult, type MetricDelta, PREVENTION_DEBOUNCE_MS, PROJECT_CONTEXT_FILE, PROJECT_CONTEXT_THROTTLE_MS, type PreventionEvent, type PreventionRow, type PreventionSource, type PreventionTrend, type PrioritySignals, type ProposedSensorVerdict, RUNTIME_JOURNAL_FILENAME, type RecurrenceReport, type RecurrenceRow, type ResolveProjectInfo, type RetirementSignal, type RetrievalAggregate, type RetrievalCase, type RetrievalCaseResult, type RuntimeJournalEntry, SEED_QUALITY_FLOOR, SENSOR_ABSENT_LOOKBACK, SENSOR_ABSENT_WINDOW, SESSION_RECAP_TTL_MS, STACK_PACK_TAG, type SeedProposal, type SelfEvalOptions, type Sensor, type SensorAggregate, type SensorCase, type SensorCaseResult, type SensorHit, type SensorRow, SensorSchema, type SensorSeed, type SensorSelfCheck, type SensorSuggestionOptions, type SensorTarget, type SessionHandoffData, type SkillActivation, type TimelineEntry, type TopicStatusPair, type TruncateOptions, type TruncateResult, USAGE_FILE, USAGE_LOG_DIR, USAGE_LOG_FILE, type UncapturedFailure, type UsageAggregate, type UsageEvent, type UsageIndex, type VerifyOptions, type VerifyResult, addedLinesFromDiff, aggregateRetrieval, aggregateSensors, aggregateUsage, allocateBudget, antiPatternGateParams, appendEvalHistory, appendPreventionEvent, appendRuntimeJournalEntry, appendUsageEvent, applyConflictResolution, applyFeedbackAdjustment, assessBootstrapState, bridgeMemorySummary, briefingMarkerPath, briefingMarkersDir, briefingProofLine, buildCodeMap, buildCoverageIndex, buildDashboard, buildDocFrequency, buildFrontmatter, buildHandoffMarkdown, buildReport, bumpRead, classifyMemoryPriority, codeMapPath, collectTimelineEntries, compactAutoRecapBody, compareEvalReports, compareGatePrecision, compareImpact, compileRegexSensor, componentOf, computeEvalTrend, computeGatePrecision, computeImpact, computePreventionTrend, computeRecurrence, configPath, contractLockPath, countSourceFilesOnDisk, deriveConfidence, detectStacksFromManifests, diffContract, diffHasDistinctiveOverlap, distinctiveCap, draftsFromFindings, emptyUsage, emptyUsageIndex, enforcementDir, estimateTokens, evalHistoryPath, evaluateSkillActivation, extractActionsBriefBody, extractReferencedPaths, extractSensorExamples, extractSnippet, filterNewDrafts, findCoverageGaps, findLexicalConflictPairs, findProjectRoot, findTopicStatusConflictPairs, findUncapturedFailures, findingBody, findingToDraft, firstMemoryOneLine, generateBridges, getUsage, globToRegExp, handoffAgeMs, handoffFilePath, hasRecentBriefingMarker, hashProjectContext, inferModulesFromPaths, isAutoPromoteEligible, isAutoRecap, isCovered, isDecaying, isDistinctiveToken, isEnvWorkaroundMemory, isFreshIsoDate, isGlobPath, isLikelyGuessable, isNoiseSubject, isRetiredMemory, isSensorScannablePath, isSkill, isSkillSuppressed, isStackPackSeed, isStylisticRule, isTemplateProjectContext, judgeProposedSensor, listMarkdownFilesRecursive, literalMatchesAllTokens, literalMatchesAnyToken, loadCodeMap, loadConfig, loadConfigSync, loadEvalHistory, loadMemoriesFromDir, loadMemory, loadPreventionEvents, loadUsageIndex, looksLikeGenericAdvice, meetsSeedQualityFloor, memoryFilePath, memoryHasExcludedTag, memoryMatchesAnchorPaths, mergeHotFiles, mergeMemoryVersions, moduleNameOf, newMemoryId, normalizeFindingSeverity, normalizeSessionId, overallScore, parseEslintJson, parseFileAst, parseFindings, parseMemory, parseNpmAudit, parseSarif, parseSince, parseSonar, pathsOverlap, pickSnippetNeedle, planConflictResolution, prepareBridgeData, preventionLogPath, priorityRank, prioritySignals, projectContextRecentlyEmitted, proposeSeedsFromCommits, pullCrossRepoSources, queryCodeMap, rankMemoriesLexical, readRecentBriefingMarker, readRuntimeJournalTail, readSessionHandoff, readUsageEvents, recommendFeedbackAdjustment, recordApplied, recordPrevention, recordPreventionHits, recordProjectContextEmission, recordRejection, relPathFrom, renderBootstrapChecklist, renderCaughtForYou, resolveBriefingBudget, resolveHaivePaths, resolveManifestFiles, resolveProjectInfo, retirementSignal, runRegexSensor, runSensors, runtimeJournalPath, saveCodeMap, saveConfig, saveUsageIndex, scannableSensorTargets, scoreRetrievalCase, scoreSensorCase, selectCommandSensors, sensorAppliesToPath, sensorPatternBrittleness, sensorSelfCheck, sensorTargetsFromDiff, serializeMemory, snapshotContract, specificityScore, stripPrivate, suggestGate, suggestSensorFromMemory, suggestSensorSeed, suggestTopicKey, summarizeCaughtForYou, summarizeImpact, synthesizeSelfEvalCases, tallyHotFiles, titleFromBody, tokenizeQuery, tokenizeWords, trackDependencies, trackReads, truncateToTokens, usageLogPath, usageLogSize, usagePath, verifyAnchor, watchContracts, writeBriefingMarker, writeSessionHandoff };