claude-memory-layer 1.0.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.
Files changed (127) hide show
  1. package/.claude-plugin/commands/memory-forget.md +42 -0
  2. package/.claude-plugin/commands/memory-history.md +34 -0
  3. package/.claude-plugin/commands/memory-import.md +56 -0
  4. package/.claude-plugin/commands/memory-list.md +37 -0
  5. package/.claude-plugin/commands/memory-search.md +36 -0
  6. package/.claude-plugin/commands/memory-stats.md +34 -0
  7. package/.claude-plugin/hooks.json +59 -0
  8. package/.claude-plugin/plugin.json +24 -0
  9. package/.history/package_20260201112328.json +45 -0
  10. package/.history/package_20260201113602.json +45 -0
  11. package/.history/package_20260201113713.json +45 -0
  12. package/.history/package_20260201114110.json +45 -0
  13. package/Memo.txt +558 -0
  14. package/README.md +520 -0
  15. package/context.md +636 -0
  16. package/dist/.claude-plugin/commands/memory-forget.md +42 -0
  17. package/dist/.claude-plugin/commands/memory-history.md +34 -0
  18. package/dist/.claude-plugin/commands/memory-import.md +56 -0
  19. package/dist/.claude-plugin/commands/memory-list.md +37 -0
  20. package/dist/.claude-plugin/commands/memory-search.md +36 -0
  21. package/dist/.claude-plugin/commands/memory-stats.md +34 -0
  22. package/dist/.claude-plugin/hooks.json +59 -0
  23. package/dist/.claude-plugin/plugin.json +24 -0
  24. package/dist/cli/index.js +3539 -0
  25. package/dist/cli/index.js.map +7 -0
  26. package/dist/core/index.js +4408 -0
  27. package/dist/core/index.js.map +7 -0
  28. package/dist/hooks/session-end.js +2971 -0
  29. package/dist/hooks/session-end.js.map +7 -0
  30. package/dist/hooks/session-start.js +2969 -0
  31. package/dist/hooks/session-start.js.map +7 -0
  32. package/dist/hooks/stop.js +3123 -0
  33. package/dist/hooks/stop.js.map +7 -0
  34. package/dist/hooks/user-prompt-submit.js +2960 -0
  35. package/dist/hooks/user-prompt-submit.js.map +7 -0
  36. package/dist/services/memory-service.js +2931 -0
  37. package/dist/services/memory-service.js.map +7 -0
  38. package/package.json +45 -0
  39. package/plan.md +1642 -0
  40. package/scripts/build.ts +102 -0
  41. package/spec.md +624 -0
  42. package/specs/citations-system/context.md +243 -0
  43. package/specs/citations-system/plan.md +495 -0
  44. package/specs/citations-system/spec.md +371 -0
  45. package/specs/endless-mode/context.md +305 -0
  46. package/specs/endless-mode/plan.md +620 -0
  47. package/specs/endless-mode/spec.md +455 -0
  48. package/specs/entity-edge-model/context.md +401 -0
  49. package/specs/entity-edge-model/plan.md +459 -0
  50. package/specs/entity-edge-model/spec.md +391 -0
  51. package/specs/evidence-aligner-v2/context.md +401 -0
  52. package/specs/evidence-aligner-v2/plan.md +303 -0
  53. package/specs/evidence-aligner-v2/spec.md +312 -0
  54. package/specs/mcp-desktop-integration/context.md +278 -0
  55. package/specs/mcp-desktop-integration/plan.md +550 -0
  56. package/specs/mcp-desktop-integration/spec.md +494 -0
  57. package/specs/post-tool-use-hook/context.md +319 -0
  58. package/specs/post-tool-use-hook/plan.md +469 -0
  59. package/specs/post-tool-use-hook/spec.md +364 -0
  60. package/specs/private-tags/context.md +288 -0
  61. package/specs/private-tags/plan.md +412 -0
  62. package/specs/private-tags/spec.md +345 -0
  63. package/specs/progressive-disclosure/context.md +346 -0
  64. package/specs/progressive-disclosure/plan.md +663 -0
  65. package/specs/progressive-disclosure/spec.md +415 -0
  66. package/specs/task-entity-system/context.md +297 -0
  67. package/specs/task-entity-system/plan.md +301 -0
  68. package/specs/task-entity-system/spec.md +314 -0
  69. package/specs/vector-outbox-v2/context.md +470 -0
  70. package/specs/vector-outbox-v2/plan.md +562 -0
  71. package/specs/vector-outbox-v2/spec.md +466 -0
  72. package/specs/web-viewer-ui/context.md +384 -0
  73. package/specs/web-viewer-ui/plan.md +797 -0
  74. package/specs/web-viewer-ui/spec.md +516 -0
  75. package/src/cli/index.ts +570 -0
  76. package/src/core/canonical-key.ts +186 -0
  77. package/src/core/citation-generator.ts +63 -0
  78. package/src/core/consolidated-store.ts +279 -0
  79. package/src/core/consolidation-worker.ts +384 -0
  80. package/src/core/context-formatter.ts +276 -0
  81. package/src/core/continuity-manager.ts +336 -0
  82. package/src/core/edge-repo.ts +324 -0
  83. package/src/core/embedder.ts +124 -0
  84. package/src/core/entity-repo.ts +342 -0
  85. package/src/core/event-store.ts +672 -0
  86. package/src/core/evidence-aligner.ts +635 -0
  87. package/src/core/graduation.ts +365 -0
  88. package/src/core/index.ts +32 -0
  89. package/src/core/matcher.ts +210 -0
  90. package/src/core/metadata-extractor.ts +203 -0
  91. package/src/core/privacy/filter.ts +179 -0
  92. package/src/core/privacy/index.ts +20 -0
  93. package/src/core/privacy/tag-parser.ts +145 -0
  94. package/src/core/progressive-retriever.ts +415 -0
  95. package/src/core/retriever.ts +235 -0
  96. package/src/core/task/blocker-resolver.ts +325 -0
  97. package/src/core/task/index.ts +9 -0
  98. package/src/core/task/task-matcher.ts +238 -0
  99. package/src/core/task/task-projector.ts +345 -0
  100. package/src/core/task/task-resolver.ts +414 -0
  101. package/src/core/types.ts +841 -0
  102. package/src/core/vector-outbox.ts +295 -0
  103. package/src/core/vector-store.ts +182 -0
  104. package/src/core/vector-worker.ts +488 -0
  105. package/src/core/working-set-store.ts +244 -0
  106. package/src/hooks/post-tool-use.ts +127 -0
  107. package/src/hooks/session-end.ts +78 -0
  108. package/src/hooks/session-start.ts +57 -0
  109. package/src/hooks/stop.ts +78 -0
  110. package/src/hooks/user-prompt-submit.ts +54 -0
  111. package/src/mcp/handlers.ts +212 -0
  112. package/src/mcp/index.ts +47 -0
  113. package/src/mcp/tools.ts +78 -0
  114. package/src/server/api/citations.ts +101 -0
  115. package/src/server/api/events.ts +101 -0
  116. package/src/server/api/index.ts +18 -0
  117. package/src/server/api/search.ts +98 -0
  118. package/src/server/api/sessions.ts +111 -0
  119. package/src/server/api/stats.ts +97 -0
  120. package/src/server/index.ts +91 -0
  121. package/src/services/memory-service.ts +626 -0
  122. package/src/services/session-history-importer.ts +367 -0
  123. package/tests/canonical-key.test.ts +101 -0
  124. package/tests/evidence-aligner.test.ts +152 -0
  125. package/tests/matcher.test.ts +112 -0
  126. package/tsconfig.json +24 -0
  127. package/vitest.config.ts +15 -0
