@cleocode/core 2026.3.69 → 2026.3.70

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 (126) hide show
  1. package/dist/agents/retry.d.ts.map +1 -1
  2. package/dist/agents/retry.js +23 -42
  3. package/dist/agents/retry.js.map +1 -1
  4. package/dist/cleo.js +2 -2
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +30 -0
  7. package/dist/config.js.map +1 -1
  8. package/dist/hooks/handlers/file-hooks.d.ts +5 -2
  9. package/dist/hooks/handlers/file-hooks.d.ts.map +1 -1
  10. package/dist/hooks/handlers/index.d.ts +2 -0
  11. package/dist/hooks/handlers/index.d.ts.map +1 -1
  12. package/dist/hooks/handlers/mcp-hooks.d.ts +11 -7
  13. package/dist/hooks/handlers/mcp-hooks.d.ts.map +1 -1
  14. package/dist/hooks/handlers/memory-bridge-refresh.d.ts +20 -0
  15. package/dist/hooks/handlers/memory-bridge-refresh.d.ts.map +1 -0
  16. package/dist/hooks/handlers/memory-bridge-refresh.js +42 -0
  17. package/dist/hooks/handlers/memory-bridge-refresh.js.map +1 -0
  18. package/dist/hooks/handlers/session-hooks.d.ts +10 -0
  19. package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
  20. package/dist/hooks/handlers/session-hooks.js +36 -0
  21. package/dist/hooks/handlers/session-hooks.js.map +1 -1
  22. package/dist/hooks/handlers/task-hooks.d.ts +4 -0
  23. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  24. package/dist/hooks/handlers/task-hooks.js +7 -0
  25. package/dist/hooks/handlers/task-hooks.js.map +1 -1
  26. package/dist/hooks/handlers/work-capture-hooks.d.ts +40 -0
  27. package/dist/hooks/handlers/work-capture-hooks.d.ts.map +1 -0
  28. package/dist/index.d.ts +2 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +5016 -4662
  31. package/dist/index.js.map +4 -4
  32. package/dist/internal.d.ts +10 -2
  33. package/dist/internal.d.ts.map +1 -1
  34. package/dist/internal.js +10 -3
  35. package/dist/internal.js.map +1 -1
  36. package/dist/memory/auto-extract.d.ts +13 -0
  37. package/dist/memory/auto-extract.d.ts.map +1 -1
  38. package/dist/memory/auto-extract.js +34 -0
  39. package/dist/memory/auto-extract.js.map +1 -1
  40. package/dist/memory/brain-embedding.d.ts +13 -0
  41. package/dist/memory/brain-embedding.d.ts.map +1 -1
  42. package/dist/memory/brain-embedding.js +17 -0
  43. package/dist/memory/brain-embedding.js.map +1 -1
  44. package/dist/memory/brain-maintenance.d.ts +110 -0
  45. package/dist/memory/brain-maintenance.d.ts.map +1 -0
  46. package/dist/memory/brain-maintenance.js +98 -0
  47. package/dist/memory/brain-maintenance.js.map +1 -0
  48. package/dist/memory/brain-retrieval.d.ts +31 -5
  49. package/dist/memory/brain-retrieval.d.ts.map +1 -1
  50. package/dist/memory/brain-retrieval.js +53 -6
  51. package/dist/memory/brain-retrieval.js.map +1 -1
  52. package/dist/memory/embedding-local.d.ts +55 -0
  53. package/dist/memory/embedding-local.d.ts.map +1 -0
  54. package/dist/memory/embedding-local.js +97 -0
  55. package/dist/memory/embedding-local.js.map +1 -0
  56. package/dist/memory/embedding-queue.d.ts +90 -0
  57. package/dist/memory/embedding-queue.d.ts.map +1 -0
  58. package/dist/memory/embedding-queue.js +271 -0
  59. package/dist/memory/embedding-queue.js.map +1 -0
  60. package/dist/memory/embedding-worker.d.ts +19 -0
  61. package/dist/memory/embedding-worker.d.ts.map +1 -0
  62. package/dist/memory/embedding-worker.js +58 -0
  63. package/dist/memory/embedding-worker.js.map +1 -0
  64. package/dist/memory/memory-bridge.d.ts +21 -1
  65. package/dist/memory/memory-bridge.d.ts.map +1 -1
  66. package/dist/memory/memory-bridge.js +83 -2
  67. package/dist/memory/memory-bridge.js.map +1 -1
  68. package/dist/memory/session-memory.d.ts +26 -0
  69. package/dist/memory/session-memory.d.ts.map +1 -1
  70. package/dist/memory/session-memory.js +105 -0
  71. package/dist/memory/session-memory.js.map +1 -1
  72. package/dist/pagination.js +3 -0
  73. package/dist/pagination.js.map +1 -1
  74. package/dist/sessions/index.d.ts.map +1 -1
  75. package/dist/sessions/index.js +2 -6
  76. package/dist/sessions/index.js.map +1 -1
  77. package/dist/store/brain-sqlite.js +13 -62
  78. package/dist/store/brain-sqlite.js.map +1 -1
  79. package/dist/store/migration-manager.js +151 -0
  80. package/dist/store/migration-manager.js.map +1 -0
  81. package/dist/store/sqlite.d.ts.map +1 -1
  82. package/dist/store/sqlite.js +16 -134
  83. package/dist/store/sqlite.js.map +1 -1
  84. package/dist/tasks/add.js +27 -22
  85. package/dist/tasks/add.js.map +1 -1
  86. package/dist/tasks/complete.d.ts.map +1 -1
  87. package/dist/tasks/complete.js +13 -40
  88. package/dist/tasks/complete.js.map +1 -1
  89. package/dist/tasks/enforcement.js +12 -15
  90. package/dist/tasks/enforcement.js.map +1 -1
  91. package/dist/upgrade.js +246 -3
  92. package/dist/upgrade.js.map +1 -1
  93. package/migrations/drizzle-tasks/20260320013731_wave0-schema-hardening/migration.sql +17 -17
  94. package/package.json +6 -5
  95. package/src/agents/retry.ts +30 -24
  96. package/src/config.ts +18 -0
  97. package/src/hooks/handlers/file-hooks.ts +29 -3
  98. package/src/hooks/handlers/index.ts +2 -0
  99. package/src/hooks/handlers/mcp-hooks.ts +32 -13
  100. package/src/hooks/handlers/memory-bridge-refresh.ts +47 -0
  101. package/src/hooks/handlers/session-hooks.ts +38 -0
  102. package/src/hooks/handlers/task-hooks.ts +8 -0
  103. package/src/hooks/handlers/work-capture-hooks.ts +184 -0
  104. package/src/index.ts +5 -0
  105. package/src/internal.ts +28 -2
  106. package/src/memory/__tests__/brain-automation.test.ts +941 -0
  107. package/src/memory/auto-extract.ts +40 -0
  108. package/src/memory/brain-embedding.ts +18 -0
  109. package/src/memory/brain-maintenance.ts +183 -0
  110. package/src/memory/brain-retrieval.ts +85 -7
  111. package/src/memory/embedding-local.ts +107 -0
  112. package/src/memory/embedding-queue.ts +304 -0
  113. package/src/memory/embedding-worker.ts +79 -0
  114. package/src/memory/memory-bridge.ts +101 -2
  115. package/src/memory/session-memory.ts +123 -0
  116. package/src/sessions/index.ts +2 -6
  117. package/src/store/__tests__/test-db-helper.js +14 -2
  118. package/src/store/__tests__/test-db-helper.ts +4 -1
  119. package/src/store/sqlite.ts +28 -0
  120. package/src/tasks/__tests__/complete-unblocks.test.ts +4 -1
  121. package/src/tasks/__tests__/complete.test.ts +18 -6
  122. package/src/tasks/__tests__/epic-enforcement.test.ts +4 -1
  123. package/src/tasks/__tests__/update.test.ts +4 -1
  124. package/src/tasks/complete.ts +8 -8
  125. package/templates/config.template.json +19 -0
  126. package/templates/global-config.template.json +19 -0
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * MCP Prompt/Response Hook Handlers - Wave 2 of T5237
3
3
  *