@@ -0,0 +1,841 @@
1
+ /**
2
+ * Core types for code-memory plugin
3
+ * Idris2 inspired: Complete, immutable type definitions with Zod validation
4
+ */
5
+
6
+ import { z } from 'zod';
7
+
8
+ // ============================================================
9
+ // Event Types
10
+ // ============================================================
11
+
12
+ export const EventTypeSchema = z.enum([
13
+ 'user_prompt',
14
+ 'agent_response',
15
+ 'session_summary',
16
+ 'tool_observation'
17
+ ]);
18
+ export type EventType = z.infer<typeof EventTypeSchema>;
19
+
20
+ // ============================================================
21
+ // Memory Event (L0 EventStore)
22
+ // ============================================================
23
+
24
+ export const MemoryEventSchema = z.object({
25
+ id: z.string().uuid(),
26
+ eventType: EventTypeSchema,
27
+ sessionId: z.string(),
28
+ timestamp: z.date(),
29
+ content: z.string(),
30
+ canonicalKey: z.string(),
31
+ dedupeKey: z.string(),
32
+ metadata: z.record(z.unknown()).optional()
33
+ });
34
+ export type MemoryEvent = z.infer<typeof MemoryEventSchema>;
35
+
36
+ // Input for creating new events (id, dedupeKey generated automatically)
37
+ export const MemoryEventInputSchema = MemoryEventSchema.omit({
38
+ id: true,
39
+ dedupeKey: true,
40
+ canonicalKey: true
41
+ });
42
+ export type MemoryEventInput = z.infer<typeof MemoryEventInputSchema>;
43
+
44
+ // ============================================================
45
+ // Session
46
+ // ============================================================
47
+
48
+ export const SessionSchema = z.object({
49
+ id: z.string(),
50
+ startedAt: z.date(),
51
+ endedAt: z.date().optional(),
52
+ projectPath: z.string().optional(),
53
+ summary: z.string().optional(),
54
+ tags: z.array(z.string()).optional()
55
+ });
56
+ export type Session = z.infer<typeof SessionSchema>;
57
+
58
+ // ============================================================
59
+ // Insight (L1 Structured)
60
+ // ============================================================
61
+
62
+ export const InsightTypeSchema = z.enum([
63
+ 'preference',
64
+ 'pattern',
65
+ 'expertise'
66
+ ]);
67
+ export type InsightType = z.infer<typeof InsightTypeSchema>;
68
+
69
+ export const InsightSchema = z.object({
70
+ id: z.string().uuid(),
71
+ insightType: InsightTypeSchema,
72
+ content: z.string(),
73
+ canonicalKey: z.string(),
74
+ confidence: z.number().min(0).max(1),
75
+ sourceEvents: z.array(z.string().uuid()),
76
+ createdAt: z.date(),
77
+ lastUpdated: z.date()
78
+ });
79
+ export type Insight = z.infer<typeof InsightSchema>;
80
+
81
+ // ============================================================
82
+ // Memory Match (Search Result)
83
+ // ============================================================
84
+
85
+ export const MemoryMatchSchema = z.object({
86
+ event: MemoryEventSchema,
87
+ score: z.number().min(0).max(1),
88
+ relevanceReason: z.string().optional()
89
+ });
90
+ export type MemoryMatch = z.infer<typeof MemoryMatchSchema>;
91
+
92
+ // ============================================================
93
+ // Match Confidence (AXIOMMIND)
94
+ // ============================================================
95
+
96
+ export const MatchConfidenceSchema = z.enum(['high', 'suggested', 'none']);
97
+ export type MatchConfidence = z.infer<typeof MatchConfidenceSchema>;
98
+
99
+ export const MatchResultSchema = z.object({
100
+ match: MemoryMatchSchema.nullable(),
101
+ confidence: MatchConfidenceSchema,
102
+ gap: z.number().optional(),
103
+ alternatives: z.array(MemoryMatchSchema).optional()
104
+ });
105
+ export type MatchResult = z.infer<typeof MatchResultSchema>;
106
+
107
+ // AXIOMMIND Matching Thresholds
108
+ export const MATCH_THRESHOLDS = {
109
+ minCombinedScore: 0.92,
110
+ minGap: 0.03,
111
+ suggestionThreshold: 0.75
112
+ } as const;
113
+
114
+ // ============================================================
115
+ // Memory Level (Graduation Pipeline)
116
+ // ============================================================
117
+
118
+ export const MemoryLevelSchema = z.enum(['L0', 'L1', 'L2', 'L3', 'L4']);
119
+ export type MemoryLevel = z.infer<typeof MemoryLevelSchema>;
120
+
121
+ export const GraduationResultSchema = z.object({
122
+ eventId: z.string().uuid(),
123
+ fromLevel: MemoryLevelSchema,
124
+ toLevel: MemoryLevelSchema,
125
+ success: z.boolean(),
126
+ reason: z.string().optional()
127
+ });
128
+ export type GraduationResult = z.infer<typeof GraduationResultSchema>;
129
+
130
+ // ============================================================
131
+ // Evidence Span (AXIOMMIND Principle 4)
132
+ // ============================================================
133
+
134
+ export const EvidenceSpanSchema = z.object({
135
+ start: z.number().int().nonnegative(),
136
+ end: z.number().int().positive(),
137
+ confidence: z.number().min(0).max(1),
138
+ matchType: z.enum(['exact', 'fuzzy', 'none']),
139
+ originalQuote: z.string(),
140
+ alignedText: z.string()
141
+ });
142
+ export type EvidenceSpan = z.infer<typeof EvidenceSpanSchema>;
143
+
144
+ // ============================================================
145
+ // Configuration
146
+ // ============================================================
147
+
148
+ export const ConfigSchema = z.object({
149
+ storage: z.object({
150
+ path: z.string().default('~/.claude-code/memory'),
151
+ maxSizeMB: z.number().default(500)
152
+ }).default({}),
153
+ embedding: z.object({
154
+ provider: z.enum(['local', 'openai']).default('local'),
155
+ model: z.string().default('Xenova/all-MiniLM-L6-v2'),
156
+ openaiModel: z.string().default('text-embedding-3-small'),
157
+ batchSize: z.number().default(32)
158
+ }).default({}),
159
+ retrieval: z.object({
160
+ topK: z.number().default(5),
161
+ minScore: z.number().default(0.7),
162
+ maxTokens: z.number().default(2000)
163
+ }).default({}),
164
+ matching: z.object({
165
+ minCombinedScore: z.number().default(0.92),
166
+ minGap: z.number().default(0.03),
167
+ suggestionThreshold: z.number().default(0.75),
168
+ weights: z.object({
169
+ semanticSimilarity: z.number().default(0.4),
170
+ ftsScore: z.number().default(0.25),
171
+ recencyBonus: z.number().default(0.2),
172
+ statusWeight: z.number().default(0.15)
173
+ }).default({})
174
+ }).default({}),
175
+ privacy: z.object({
176
+ excludePatterns: z.array(z.string()).default(['password', 'secret', 'api_key', 'token', 'bearer']),
177
+ anonymize: z.boolean().default(false),
178
+ privateTags: z.object({
179
+ enabled: z.boolean().default(true),
180
+ marker: z.enum(['[PRIVATE]', '[REDACTED]', '']).default('[PRIVATE]'),
181
+ preserveLineCount: z.boolean().default(false),
182
+ supportedFormats: z.array(z.enum(['xml', 'bracket', 'comment'])).default(['xml'])
183
+ }).default({})
184
+ }).default({}),
185
+ toolObservation: z.object({
186
+ enabled: z.boolean().default(true),
187
+ excludedTools: z.array(z.string()).default(['TodoWrite', 'TodoRead']),
188
+ maxOutputLength: z.number().default(10000),
189
+ maxOutputLines: z.number().default(100),
190
+ storeOnlyOnSuccess: z.boolean().default(false)
191
+ }).default({}),
192
+ features: z.object({
193
+ autoSave: z.boolean().default(true),
194
+ sessionSummary: z.boolean().default(true),
195
+ insightExtraction: z.boolean().default(true),
196
+ crossProjectLearning: z.boolean().default(false),
197
+ singleWriterMode: z.boolean().default(true)
198
+ }).default({}),
199
+ mode: z.enum(['session', 'endless']).default('session'),
200
+ endless: z.object({
201
+ enabled: z.boolean().default(false),
202
+ workingSet: z.object({
203
+ maxEvents: z.number().default(100),
204
+ timeWindowHours: z.number().default(24),
205
+ minRelevanceScore: z.number().default(0.5)
206
+ }).default({}),
207
+ consolidation: z.object({
208
+ triggerIntervalMs: z.number().default(3600000),
209
+ triggerEventCount: z.number().default(100),
210
+ triggerIdleMs: z.number().default(1800000),
211
+ useLLMSummarization: z.boolean().default(false)
212
+ }).default({}),
213
+ continuity: z.object({
214
+ minScoreForSeamless: z.number().default(0.7),
215
+ topicDecayHours: z.number().default(48)
216
+ }).default({})
217
+ }).optional()
218
+ });
219
+ export type Config = z.infer<typeof ConfigSchema>;
220
+
221
+ // ============================================================
222
+ // Append Result (AXIOMMIND Principle 2: Append-only)
223
+ // ============================================================
224
+
225
+ export type AppendResult =
226
+ | { success: true; eventId: string; isDuplicate: false }
227
+ | { success: true; eventId: string; isDuplicate: true }
228
+ | { success: false; error: string };
229
+
230
+ // ============================================================
231
+ // Hook Input/Output Types
232
+ // ============================================================
233
+
234
+ export interface SessionStartInput {
235
+ session_id: string;
236
+ cwd: string;
237
+ }
238
+
239
+ export interface SessionStartOutput {
240
+ context?: string;
241
+ }
242
+
243
+ export interface UserPromptSubmitInput {
244
+ session_id: string;
245
+ prompt: string;
246
+ }
247
+
248
+ export interface UserPromptSubmitOutput {
249
+ context?: string;
250
+ }
251
+
252
+ export interface StopInput {
253
+ session_id: string;
254
+ stop_reason: string;
255
+ messages: Array<{ role: string; content: string }>;
256
+ }
257
+
258
+ export interface SessionEndInput {
259
+ session_id: string;
260
+ }
261
+
262
+ // PostToolUse Hook Input
263
+ export interface PostToolUseInput {
264
+ tool_name: string;
265
+ tool_input: Record<string, unknown>;
266
+ tool_output: string;
267
+ tool_error?: string;
268
+ session_id: string;
269
+ started_at: string;
270
+ ended_at: string;
271
+ }
272
+
273
+ // ============================================================
274
+ // Tool Observation Types
275
+ // ============================================================
276
+
277
+ export const ToolMetadataSchema = z.object({
278
+ filePath: z.string().optional(),
279
+ fileType: z.string().optional(),
280
+ lineCount: z.number().optional(),
281
+ command: z.string().optional(),
282
+ exitCode: z.number().optional(),
283
+ pattern: z.string().optional(),
284
+ matchCount: z.number().optional(),
285
+ url: z.string().optional(),
286
+ statusCode: z.number().optional()
287
+ });
288
+ export type ToolMetadata = z.infer<typeof ToolMetadataSchema>;
289
+
290
+ export const ToolObservationPayloadSchema = z.object({
291
+ toolName: z.string(),
292
+ toolInput: z.record(z.unknown()),
293
+ toolOutput: z.string(),
294
+ durationMs: z.number(),
295
+ success: z.boolean(),
296
+ errorMessage: z.string().optional(),
297
+ metadata: ToolMetadataSchema.optional()
298
+ });
299
+ export type ToolObservationPayload = z.infer<typeof ToolObservationPayloadSchema>;
300
+
301
+ // ============================================================
302
+ // Vector Record
303
+ // ============================================================
304
+
305
+ export interface VectorRecord {
306
+ id: string;
307
+ eventId: string;
308
+ sessionId: string;
309
+ eventType: string;
310
+ content: string;
311
+ vector: number[];
312
+ timestamp: string;
313
+ metadata?: Record<string, unknown>;
314
+ }
315
+
316
+ // ============================================================
317
+ // Outbox Item (Single-Writer Pattern)
318
+ // ============================================================
319
+
320
+ export interface OutboxItem {
321
+ id: string;
322
+ eventId: string;
323
+ content: string;
324
+ status: 'pending' | 'processing' | 'done' | 'failed';
325
+ retryCount: number;
326
+ createdAt: Date;
327
+ errorMessage?: string;
328
+ }
329
+
330
+ // ============================================================
331
+ // Entity Types (Task, Condition, Artifact)
332
+ // ============================================================
333
+
334
+ export const EntityTypeSchema = z.enum(['task', 'condition', 'artifact']);
335
+ export type EntityType = z.infer<typeof EntityTypeSchema>;
336
+
337
+ export const TaskStatusSchema = z.enum([
338
+ 'pending',
339
+ 'in_progress',
340
+ 'blocked',
341
+ 'done',
342
+ 'cancelled'
343
+ ]);
344
+ export type TaskStatus = z.infer<typeof TaskStatusSchema>;
345
+
346
+ export const TaskPrioritySchema = z.enum(['low', 'medium', 'high', 'critical']);
347
+ export type TaskPriority = z.infer<typeof TaskPrioritySchema>;
348
+
349
+ export const EntityStageSchema = z.enum([
350
+ 'raw',
351
+ 'working',
352
+ 'candidate',
353
+ 'verified',
354
+ 'certified'
355
+ ]);
356
+ export type EntityStage = z.infer<typeof EntityStageSchema>;
357
+
358
+ export const EntityStatusSchema = z.enum([
359
+ 'active',
360
+ 'contested',
361
+ 'deprecated',
362
+ 'superseded'
363
+ ]);
364
+ export type EntityStatus = z.infer<typeof EntityStatusSchema>;
365
+
366
+ // Base Entity schema
367
+ export const EntitySchema = z.object({
368
+ entityId: z.string(),
369
+ entityType: EntityTypeSchema,
370
+ canonicalKey: z.string(),
371
+ title: z.string(),
372
+ stage: EntityStageSchema,
373
+ status: EntityStatusSchema,
374
+ currentJson: z.record(z.unknown()),
375
+ titleNorm: z.string().optional(),
376
+ searchText: z.string().optional(),
377
+ createdAt: z.date(),
378
+ updatedAt: z.date()
379
+ });
380
+ export type Entity = z.infer<typeof EntitySchema>;
381
+
382
+ // Task-specific current_json structure
383
+ export const TaskCurrentJsonSchema = z.object({
384
+ status: TaskStatusSchema,
385
+ priority: TaskPrioritySchema.optional(),
386
+ blockers: z.array(z.string()).optional(),
387
+ blockerSuggestions: z.array(z.string()).optional(),
388
+ description: z.string().optional(),
389
+ project: z.string().optional()
390
+ });
391
+ export type TaskCurrentJson = z.infer<typeof TaskCurrentJsonSchema>;
392
+
393
+ // Entity alias for canonical key lookup
394
+ export const EntityAliasSchema = z.object({
395
+ entityType: EntityTypeSchema,
396
+ canonicalKey: z.string(),
397
+ entityId: z.string(),
398
+ isPrimary: z.boolean()
399
+ });
400
+ export type EntityAlias = z.infer<typeof EntityAliasSchema>;
401
+
402
+ // ============================================================
403
+ // Edge Types (Relationships)
404
+ // ============================================================
405
+
406
+ export const NodeTypeSchema = z.enum(['entry', 'entity', 'event']);
407
+ export type NodeType = z.infer<typeof NodeTypeSchema>;
408
+
409
+ export const RelationTypeSchema = z.enum([
410
+ 'evidence_of',
411
+ 'blocked_by',
412
+ 'blocked_by_suggested',
413
+ 'resolves_to',
414
+ 'derived_from',
415
+ 'supersedes',
416
+ 'source_of'
417
+ ]);
418
+ export type RelationType = z.infer<typeof RelationTypeSchema>;
419
+
420
+ export const EdgeSchema = z.object({
421
+ edgeId: z.string(),
422
+ srcType: NodeTypeSchema,
423
+ srcId: z.string(),
424
+ relType: RelationTypeSchema,
425
+ dstType: NodeTypeSchema,
426
+ dstId: z.string(),
427
+ metaJson: z.record(z.unknown()).optional(),
428
+ createdAt: z.date()
429
+ });
430
+ export type Edge = z.infer<typeof EdgeSchema>;
431
+
432
+ // ============================================================
433
+ // Task Event Types (SoT for Task Entity)
434
+ // ============================================================
435
+
436
+ export const TaskEventTypeSchema = z.enum([
437
+ 'task_created',
438
+ 'task_status_changed',
439
+ 'task_priority_changed',
440
+ 'task_blockers_set',
441
+ 'task_transition_rejected',
442
+ 'condition_declared',
443
+ 'artifact_declared',
444
+ 'condition_resolved_to'
445
+ ]);
446
+ export type TaskEventType = z.infer<typeof TaskEventTypeSchema>;
447
+
448
+ export const BlockerModeSchema = z.enum(['replace', 'suggest']);
449
+ export type BlockerMode = z.infer<typeof BlockerModeSchema>;
450
+
451
+ export const BlockerKindSchema = z.enum(['task', 'condition', 'artifact']);
452
+ export type BlockerKind = z.infer<typeof BlockerKindSchema>;
453
+
454
+ export const BlockerRefSchema = z.object({
455
+ kind: BlockerKindSchema,
456
+ entityId: z.string(),
457
+ rawText: z.string().optional(),
458
+ confidence: z.number().min(0).max(1).optional(),
459
+ candidates: z.array(z.string()).optional()
460
+ });
461
+ export type BlockerRef = z.infer<typeof BlockerRefSchema>;
462
+
463
+ // Task event payloads
464
+ export const TaskCreatedPayloadSchema = z.object({
465
+ taskId: z.string(),
466
+ title: z.string(),
467
+ canonicalKey: z.string(),
468
+ initialStatus: TaskStatusSchema,
469
+ priority: TaskPrioritySchema.optional(),
470
+ description: z.string().optional(),
471
+ project: z.string().optional()
472
+ });
473
+ export type TaskCreatedPayload = z.infer<typeof TaskCreatedPayloadSchema>;
474
+
475
+ export const TaskStatusChangedPayloadSchema = z.object({
476
+ taskId: z.string(),
477
+ fromStatus: TaskStatusSchema,
478
+ toStatus: TaskStatusSchema,
479
+ reason: z.string().optional()
480
+ });
481
+ export type TaskStatusChangedPayload = z.infer<typeof TaskStatusChangedPayloadSchema>;
482
+
483
+ export const TaskBlockersSetPayloadSchema = z.object({
484
+ taskId: z.string(),
485
+ mode: BlockerModeSchema,
486
+ blockers: z.array(BlockerRefSchema),
487
+ sourceEntryId: z.string().optional()
488
+ });
489
+ export type TaskBlockersSetPayload = z.infer<typeof TaskBlockersSetPayloadSchema>;
490
+
491
+ // ============================================================
492
+ // Entry Types (Immutable memory units)
493
+ // ============================================================
494
+
495
+ export const EntryTypeSchema = z.enum([
496
+ 'fact',
497
+ 'decision',
498
+ 'insight',
499
+ 'task_note',
500
+ 'reference',
501
+ 'preference',
502
+ 'pattern'
503
+ ]);
504
+ export type EntryType = z.infer<typeof EntryTypeSchema>;
505
+
506
+ export const EntrySchema = z.object({
507
+ entryId: z.string(),
508
+ createdTs: z.date(),
509
+ entryType: EntryTypeSchema,
510
+ title: z.string(),
511
+ contentJson: z.record(z.unknown()),
512
+ stage: EntityStageSchema,
513
+ status: EntityStatusSchema,
514
+ supersededBy: z.string().optional(),
515
+ buildId: z.string().optional(),
516
+ evidenceJson: z.record(z.unknown()).optional(),
517
+ canonicalKey: z.string()
518
+ });
519
+ export type Entry = z.infer<typeof EntrySchema>;
520
+
521
+ // ============================================================
522
+ // Evidence Aligner V2 Types
523
+ // ============================================================
524
+
525
+ export const ExtractedEvidenceSchema = z.object({
526
+ messageIndex: z.number().int().nonnegative(),
527
+ quote: z.string()
528
+ });
529
+ export type ExtractedEvidence = z.infer<typeof ExtractedEvidenceSchema>;
530
+
531
+ export const AlignedEvidenceSchema = z.object({
532
+ messageIndex: z.number().int().nonnegative(),
533
+ quote: z.string(),
534
+ spanStart: z.number().int().nonnegative(),
535
+ spanEnd: z.number().int().positive(),
536
+ quoteHash: z.string(),
537
+ confidence: z.number().min(0).max(1),
538
+ matchMethod: z.enum(['exact', 'normalized', 'fuzzy'])
539
+ });
540
+ export type AlignedEvidence = z.infer<typeof AlignedEvidenceSchema>;
541
+
542
+ export const FailedEvidenceSchema = z.object({
543
+ messageIndex: z.number().int().nonnegative(),
544
+ quote: z.string(),
545
+ failureReason: z.enum(['not_found', 'below_threshold', 'ambiguous', 'empty_quote', 'invalid_index'])
546
+ });
547
+ export type FailedEvidence = z.infer<typeof FailedEvidenceSchema>;
548
+
549
+ export const EvidenceAlignResultSchema = z.discriminatedUnion('aligned', [
550
+ z.object({ aligned: z.literal(true), evidence: AlignedEvidenceSchema }),
551
+ z.object({ aligned: z.literal(false), evidence: FailedEvidenceSchema })
552
+ ]);
553
+ export type EvidenceAlignResult = z.infer<typeof EvidenceAlignResultSchema>;
554
+
555
+ // ============================================================
556
+ // Vector Outbox V2 Types
557
+ // ============================================================
558
+
559
+ export const OutboxStatusSchema = z.enum(['pending', 'processing', 'done', 'failed']);
560
+ export type OutboxStatus = z.infer<typeof OutboxStatusSchema>;
561
+
562
+ export const OutboxItemKindSchema = z.enum(['entry', 'task_title', 'event']);
563
+ export type OutboxItemKind = z.infer<typeof OutboxItemKindSchema>;
564
+
565
+ export const OutboxJobSchema = z.object({
566
+ jobId: z.string(),
567
+ itemKind: OutboxItemKindSchema,
568
+ itemId: z.string(),
569
+ embeddingVersion: z.string(),
570
+ status: OutboxStatusSchema,
571
+ retryCount: z.number().int().nonnegative(),
572
+ error: z.string().optional(),
573
+ createdAt: z.date(),
574
+ updatedAt: z.date()
575
+ });
576
+ export type OutboxJob = z.infer<typeof OutboxJobSchema>;
577
+
578
+ // Valid state transitions for outbox
579
+ export const VALID_OUTBOX_TRANSITIONS: Array<{ from: OutboxStatus; to: OutboxStatus }> = [
580
+ { from: 'pending', to: 'processing' },
581
+ { from: 'processing', to: 'done' },
582
+ { from: 'processing', to: 'failed' },
583
+ { from: 'failed', to: 'pending' }
584
+ ];
585
+
586
+ // ============================================================
587
+ // Build Runs (Pipeline metadata)
588
+ // ============================================================
589
+
590
+ export const BuildRunSchema = z.object({
591
+ buildId: z.string(),
592
+ startedAt: z.date(),
593
+ finishedAt: z.date().optional(),
594
+ extractorModel: z.string(),
595
+ extractorPromptHash: z.string(),
596
+ embedderModel: z.string(),
597
+ embeddingVersion: z.string(),
598
+ idrisVersion: z.string(),
599
+ schemaVersion: z.string(),
600
+ status: z.enum(['running', 'success', 'failed']),
601
+ error: z.string().optional()
602
+ });
603
+ export type BuildRun = z.infer<typeof BuildRunSchema>;
604
+
605
+ // ============================================================
606
+ // Pipeline Metrics
607
+ // ============================================================
608
+
609
+ export const PipelineMetricSchema = z.object({
610
+ id: z.string(),
611
+ ts: z.date(),
612
+ stage: z.string(),
613
+ latencyMs: z.number(),
614
+ success: z.boolean(),
615
+ error: z.string().optional(),
616
+ sessionId: z.string().optional()
617
+ });
618
+ export type PipelineMetric = z.infer<typeof PipelineMetricSchema>;
619
+
620
+ // ============================================================
621
+ // Progressive Disclosure Types
622
+ // ============================================================
623
+
624
+ // Layer 1: Search Index (lightweight)
625
+ export const SearchIndexItemSchema = z.object({
626
+ id: z.string(),
627
+ summary: z.string().max(100),
628
+ score: z.number(),
629
+ type: z.enum(['user_prompt', 'agent_response', 'session_summary', 'tool_observation']),
630
+ timestamp: z.date(),
631
+ sessionId: z.string()
632
+ });
633
+ export type SearchIndexItem = z.infer<typeof SearchIndexItemSchema>;
634
+
635
+ // Layer 2: Timeline
636
+ export const TimelineItemSchema = z.object({
637
+ id: z.string(),
638
+ timestamp: z.date(),
639
+ type: z.enum(['user_prompt', 'agent_response', 'session_summary', 'tool_observation']),
640
+ preview: z.string().max(200),
641
+ isTarget: z.boolean()
642
+ });
643
+ export type TimelineItem = z.infer<typeof TimelineItemSchema>;
644
+
645
+ // Layer 3: Full Detail
646
+ export const FullDetailSchema = z.object({
647
+ id: z.string(),
648
+ content: z.string(),
649
+ type: z.enum(['user_prompt', 'agent_response', 'session_summary', 'tool_observation']),
650
+ timestamp: z.date(),
651
+ sessionId: z.string(),
652
+ citationId: z.string().optional(),
653
+ metadata: z.object({
654
+ tokenCount: z.number(),
655
+ hasCode: z.boolean(),
656
+ files: z.array(z.string()).optional(),
657
+ tools: z.array(z.string()).optional()
658
+ })
659
+ });
660
+ export type FullDetail = z.infer<typeof FullDetailSchema>;
661
+
662
+ // Progressive Search Result
663
+ export const ProgressiveSearchResultSchema = z.object({
664
+ index: z.array(SearchIndexItemSchema),
665
+ timeline: z.array(TimelineItemSchema).optional(),
666
+ details: z.array(FullDetailSchema).optional(),
667
+ meta: z.object({
668
+ totalMatches: z.number(),
669
+ expandedCount: z.number(),
670
+ estimatedTokens: z.number(),
671
+ expansionReason: z.string().optional()
672
+ })
673
+ });
674
+ export type ProgressiveSearchResult = z.infer<typeof ProgressiveSearchResultSchema>;
675
+
676
+ // Progressive Disclosure Config
677
+ export const ProgressiveDisclosureConfigSchema = z.object({
678
+ enabled: z.boolean().default(true),
679
+ layer1: z.object({
680
+ topK: z.number().default(10),
681
+ minScore: z.number().default(0.7)
682
+ }).default({}),
683
+ autoExpand: z.object({
684
+ enabled: z.boolean().default(true),
685
+ highConfidenceThreshold: z.number().default(0.92),
686
+ scoreGapThreshold: z.number().default(0.1),
687
+ maxAutoExpandCount: z.number().default(3)
688
+ }).default({}),
689
+ tokenBudget: z.object({
690
+ maxTotalTokens: z.number().default(2000),
691
+ layer1PerItem: z.number().default(50),
692
+ layer2PerItem: z.number().default(40),
693
+ layer3PerItem: z.number().default(500)
694
+ }).default({})
695
+ });
696
+ export type ProgressiveDisclosureConfig = z.infer<typeof ProgressiveDisclosureConfigSchema>;
697
+
698
+ // ============================================================
699
+ // Citation Types
700
+ // ============================================================
701
+
702
+ export const CitationSchema = z.object({
703
+ citationId: z.string().length(6),
704
+ eventId: z.string(),
705
+ createdAt: z.date()
706
+ });
707
+ export type Citation = z.infer<typeof CitationSchema>;
708
+
709
+ export const CitationUsageSchema = z.object({
710
+ usageId: z.string(),
711
+ citationId: z.string(),
712
+ sessionId: z.string(),
713
+ usedAt: z.date(),
714
+ context: z.string().optional()
715
+ });
716
+ export type CitationUsage = z.infer<typeof CitationUsageSchema>;
717
+
718
+ export interface CitedSearchResult {
719
+ event: MemoryEvent;
720
+ citation: Citation;
721
+ score: number;
722
+ }
723
+
724
+ export interface CitationStats {
725
+ usageCount: number;
726
+ lastUsed: Date | null;
727
+ }
728
+
729
+ // ============================================================
730
+ // Endless Mode Types
731
+ // ============================================================
732
+
733
+ export const MemoryModeSchema = z.enum(['session', 'endless']);
734
+ export type MemoryMode = z.infer<typeof MemoryModeSchema>;
735
+
736
+ export const EndlessModeConfigSchema = z.object({
737
+ enabled: z.boolean().default(false),
738
+
739
+ workingSet: z.object({
740
+ maxEvents: z.number().default(100),
741
+ timeWindowHours: z.number().default(24),
742
+ minRelevanceScore: z.number().default(0.5)
743
+ }).default({}),
744
+
745
+ consolidation: z.object({
746
+ triggerIntervalMs: z.number().default(3600000), // 1 hour
747
+ triggerEventCount: z.number().default(100),
748
+ triggerIdleMs: z.number().default(1800000), // 30 minutes
749
+ useLLMSummarization: z.boolean().default(false)
750
+ }).default({}),
751
+
752
+ continuity: z.object({
753
+ minScoreForSeamless: z.number().default(0.7),
754
+ topicDecayHours: z.number().default(48)
755
+ }).default({})
756
+ });
757
+ export type EndlessModeConfig = z.infer<typeof EndlessModeConfigSchema>;
758
+
759
+ // Working Set Item
760
+ export const WorkingSetItemSchema = z.object({
761
+ id: z.string(),
762
+ eventId: z.string(),
763
+ addedAt: z.date(),
764
+ relevanceScore: z.number(),
765
+ topics: z.array(z.string()).optional(),
766
+ expiresAt: z.date()
767
+ });
768
+ export type WorkingSetItem = z.infer<typeof WorkingSetItemSchema>;
769
+
770
+ // Working Set
771
+ export interface WorkingSet {
772
+ recentEvents: MemoryEvent[];
773
+ lastActivity: Date;
774
+ continuityScore: number;
775
+ }
776
+
777
+ // Consolidated Memory
778
+ export const ConsolidatedMemorySchema = z.object({
779
+ memoryId: z.string(),
780
+ summary: z.string(),
781
+ topics: z.array(z.string()),
782
+ sourceEvents: z.array(z.string()),
783
+ confidence: z.number(),
784
+ createdAt: z.date(),
785
+ accessedAt: z.date().optional(),
786
+ accessCount: z.number().default(0)
787
+ });
788
+ export type ConsolidatedMemory = z.infer<typeof ConsolidatedMemorySchema>;
789
+
790
+ // Consolidated Memory Input (for creation)
791
+ export interface ConsolidatedMemoryInput {
792
+ summary: string;
793
+ topics: string[];
794
+ sourceEvents: string[];
795
+ confidence: number;
796
+ }
797
+
798
+ // Event Group (for consolidation)
799
+ export interface EventGroup {
800
+ topics: string[];
801
+ events: MemoryEvent[];
802
+ }
803
+
804
+ // Context Snapshot (for continuity calculation)
805
+ export interface ContextSnapshot {
806
+ id: string;
807
+ timestamp: number;
808
+ topics: string[];
809
+ files: string[];
810
+ entities: string[];
811
+ }
812
+
813
+ // Transition Type
814
+ export const TransitionTypeSchema = z.enum(['seamless', 'topic_shift', 'break']);
815
+ export type TransitionType = z.infer<typeof TransitionTypeSchema>;
816
+
817
+ // Continuity Score Result
818
+ export interface ContinuityScore {
819
+ score: number;
820
+ transitionType: TransitionType;
821
+ }
822
+
823
+ // Continuity Log
824
+ export const ContinuityLogSchema = z.object({
825
+ logId: z.string(),
826
+ fromContextId: z.string().optional(),
827
+ toContextId: z.string().optional(),
828
+ continuityScore: z.number(),
829
+ transitionType: TransitionTypeSchema,
830
+ createdAt: z.date()
831
+ });
832
+ export type ContinuityLog = z.infer<typeof ContinuityLogSchema>;
833
+
834
+ // Endless Mode Status
835
+ export interface EndlessModeStatus {
836
+ mode: MemoryMode;
837
+ workingSetSize: number;
838
+ continuityScore: number;
839
+ consolidatedCount: number;
840
+ lastConsolidation: Date | null;
841
+ }