4
- * Handlers for onPromptSubmit and onResponseComplete events.
5
- * By default, NO brain capture (too noisy). Brain observation is
6
- * opt-in via CLEO_BRAIN_CAPTURE_MCP=true environment variable.
4
+ * Handlers for onPromptSubmit and onResponseComplete events that capture
5
+ * ALL gateway operations (read and write) to BRAIN.
6
+ * By default, NO brain capture (too noisy). Enable via:
7
+ * - Config: brain.captureMcp = true (checked first)
8
+ * - Env: CLEO_BRAIN_CAPTURE_MCP=true (overrides config)
7
9
  * Auto-registers on module load.
8
10
  */
9
11
 
@@ -17,23 +19,39 @@ function isMissingBrainSchemaError(err: unknown): boolean {
17
19
  }
18
20
 
19
21
  /**
20
- * Check if brain capture is enabled for MCP events.
21
- * Defaults to false (too noisy for normal operation).
22
+ * Check whether MCP-level brain capture is enabled.
23
+ *
24
+ * Resolution order (first truthy wins):
25
+ * 1. CLEO_BRAIN_CAPTURE_MCP env var (explicit override)
26
+ * 2. brain.captureMcp project config value
27
+ *
28
+ * Defaults to false when neither is set (too noisy for normal operation).
22
29
  */
23
- function isBrainCaptureEnabled(): boolean {
24
- return process.env['CLEO_BRAIN_CAPTURE_MCP'] === 'true';
30
+ async function isBrainCaptureEnabled(projectRoot: string): Promise<boolean> {
31
+ const envOverride = process.env['CLEO_BRAIN_CAPTURE_MCP'];
32
+ if (envOverride !== undefined) {
33
+ return envOverride === 'true';
34
+ }
35
+ try {
36
+ const { loadConfig } = await import('../../config.js');
37
+ const config = await loadConfig(projectRoot);
38
+ return config.brain?.captureMcp ?? false;
39
+ } catch {
40
+ return false;
41
+ }
25
42
  }
26
43
 
27
44
  /**
28
- * Handle onPromptSubmit - optionally capture prompt events to BRAIN
45
+ * Handle onPromptSubmit - optionally capture ALL gateway prompt events to BRAIN.
29
46
  *
30
- * No-op by default. Set CLEO_BRAIN_CAPTURE_MCP=true to enable.
47
+ * No-op by default. Enable via brain.captureMcp config or CLEO_BRAIN_CAPTURE_MCP env.
48
+ * For selective mutation-only capture, use work-capture-hooks.ts instead.
31
49
  */
32
50
  export async function handlePromptSubmit(
33
51
  projectRoot: string,
34
52
  payload: OnPromptSubmitPayload,
35
53
  ): Promise<void> {
36
- if (!isBrainCaptureEnabled()) return;
54
+ if (!(await isBrainCaptureEnabled(projectRoot))) return;
37
55
 
38
56
  const { observeBrain } = await import('../../memory/brain-retrieval.js');
39
57
 
@@ -50,15 +68,16 @@ export async function handlePromptSubmit(
50
68
  }
51
69
 
52
70
  /**
53
- * Handle onResponseComplete - optionally capture response events to BRAIN
71
+ * Handle onResponseComplete - optionally capture ALL gateway response events to BRAIN.
54
72
  *
55
- * No-op by default. Set CLEO_BRAIN_CAPTURE_MCP=true to enable.
73
+ * No-op by default. Enable via brain.captureMcp config or CLEO_BRAIN_CAPTURE_MCP env.
74
+ * For selective mutation-only capture, use work-capture-hooks.ts instead.
56
75
  */
57
76
  export async function handleResponseComplete(
58
77
  projectRoot: string,
59
78
  payload: OnResponseCompletePayload,
60
79
  ): Promise<void> {
61
- if (!isBrainCaptureEnabled()) return;
80
+ if (!(await isBrainCaptureEnabled(projectRoot))) return;
62
81
 
63
82
  const { observeBrain } = await import('../../memory/brain-retrieval.js');
64
83
 
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Shared memory bridge refresh helper for hook handlers.
3
+ *
4
+ * Provides a config-gated, debounced wrapper around refreshMemoryBridge().
5
+ * Prevents rapid regeneration of .cleo/memory-bridge.md when multiple
6
+ * lifecycle events fire in quick succession (e.g. session end + task complete).
7
+ *
8
+ * Debounce: max one refresh per 30 seconds across all callers in the process.
9
+ *
10
+ * @task T138
11
+ * @epic T134
12
+ */
13
+
14
+ /** Debounce window in milliseconds. */
15
+ const DEBOUNCE_MS = 30_000;
16
+
17
+ /** Timestamp of the last successful refresh call (module-level singleton). */
18
+ let lastRefreshTime = 0;
19
+
20
+ /**
21
+ * Refresh the memory bridge if autoRefresh is enabled and the debounce window
22
+ * has elapsed. Reads config via loadConfig() (cascaded). Never throws.
23
+ *
24
+ * @param projectRoot - Absolute path to the project root directory.
25
+ */
26
+ export async function maybeRefreshMemoryBridge(projectRoot: string): Promise<void> {
27
+ try {
28
+ const { loadConfig } = await import('../../config.js');
29
+ const config = await loadConfig(projectRoot);
30
+
31
+ if (!config.brain?.memoryBridge?.autoRefresh) {
32
+ return;
33
+ }
34
+
35
+ const now = Date.now();
36
+ if (now - lastRefreshTime < DEBOUNCE_MS) {
37
+ return;
38
+ }
39
+
40
+ lastRefreshTime = now;
41
+
42
+ const { refreshMemoryBridge } = await import('../../memory/memory-bridge.js');
43
+ await refreshMemoryBridge(projectRoot);
44
+ } catch {
45
+ // Best-effort: never block lifecycle events
46
+ }
47
+ }
@@ -3,10 +3,15 @@
3
3
  *
4
4
  * Handlers that capture session lifecycle events to BRAIN via memory.observe.
5
5
  * Auto-registers on module load.
6
+ *
7
+ * T138: Triggers memory bridge refresh on session start and end.
8
+ * T139: Regenerates bridge with session scope on start.
9
+ * T144: Extracts transcript observations on session end.
6
10
  */
7
11
 
8
12
  import { hooks } from '../registry.js';
9
13
  import type { OnSessionEndPayload, OnSessionStartPayload } from '../types.js';
14
+ import { maybeRefreshMemoryBridge } from './memory-bridge-refresh.js';
10
15
 
11
16
  function isMissingBrainSchemaError(err: unknown): boolean {
12
17
  if (!(err instanceof Error)) return false;
@@ -16,6 +21,9 @@ function isMissingBrainSchemaError(err: unknown): boolean {
16
21
 
17
22
  /**
18
23
  * Handle onSessionStart - capture initial session context
24
+ *
25
+ * T138: Refresh memory bridge on session start.
26
+ * T139: Regenerate bridge with session scope context.
19
27
  */
20
28
  export async function handleSessionStart(
21
29
  projectRoot: string,
@@ -34,10 +42,16 @@ export async function handleSessionStart(
34
42
  } catch (err) {
35
43
  if (!isMissingBrainSchemaError(err)) throw err;
36
44
  }
45
+
46
+ // T138/T139: Refresh memory bridge after session starts (best-effort)
47
+ await maybeRefreshMemoryBridge(projectRoot);
37
48
  }
38
49
 
39
50
  /**
40
51
  * Handle onSessionEnd - capture session summary
52
+ *
53
+ * T138: Refresh memory bridge after session ends.
54
+ * T144: Extract transcript observations via cross-provider adapter.
41
55
  */
42
56
  export async function handleSessionEnd(
43
57
  projectRoot: string,
@@ -64,6 +78,30 @@ export async function handleSessionEnd(
64
78
  } catch {
65
79
  // Grading must never block session end
66
80
  }
81
+
82
+ // T144: Cross-provider transcript extraction (best-effort)
83
+ try {
84
+ const { loadConfig } = await import('../../config.js');
85
+ const config = await loadConfig(projectRoot);
86
+ if (config.brain?.autoCapture) {
87
+ const { AdapterManager } = await import('../../adapters/index.js');
88
+ const manager = AdapterManager.getInstance(projectRoot);
89
+ const activeAdapter = manager.getActive();
90
+ const hookProvider = activeAdapter?.hooks;
91
+ if (hookProvider && typeof hookProvider.getTranscript === 'function') {
92
+ const transcript = await hookProvider.getTranscript(payload.sessionId, projectRoot);
93
+ if (transcript) {
94
+ const { extractFromTranscript } = await import('../../memory/auto-extract.js');
95
+ await extractFromTranscript(projectRoot, payload.sessionId, transcript);
96
+ }
97
+ }
98
+ }
99
+ } catch {
100
+ // Graceful no-op: transcript extraction must never block session end
101
+ }
102
+
103
+ // T138: Refresh memory bridge after session ends (best-effort)
104
+ await maybeRefreshMemoryBridge(projectRoot);
67
105
  }
68
106
 
69
107
  // Register handlers on module load
@@ -3,10 +3,13 @@
3
3
  *
4
4
  * Handlers that capture task lifecycle events to BRAIN via memory.observe.
5
5
  * Auto-registers on module load.
6
+ *
7
+ * T138: Triggers memory bridge refresh after task completion.
6
8
  */
7
9
 
8
10
  import { hooks } from '../registry.js';
9
11
  import type { OnToolCompletePayload, OnToolStartPayload } from '../types.js';
12
+ import { maybeRefreshMemoryBridge } from './memory-bridge-refresh.js';
10
13
 
11
14
  function isMissingBrainSchemaError(err: unknown): boolean {
12
15
  if (!(err instanceof Error)) return false;
@@ -37,6 +40,8 @@ export async function handleToolStart(
37
40
 
38
41
  /**
39
42
  * Handle onToolComplete (maps to task.complete in CLEO)
43
+ *
44
+ * T138: Refresh memory bridge after task completion.
40
45
  */
41
46
  export async function handleToolComplete(
42
47
  projectRoot: string,
@@ -54,6 +59,9 @@ export async function handleToolComplete(
54
59
  } catch (err) {
55
60
  if (!isMissingBrainSchemaError(err)) throw err;
56
61
  }
62
+
63
+ // T138: Refresh memory bridge after task completes (best-effort)
64
+ await maybeRefreshMemoryBridge(projectRoot);
57
65
  }
58
66
 
59
67
  // Register handlers
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Active-Work Capture Hook Handlers
3
+ *
4
+ * Captures dispatch mutation events to BRAIN during active work, closing
5
+ * the gap between lifecycle-only capture (session end, task complete) and
6
+ * continuous capture. Only WRITE operations that represent meaningful work
7
+ * are captured — reads and operations already handled by lifecycle hooks
8
+ * are skipped to avoid flooding brain.db.
9
+ *
10
+ * Disabled by default. Enable via:
11
+ * - Config: brain.captureWork = true (checked first)
12
+ * - Env: CLEO_BRAIN_CAPTURE_WORK=true (overrides config)
13
+ *
14
+ * Auto-registers on module load.
15
+ *
16
+ * @task T142
17
+ */
18
+
19
+ import { hooks } from '../registry.js';
20
+ import type { OnPromptSubmitPayload, OnResponseCompletePayload } from '../types.js';
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Shared helpers
24
+ // ---------------------------------------------------------------------------
25
+
26
+ function isMissingBrainSchemaError(err: unknown): boolean {
27
+ if (!(err instanceof Error)) return false;
28
+ const message = String(err.message || '').toLowerCase();
29
+ return message.includes('no such table') && message.includes('brain_');
30
+ }
31
+
32
+ /**
33
+ * Check whether active-work capture is enabled.
34
+ *
35
+ * Resolution order (first truthy wins):
36
+ * 1. CLEO_BRAIN_CAPTURE_WORK env var (explicit override)
37
+ * 2. brain.captureWork project config value
38
+ *
39
+ * Defaults to false when neither is set.
40
+ */
41
+ async function isWorkCaptureEnabled(projectRoot: string): Promise<boolean> {
42
+ const envOverride = process.env['CLEO_BRAIN_CAPTURE_WORK'];
43
+ if (envOverride !== undefined) {
44
+ return envOverride === 'true';
45
+ }
46
+ try {
47
+ const { loadConfig } = await import('../../config.js');
48
+ const config = await loadConfig(projectRoot);
49
+ return config.brain?.captureWork ?? false;
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Smart-filter: which mutations to capture
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /**
60
+ * Mutations that represent novel work not already captured by lifecycle hooks.
61
+ *
62
+ * Excluded (already captured elsewhere):
63
+ * - tasks.complete → task-hooks.ts (onToolComplete)
64
+ * - session.start → session-hooks.ts (onSessionStart)
65
+ * - session.end → session-hooks.ts (onSessionEnd)
66
+ * - memory.brain.observe → observeBrain itself writes to brain; self-loop
67
+ *
68
+ * All query gateway operations are excluded by the gateway check before
69
+ * this set is consulted.
70
+ */
71
+ const CAPTURE_OPERATIONS = new Set<string>([
72
+ 'tasks.add',
73
+ 'tasks.update',
74
+ 'tasks.move',
75
+ 'tasks.link',
76
+ 'tasks.unlink',
77
+ 'tasks.label',
78
+ 'tasks.unlabel',
79
+ 'tasks.note',
80
+ ]);
81
+
82
+ /**
83
+ * Determine whether a mutate operation should be captured.
84
+ *
85
+ * Only `mutate` gateway operations in CAPTURE_OPERATIONS are captured.
86
+ * All `query` gateway calls are skipped (reads produce no novel work).
87
+ *
88
+ * @param gateway - 'query' or 'mutate'
89
+ * @param domain - e.g. 'tasks'
90
+ * @param operation - e.g. 'add'
91
+ */
92
+ function shouldCapture(gateway: string, domain: string, operation: string): boolean {
93
+ if (gateway !== 'mutate') return false;
94
+ const key = `${domain}.${operation}`;
95
+ return CAPTURE_OPERATIONS.has(key);
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Handlers
100
+ // ---------------------------------------------------------------------------
101
+
102
+ /**
103
+ * Handle onPromptSubmit — log incoming mutation intents to BRAIN.
104
+ *
105
+ * Only fires for mutate operations in CAPTURE_OPERATIONS.
106
+ * Gated behind brain.captureWork config (or CLEO_BRAIN_CAPTURE_WORK env).
107
+ *
108
+ * @param projectRoot - Absolute path to the project root
109
+ * @param payload - onPromptSubmit event payload
110
+ */
111
+ export async function handleWorkPromptSubmit(
112
+ projectRoot: string,
113
+ payload: OnPromptSubmitPayload,
114
+ ): Promise<void> {
115
+ if (!shouldCapture(payload.gateway, payload.domain, payload.operation)) return;
116
+ if (!(await isWorkCaptureEnabled(projectRoot))) return;
117
+
118
+ const { observeBrain } = await import('../../memory/brain-retrieval.js');
119
+
120
+ try {
121
+ await observeBrain(projectRoot, {
122
+ text: `Dispatch intent: ${payload.gateway}:${payload.domain}.${payload.operation}${payload.source ? ` (from ${payload.source})` : ''}`,
123
+ title: `Work intent: ${payload.domain}.${payload.operation}`,
124
+ type: 'discovery',
125
+ sourceType: 'agent',
126
+ });
127
+ } catch (err) {
128
+ if (!isMissingBrainSchemaError(err)) throw err;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Handle onResponseComplete — capture completed mutations to BRAIN.
134
+ *
135
+ * Only fires for successful mutate operations in CAPTURE_OPERATIONS.
136
+ * Failures are skipped — the intent was already captured by handleWorkPromptSubmit.
137
+ * Gated behind brain.captureWork config (or CLEO_BRAIN_CAPTURE_WORK env).
138
+ *
139
+ * @param projectRoot - Absolute path to the project root
140
+ * @param payload - onResponseComplete event payload
141
+ */
142
+ export async function handleWorkResponseComplete(
143
+ projectRoot: string,
144
+ payload: OnResponseCompletePayload,
145
+ ): Promise<void> {
146
+ if (!shouldCapture(payload.gateway, payload.domain, payload.operation)) return;
147
+ // Only capture successful completions — failures are noise
148
+ if (!payload.success) return;
149
+ if (!(await isWorkCaptureEnabled(projectRoot))) return;
150
+
151
+ const { observeBrain } = await import('../../memory/brain-retrieval.js');
152
+
153
+ try {
154
+ const durationNote = payload.durationMs != null ? ` (${payload.durationMs}ms)` : '';
155
+ await observeBrain(projectRoot, {
156
+ text: `Dispatch complete: ${payload.gateway}:${payload.domain}.${payload.operation}${durationNote}`,
157
+ title: `Work done: ${payload.domain}.${payload.operation}`,
158
+ type: 'change',
159
+ sourceType: 'agent',
160
+ });
161
+ } catch (err) {
162
+ if (!isMissingBrainSchemaError(err)) throw err;
163
+ }
164
+ }
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // Auto-registration
168
+ // ---------------------------------------------------------------------------
169
+
170
+ // Register at lower priority (90) than lifecycle hooks (100) so lifecycle
171
+ // handlers always run first.
172
+ hooks.register({
173
+ id: 'work-capture-prompt-submit',
174
+ event: 'onPromptSubmit',
175
+ handler: handleWorkPromptSubmit,
176
+ priority: 90,
177
+ });
178
+
179
+ hooks.register({
180
+ id: 'work-capture-response-complete',
181
+ event: 'onResponseComplete',
182
+ handler: handleWorkResponseComplete,
183
+ priority: 90,
184
+ });
package/src/index.ts CHANGED
@@ -268,10 +268,15 @@ export type {
268
268
  export { Cleo } from './cleo.js';
269
269
  // Hooks
270
270
  export { HookRegistry, hooks } from './hooks/registry.js';
271
+ export type {
272
+ PopulateEmbeddingsOptions,
273
+ PopulateEmbeddingsResult,
274
+ } from './memory/brain-retrieval.js';
271
275
  // Memory
272
276
  export {
273
277
  fetchBrainEntries,
274
278
  observeBrain,
279
+ populateEmbeddings,
275
280
  searchBrainCompact,
276
281
  timelineBrain,
277
282
  } from './memory/brain-retrieval.js';
package/src/internal.ts CHANGED
@@ -135,6 +135,23 @@ export { instantiateTessera, showTessera } from './lifecycle/tessera-engine.js';
135
135
 
136
136
  // MCP helpers
137
137
  export { detectEnvMode, generateMcpServerEntry, getMcpServerName } from './mcp/index.js';
138
+ // Memory — brain lifecycle (temporal decay + consolidation)
139
+ export type { ConsolidationResult, DecayResult } from './memory/brain-lifecycle.js';
140
+ export { applyTemporalDecay, consolidateMemories } from './memory/brain-lifecycle.js';
141
+ // Memory — brain maintenance
142
+ export type {
143
+ BrainMaintenanceConsolidationResult,
144
+ BrainMaintenanceDecayResult,
145
+ BrainMaintenanceEmbeddingsResult,
146
+ BrainMaintenanceOptions,
147
+ BrainMaintenanceResult,
148
+ } from './memory/brain-maintenance.js';
149
+ export { runBrainMaintenance } from './memory/brain-maintenance.js';
150
+ export type {
151
+ PopulateEmbeddingsOptions,
152
+ PopulateEmbeddingsResult,
153
+ } from './memory/brain-retrieval.js';
154
+ export { populateEmbeddings } from './memory/brain-retrieval.js';
138
155
  export { migrateClaudeMem } from './memory/claude-mem-migration.js';
139
156
  // Memory — engine-compat
140
157
  export {
@@ -686,6 +703,10 @@ export type { BuildConfig } from './config/build-config.js';
686
703
  export { BUILD_CONFIG } from './config/build-config.js';
687
704
  // Init (additional)
688
705
  export { initCoreSkills } from './init.js';
706
+ // Memory — auto-extract (additional)
707
+ export { extractFromTranscript } from './memory/auto-extract.js';
708
+ // Memory — brain embedding (additional)
709
+ export { initDefaultProvider } from './memory/brain-embedding.js';
689
710
  // Memory — brain row types
690
711
  export type {
691
712
  BrainAnchor,
@@ -699,9 +720,14 @@ export type {
699
720
  BrainTimelineNeighborRow,
700
721
  } from './memory/brain-row-types.js';
701
722
  // Memory (additional)
702
- export { writeMemoryBridge } from './memory/memory-bridge.js';
723
+ export { generateContextAwareContent, writeMemoryBridge } from './memory/memory-bridge.js';
703
724
  export type { SessionMemoryContext } from './memory/session-memory.js';
704
- export { getSessionMemoryContext, persistSessionMemory } from './memory/session-memory.js';
725
+ export {
726
+ buildSummarizationPrompt,
727
+ getSessionMemoryContext,
728
+ ingestStructuredSummary,
729
+ persistSessionMemory,
730
+ } from './memory/session-memory.js';
705
731
  // Nexus — discoverRelated (exported as nexusDiscoverRelated to avoid name clash with tasks discoverRelated)
706
732
  // Nexus — searchAcrossProjects
707
733
  export {