@soleri/core 2.0.2 → 2.4.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 (226) hide show
  1. package/dist/brain/brain.d.ts +14 -50
  2. package/dist/brain/brain.d.ts.map +1 -1
  3. package/dist/brain/brain.js +207 -16
  4. package/dist/brain/brain.js.map +1 -1
  5. package/dist/brain/intelligence.d.ts +86 -0
  6. package/dist/brain/intelligence.d.ts.map +1 -0
  7. package/dist/brain/intelligence.js +771 -0
  8. package/dist/brain/intelligence.js.map +1 -0
  9. package/dist/brain/types.d.ts +197 -0
  10. package/dist/brain/types.d.ts.map +1 -0
  11. package/dist/brain/types.js +2 -0
  12. package/dist/brain/types.js.map +1 -0
  13. package/dist/cognee/client.d.ts +35 -0
  14. package/dist/cognee/client.d.ts.map +1 -0
  15. package/dist/cognee/client.js +291 -0
  16. package/dist/cognee/client.js.map +1 -0
  17. package/dist/cognee/types.d.ts +46 -0
  18. package/dist/cognee/types.d.ts.map +1 -0
  19. package/dist/cognee/types.js +3 -0
  20. package/dist/cognee/types.js.map +1 -0
  21. package/dist/control/identity-manager.d.ts +22 -0
  22. package/dist/control/identity-manager.d.ts.map +1 -0
  23. package/dist/control/identity-manager.js +233 -0
  24. package/dist/control/identity-manager.js.map +1 -0
  25. package/dist/control/intent-router.d.ts +32 -0
  26. package/dist/control/intent-router.d.ts.map +1 -0
  27. package/dist/control/intent-router.js +242 -0
  28. package/dist/control/intent-router.js.map +1 -0
  29. package/dist/control/types.d.ts +68 -0
  30. package/dist/control/types.d.ts.map +1 -0
  31. package/dist/control/types.js +9 -0
  32. package/dist/control/types.js.map +1 -0
  33. package/dist/curator/curator.d.ts +29 -0
  34. package/dist/curator/curator.d.ts.map +1 -1
  35. package/dist/curator/curator.js +142 -5
  36. package/dist/curator/curator.js.map +1 -1
  37. package/dist/facades/types.d.ts +1 -1
  38. package/dist/governance/governance.d.ts +42 -0
  39. package/dist/governance/governance.d.ts.map +1 -0
  40. package/dist/governance/governance.js +488 -0
  41. package/dist/governance/governance.js.map +1 -0
  42. package/dist/governance/index.d.ts +3 -0
  43. package/dist/governance/index.d.ts.map +1 -0
  44. package/dist/governance/index.js +2 -0
  45. package/dist/governance/index.js.map +1 -0
  46. package/dist/governance/types.d.ts +102 -0
  47. package/dist/governance/types.d.ts.map +1 -0
  48. package/dist/governance/types.js +3 -0
  49. package/dist/governance/types.js.map +1 -0
  50. package/dist/index.d.ts +35 -3
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +32 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/llm/llm-client.d.ts.map +1 -1
  55. package/dist/llm/llm-client.js +9 -2
  56. package/dist/llm/llm-client.js.map +1 -1
  57. package/dist/logging/logger.d.ts +37 -0
  58. package/dist/logging/logger.d.ts.map +1 -0
  59. package/dist/logging/logger.js +145 -0
  60. package/dist/logging/logger.js.map +1 -0
  61. package/dist/logging/types.d.ts +19 -0
  62. package/dist/logging/types.d.ts.map +1 -0
  63. package/dist/logging/types.js +2 -0
  64. package/dist/logging/types.js.map +1 -0
  65. package/dist/loop/loop-manager.d.ts +49 -0
  66. package/dist/loop/loop-manager.d.ts.map +1 -0
  67. package/dist/loop/loop-manager.js +105 -0
  68. package/dist/loop/loop-manager.js.map +1 -0
  69. package/dist/loop/types.d.ts +35 -0
  70. package/dist/loop/types.d.ts.map +1 -0
  71. package/dist/loop/types.js +8 -0
  72. package/dist/loop/types.js.map +1 -0
  73. package/dist/planning/gap-analysis.d.ts +29 -0
  74. package/dist/planning/gap-analysis.d.ts.map +1 -0
  75. package/dist/planning/gap-analysis.js +265 -0
  76. package/dist/planning/gap-analysis.js.map +1 -0
  77. package/dist/planning/gap-types.d.ts +29 -0
  78. package/dist/planning/gap-types.d.ts.map +1 -0
  79. package/dist/planning/gap-types.js +28 -0
  80. package/dist/planning/gap-types.js.map +1 -0
  81. package/dist/planning/planner.d.ts +150 -1
  82. package/dist/planning/planner.d.ts.map +1 -1
  83. package/dist/planning/planner.js +365 -2
  84. package/dist/planning/planner.js.map +1 -1
  85. package/dist/project/project-registry.d.ts +79 -0
  86. package/dist/project/project-registry.d.ts.map +1 -0
  87. package/dist/project/project-registry.js +276 -0
  88. package/dist/project/project-registry.js.map +1 -0
  89. package/dist/project/types.d.ts +28 -0
  90. package/dist/project/types.d.ts.map +1 -0
  91. package/dist/project/types.js +5 -0
  92. package/dist/project/types.js.map +1 -0
  93. package/dist/runtime/admin-extra-ops.d.ts +13 -0
  94. package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
  95. package/dist/runtime/admin-extra-ops.js +284 -0
  96. package/dist/runtime/admin-extra-ops.js.map +1 -0
  97. package/dist/runtime/admin-ops.d.ts +15 -0
  98. package/dist/runtime/admin-ops.d.ts.map +1 -0
  99. package/dist/runtime/admin-ops.js +322 -0
  100. package/dist/runtime/admin-ops.js.map +1 -0
  101. package/dist/runtime/capture-ops.d.ts +15 -0
  102. package/dist/runtime/capture-ops.d.ts.map +1 -0
  103. package/dist/runtime/capture-ops.js +345 -0
  104. package/dist/runtime/capture-ops.js.map +1 -0
  105. package/dist/runtime/core-ops.d.ts +7 -3
  106. package/dist/runtime/core-ops.d.ts.map +1 -1
  107. package/dist/runtime/core-ops.js +646 -15
  108. package/dist/runtime/core-ops.js.map +1 -1
  109. package/dist/runtime/curator-extra-ops.d.ts +9 -0
  110. package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
  111. package/dist/runtime/curator-extra-ops.js +59 -0
  112. package/dist/runtime/curator-extra-ops.js.map +1 -0
  113. package/dist/runtime/domain-ops.d.ts.map +1 -1
  114. package/dist/runtime/domain-ops.js +59 -13
  115. package/dist/runtime/domain-ops.js.map +1 -1
  116. package/dist/runtime/grading-ops.d.ts +14 -0
  117. package/dist/runtime/grading-ops.d.ts.map +1 -0
  118. package/dist/runtime/grading-ops.js +105 -0
  119. package/dist/runtime/grading-ops.js.map +1 -0
  120. package/dist/runtime/loop-ops.d.ts +13 -0
  121. package/dist/runtime/loop-ops.d.ts.map +1 -0
  122. package/dist/runtime/loop-ops.js +179 -0
  123. package/dist/runtime/loop-ops.js.map +1 -0
  124. package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
  125. package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
  126. package/dist/runtime/memory-cross-project-ops.js +165 -0
  127. package/dist/runtime/memory-cross-project-ops.js.map +1 -0
  128. package/dist/runtime/memory-extra-ops.d.ts +13 -0
  129. package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
  130. package/dist/runtime/memory-extra-ops.js +173 -0
  131. package/dist/runtime/memory-extra-ops.js.map +1 -0
  132. package/dist/runtime/orchestrate-ops.d.ts +17 -0
  133. package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
  134. package/dist/runtime/orchestrate-ops.js +240 -0
  135. package/dist/runtime/orchestrate-ops.js.map +1 -0
  136. package/dist/runtime/planning-extra-ops.d.ts +17 -0
  137. package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
  138. package/dist/runtime/planning-extra-ops.js +300 -0
  139. package/dist/runtime/planning-extra-ops.js.map +1 -0
  140. package/dist/runtime/project-ops.d.ts +15 -0
  141. package/dist/runtime/project-ops.d.ts.map +1 -0
  142. package/dist/runtime/project-ops.js +181 -0
  143. package/dist/runtime/project-ops.js.map +1 -0
  144. package/dist/runtime/runtime.d.ts.map +1 -1
  145. package/dist/runtime/runtime.js +48 -1
  146. package/dist/runtime/runtime.js.map +1 -1
  147. package/dist/runtime/types.d.ts +23 -0
  148. package/dist/runtime/types.d.ts.map +1 -1
  149. package/dist/runtime/vault-extra-ops.d.ts +9 -0
  150. package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
  151. package/dist/runtime/vault-extra-ops.js +195 -0
  152. package/dist/runtime/vault-extra-ops.js.map +1 -0
  153. package/dist/telemetry/telemetry.d.ts +48 -0
  154. package/dist/telemetry/telemetry.d.ts.map +1 -0
  155. package/dist/telemetry/telemetry.js +87 -0
  156. package/dist/telemetry/telemetry.js.map +1 -0
  157. package/dist/vault/vault.d.ts +94 -0
  158. package/dist/vault/vault.d.ts.map +1 -1
  159. package/dist/vault/vault.js +340 -1
  160. package/dist/vault/vault.js.map +1 -1
  161. package/package.json +1 -1
  162. package/src/__tests__/admin-extra-ops.test.ts +420 -0
  163. package/src/__tests__/admin-ops.test.ts +271 -0
  164. package/src/__tests__/brain-intelligence.test.ts +828 -0
  165. package/src/__tests__/brain.test.ts +396 -27
  166. package/src/__tests__/capture-ops.test.ts +509 -0
  167. package/src/__tests__/cognee-client.test.ts +524 -0
  168. package/src/__tests__/core-ops.test.ts +341 -49
  169. package/src/__tests__/curator-extra-ops.test.ts +359 -0
  170. package/src/__tests__/curator.test.ts +126 -31
  171. package/src/__tests__/domain-ops.test.ts +111 -9
  172. package/src/__tests__/governance.test.ts +522 -0
  173. package/src/__tests__/grading-ops.test.ts +340 -0
  174. package/src/__tests__/identity-manager.test.ts +243 -0
  175. package/src/__tests__/intent-router.test.ts +222 -0
  176. package/src/__tests__/logger.test.ts +200 -0
  177. package/src/__tests__/loop-ops.test.ts +398 -0
  178. package/src/__tests__/memory-cross-project-ops.test.ts +246 -0
  179. package/src/__tests__/memory-extra-ops.test.ts +352 -0
  180. package/src/__tests__/orchestrate-ops.test.ts +284 -0
  181. package/src/__tests__/planner.test.ts +331 -0
  182. package/src/__tests__/planning-extra-ops.test.ts +548 -0
  183. package/src/__tests__/project-ops.test.ts +367 -0
  184. package/src/__tests__/runtime.test.ts +13 -11
  185. package/src/__tests__/vault-extra-ops.test.ts +407 -0
  186. package/src/brain/brain.ts +308 -72
  187. package/src/brain/intelligence.ts +1230 -0
  188. package/src/brain/types.ts +214 -0
  189. package/src/cognee/client.ts +352 -0
  190. package/src/cognee/types.ts +62 -0
  191. package/src/control/identity-manager.ts +354 -0
  192. package/src/control/intent-router.ts +326 -0
  193. package/src/control/types.ts +102 -0
  194. package/src/curator/curator.ts +265 -15
  195. package/src/governance/governance.ts +698 -0
  196. package/src/governance/index.ts +18 -0
  197. package/src/governance/types.ts +111 -0
  198. package/src/index.ts +128 -3
  199. package/src/llm/llm-client.ts +18 -24
  200. package/src/logging/logger.ts +154 -0
  201. package/src/logging/types.ts +21 -0
  202. package/src/loop/loop-manager.ts +130 -0
  203. package/src/loop/types.ts +44 -0
  204. package/src/planning/gap-analysis.ts +506 -0
  205. package/src/planning/gap-types.ts +58 -0
  206. package/src/planning/planner.ts +478 -2
  207. package/src/project/project-registry.ts +358 -0
  208. package/src/project/types.ts +31 -0
  209. package/src/runtime/admin-extra-ops.ts +307 -0
  210. package/src/runtime/admin-ops.ts +329 -0
  211. package/src/runtime/capture-ops.ts +385 -0
  212. package/src/runtime/core-ops.ts +747 -26
  213. package/src/runtime/curator-extra-ops.ts +71 -0
  214. package/src/runtime/domain-ops.ts +65 -13
  215. package/src/runtime/grading-ops.ts +121 -0
  216. package/src/runtime/loop-ops.ts +194 -0
  217. package/src/runtime/memory-cross-project-ops.ts +192 -0
  218. package/src/runtime/memory-extra-ops.ts +186 -0
  219. package/src/runtime/orchestrate-ops.ts +272 -0
  220. package/src/runtime/planning-extra-ops.ts +327 -0
  221. package/src/runtime/project-ops.ts +196 -0
  222. package/src/runtime/runtime.ts +54 -1
  223. package/src/runtime/types.ts +23 -0
  224. package/src/runtime/vault-extra-ops.ts +225 -0
  225. package/src/telemetry/telemetry.ts +118 -0
  226. package/src/vault/vault.ts +412 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Generic core operations factory — 26 ops that every agent gets.
2
+ * Generic core operations factory — 147 ops that every agent gets.
3
3
  *
4
4
  * These ops are agent-agnostic (no persona, no activation).
5
5
  * The 5 agent-specific ops (health, identity, activate, inject_claude_md, setup)
@@ -10,21 +10,53 @@ import { z } from 'zod';
10
10
  import type { OpDefinition } from '../facades/types.js';
11
11
  import type { IntelligenceEntry } from '../intelligence/types.js';
12
12
  import type { AgentRuntime } from './types.js';
13
+ import type { GuidelineCategory, OperationalMode } from '../control/types.js';
14
+ import type { PolicyType, PolicyPreset } from '../governance/types.js';
15
+ import type { CogneeSearchType } from '../cognee/types.js';
16
+ import { createPlanningExtraOps } from './planning-extra-ops.js';
17
+ import { createMemoryExtraOps } from './memory-extra-ops.js';
18
+ import { createVaultExtraOps } from './vault-extra-ops.js';
19
+ import { createAdminOps } from './admin-ops.js';
20
+ import { createAdminExtraOps } from './admin-extra-ops.js';
21
+ import { createLoopOps } from './loop-ops.js';
22
+ import { createOrchestrateOps } from './orchestrate-ops.js';
23
+ import { createGradingOps } from './grading-ops.js';
24
+ import { createCaptureOps } from './capture-ops.js';
25
+ import { createCuratorExtraOps } from './curator-extra-ops.js';
26
+ import { createProjectOps } from './project-ops.js';
27
+ import { createMemoryCrossProjectOps } from './memory-cross-project-ops.js';
13
28
 
14
29
  /**
15
- * Create the 26 generic core operations for an agent runtime.
30
+ * Create the 147 generic core operations for an agent runtime.
16
31
  *
17
32
  * Groups: search/vault (4), memory (4), export (1), planning (5),
18
- * brain (4), curator (8).
33
+ * brain (7), brain intelligence (11), cognee (5),
34
+ * llm (2), curator (8), control (8), governance (5),
35
+ * planning-extra (9), memory-extra (8), vault-extra (12),
36
+ * admin (8), admin-extra (10), loop (7), orchestrate (5),
37
+ * grading (5), capture (4), curator-extra (4), project (12).
19
38
  */
20
39
  export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
21
- const { vault, brain, planner, curator, llmClient, keyPool } = runtime;
40
+ const {
41
+ vault,
42
+ brain,
43
+ brainIntelligence,
44
+ planner,
45
+ curator,
46
+ governance,
47
+ cognee,
48
+ identityManager,
49
+ intentRouter,
50
+ llmClient,
51
+ keyPool,
52
+ } = runtime;
22
53
 
23
54
  return [
24
55
  // ─── Search / Vault ──────────────────────────────────────────
25
56
  {
26
57
  name: 'search',
27
- description: 'Search across all knowledge domains. Results ranked by TF-IDF + severity + recency + tag overlap + domain match.',
58
+ description:
59
+ 'Search across all knowledge domains. Results ranked by TF-IDF + severity + recency + tag overlap + domain match.',
28
60
  auth: 'read',
29
61
  schema: z.object({
30
62
  query: z.string(),
@@ -75,7 +107,8 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
75
107
  },
76
108
  {
77
109
  name: 'register',
78
- description: 'Register a project for this session. Call on every new session to track usage and get context.',
110
+ description:
111
+ 'Register a project for this session. Call on every new session to track usage and get context.',
79
112
  auth: 'write',
80
113
  schema: z.object({
81
114
  projectPath: z.string().optional().default('.'),
@@ -85,9 +118,18 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
85
118
  const { resolve } = await import('node:path');
86
119
  const projectPath = resolve((params.projectPath as string) ?? '.');
87
120
  const project = vault.registerProject(projectPath, params.name as string | undefined);
121
+ // Also track in project registry for cross-project features
122
+ runtime.projectRegistry.register(projectPath, params.name as string | undefined);
88
123
  const stats = vault.stats();
89
124
  const isNew = project.sessionCount === 1;
90
125
 
126
+ // Expire stale proposals on session start (fire-and-forget)
127
+ const policy = governance.getPolicy(projectPath);
128
+ const expired = governance.expireStaleProposals(policy.autoCapture.autoExpireDays);
129
+
130
+ const proposalStats = governance.getProposalStats(projectPath);
131
+ const quotaStatus = governance.getQuotaStatus(projectPath);
132
+
91
133
  return {
92
134
  project,
93
135
  is_new: isNew,
@@ -95,6 +137,15 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
95
137
  ? 'Welcome! New project registered.'
96
138
  : 'Welcome back! Session #' + project.sessionCount + ' for ' + project.name + '.',
97
139
  vault: { entries: stats.totalEntries, domains: Object.keys(stats.byDomain) },
140
+ governance: {
141
+ pendingProposals: proposalStats.pending,
142
+ quotaPercent:
143
+ quotaStatus.maxTotal > 0
144
+ ? Math.round((quotaStatus.total / quotaStatus.maxTotal) * 100)
145
+ : 0,
146
+ isQuotaWarning: quotaStatus.isWarning,
147
+ expiredThisSession: expired,
148
+ },
98
149
  };
99
150
  },
100
151
  },
@@ -167,7 +218,8 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
167
218
  },
168
219
  {
169
220
  name: 'session_capture',
170
- description: 'Capture a session summary before context compaction. Called automatically by PreCompact hook.',
221
+ description:
222
+ 'Capture a session summary before context compaction. Called automatically by PreCompact hook.',
171
223
  auth: 'write',
172
224
  schema: z.object({
173
225
  projectPath: z.string().optional().default('.'),
@@ -195,17 +247,17 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
195
247
  // ─── Export ───────────────────────────────────────────────────
196
248
  {
197
249
  name: 'export',
198
- description: 'Export vault entries as JSON intelligence bundles — one per domain. Enables version control and sharing.',
250
+ description:
251
+ 'Export vault entries as JSON intelligence bundles — one per domain. Enables version control and sharing.',
199
252
  auth: 'read',
200
253
  schema: z.object({
201
254
  domain: z.string().optional().describe('Export only this domain. Omit to export all.'),
202
255
  }),
203
256
  handler: async (params) => {
204
257
  const stats = vault.stats();
205
- const domains = params.domain
206
- ? [params.domain as string]
207
- : Object.keys(stats.byDomain);
208
- const bundles: Array<{ domain: string; version: string; entries: IntelligenceEntry[] }> = [];
258
+ const domains = params.domain ? [params.domain as string] : Object.keys(stats.byDomain);
259
+ const bundles: Array<{ domain: string; version: string; entries: IntelligenceEntry[] }> =
260
+ [];
209
261
  for (const d of domains) {
210
262
  const entries = vault.list({ domain: d, limit: 10000 });
211
263
  bundles.push({ domain: d, version: '1.0.0', entries });
@@ -222,13 +274,17 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
222
274
  // ─── Planning ────────────────────────────────────────────────
223
275
  {
224
276
  name: 'create_plan',
225
- description: 'Create a new plan in draft status. Plans track multi-step tasks with decisions and sub-tasks.',
277
+ description:
278
+ 'Create a new plan in draft status. Plans track multi-step tasks with decisions and sub-tasks.',
226
279
  auth: 'write',
227
280
  schema: z.object({
228
281
  objective: z.string().describe('What the plan aims to achieve'),
229
282
  scope: z.string().describe('Which parts of the codebase are affected'),
230
283
  decisions: z.array(z.string()).optional().default([]),
231
- tasks: z.array(z.object({ title: z.string(), description: z.string() })).optional().default([]),
284
+ tasks: z
285
+ .array(z.object({ title: z.string(), description: z.string() }))
286
+ .optional()
287
+ .default([]),
232
288
  }),
233
289
  handler: async (params) => {
234
290
  const plan = planner.create({
@@ -262,7 +318,11 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
262
318
  auth: 'write',
263
319
  schema: z.object({
264
320
  planId: z.string(),
265
- startExecution: z.boolean().optional().default(false).describe('If true, immediately start execution after approval'),
321
+ startExecution: z
322
+ .boolean()
323
+ .optional()
324
+ .default(false)
325
+ .describe('If true, immediately start execution after approval'),
266
326
  }),
267
327
  handler: async (params) => {
268
328
  let plan = planner.approve(params.planId as string);
@@ -313,7 +373,8 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
313
373
  // ─── Brain ───────────────────────────────────────────────────
314
374
  {
315
375
  name: 'record_feedback',
316
- description: 'Record feedback on a search result — accepted or dismissed. Used for adaptive weight tuning.',
376
+ description:
377
+ 'Record feedback on a search result — accepted or dismissed. Used for adaptive weight tuning.',
317
378
  auth: 'write',
318
379
  schema: z.object({
319
380
  query: z.string().describe('The original search query'),
@@ -326,7 +387,58 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
326
387
  params.entryId as string,
327
388
  params.action as 'accepted' | 'dismissed',
328
389
  );
329
- return { recorded: true, query: params.query, entryId: params.entryId, action: params.action };
390
+ return {
391
+ recorded: true,
392
+ query: params.query,
393
+ entryId: params.entryId,
394
+ action: params.action,
395
+ };
396
+ },
397
+ },
398
+ {
399
+ name: 'brain_feedback',
400
+ description:
401
+ 'Enhanced feedback with typed actions (accepted/dismissed/modified/failed), source tracking, confidence, duration, and reason.',
402
+ auth: 'write',
403
+ schema: z.object({
404
+ query: z.string().describe('The original search query'),
405
+ entryId: z.string().describe('The entry ID'),
406
+ action: z.enum(['accepted', 'dismissed', 'modified', 'failed']),
407
+ source: z
408
+ .enum(['search', 'recommendation', 'tool-execution', 'explicit'])
409
+ .optional()
410
+ .describe("Feedback source. Default 'search'."),
411
+ confidence: z.number().optional().describe('Confidence 0-1. Default 0.6.'),
412
+ duration: z.number().optional().describe('Duration in ms.'),
413
+ context: z.string().optional().describe("JSON context string. Default '{}'."),
414
+ reason: z.string().optional().describe('Human-readable reason.'),
415
+ }),
416
+ handler: async (params) => {
417
+ const entry = brain.recordFeedback({
418
+ query: params.query as string,
419
+ entryId: params.entryId as string,
420
+ action: params.action as 'accepted' | 'dismissed' | 'modified' | 'failed',
421
+ source: params.source as
422
+ | 'search'
423
+ | 'recommendation'
424
+ | 'tool-execution'
425
+ | 'explicit'
426
+ | undefined,
427
+ confidence: params.confidence as number | undefined,
428
+ duration: params.duration as number | undefined,
429
+ context: params.context as string | undefined,
430
+ reason: params.reason as string | undefined,
431
+ });
432
+ return entry;
433
+ },
434
+ },
435
+ {
436
+ name: 'brain_feedback_stats',
437
+ description:
438
+ 'Feedback statistics — counts by action and source, acceptance rate, average confidence.',
439
+ auth: 'read',
440
+ handler: async () => {
441
+ return brain.getFeedbackStats();
330
442
  },
331
443
  },
332
444
  {
@@ -340,15 +452,19 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
340
452
  },
341
453
  {
342
454
  name: 'brain_stats',
343
- description: 'Get brain intelligence stats — vocabulary size, feedback count, current scoring weights.',
455
+ description:
456
+ 'Get brain intelligence stats — vocabulary size, feedback count, current scoring weights, intelligence pipeline stats.',
344
457
  auth: 'read',
345
458
  handler: async () => {
346
- return brain.getStats();
459
+ const base = brain.getStats();
460
+ const intelligence = brainIntelligence.getStats();
461
+ return { ...base, intelligence };
347
462
  },
348
463
  },
349
464
  {
350
465
  name: 'llm_status',
351
- description: 'LLM client status — provider availability, key pool status, model routing config.',
466
+ description:
467
+ 'LLM client status — provider availability, key pool status, model routing config.',
352
468
  auth: 'read',
353
469
  handler: async () => {
354
470
  const available = llmClient.isAvailable();
@@ -368,6 +484,321 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
368
484
  },
369
485
  },
370
486
 
487
+ // ─── Brain Intelligence ───────────────────────────────────────
488
+ {
489
+ name: 'brain_session_context',
490
+ description:
491
+ 'Get recent session context — sessions, tool usage frequency, file change frequency.',
492
+ auth: 'read',
493
+ schema: z.object({
494
+ limit: z.number().optional().describe('Number of recent sessions. Default 10.'),
495
+ }),
496
+ handler: async (params) => {
497
+ return brainIntelligence.getSessionContext((params.limit as number) ?? 10);
498
+ },
499
+ },
500
+ {
501
+ name: 'brain_strengths',
502
+ description:
503
+ 'Get pattern strength scores. 4-signal scoring: usage (0-25) + spread (0-25) + success (0-25) + recency (0-25).',
504
+ auth: 'read',
505
+ schema: z.object({
506
+ domain: z.string().optional(),
507
+ minStrength: z.number().optional().describe('Minimum strength score (0-100).'),
508
+ limit: z.number().optional(),
509
+ }),
510
+ handler: async (params) => {
511
+ return brainIntelligence.getStrengths({
512
+ domain: params.domain as string | undefined,
513
+ minStrength: params.minStrength as number | undefined,
514
+ limit: (params.limit as number) ?? 50,
515
+ });
516
+ },
517
+ },
518
+ {
519
+ name: 'brain_global_patterns',
520
+ description:
521
+ 'Get cross-domain pattern registry — patterns that appear across multiple domains.',
522
+ auth: 'read',
523
+ schema: z.object({
524
+ limit: z.number().optional(),
525
+ }),
526
+ handler: async (params) => {
527
+ return brainIntelligence.getGlobalPatterns((params.limit as number) ?? 20);
528
+ },
529
+ },
530
+ {
531
+ name: 'brain_recommend',
532
+ description:
533
+ 'Get pattern recommendations for a task context. Matches domain, task terms, and source-specific acceptance rates against known strengths.',
534
+ auth: 'read',
535
+ schema: z.object({
536
+ domain: z.string().optional(),
537
+ task: z.string().optional().describe('Task description for contextual matching.'),
538
+ source: z
539
+ .string()
540
+ .optional()
541
+ .describe(
542
+ 'Feedback source to boost by (search, recommendation, tool-execution, explicit).',
543
+ ),
544
+ limit: z.number().optional(),
545
+ }),
546
+ handler: async (params) => {
547
+ return brainIntelligence.recommend({
548
+ domain: params.domain as string | undefined,
549
+ task: params.task as string | undefined,
550
+ source: params.source as string | undefined,
551
+ limit: (params.limit as number) ?? 5,
552
+ });
553
+ },
554
+ },
555
+ {
556
+ name: 'brain_build_intelligence',
557
+ description:
558
+ 'Run the full intelligence pipeline: compute strengths → build global registry → build domain profiles.',
559
+ auth: 'write',
560
+ handler: async () => {
561
+ return brainIntelligence.buildIntelligence();
562
+ },
563
+ },
564
+ {
565
+ name: 'brain_export',
566
+ description:
567
+ 'Export all brain intelligence data — strengths, sessions, proposals, global patterns, domain profiles.',
568
+ auth: 'read',
569
+ handler: async () => {
570
+ return brainIntelligence.exportData();
571
+ },
572
+ },
573
+ {
574
+ name: 'brain_import',
575
+ description: 'Import brain intelligence data from a previous export.',
576
+ auth: 'write',
577
+ schema: z.object({
578
+ data: z.any().describe('BrainExportData object from brain_export.'),
579
+ }),
580
+ handler: async (params) => {
581
+ return brainIntelligence.importData(
582
+ params.data as import('../brain/types.js').BrainExportData,
583
+ );
584
+ },
585
+ },
586
+ {
587
+ name: 'brain_extract_knowledge',
588
+ description:
589
+ 'Extract knowledge proposals from a session using 6 heuristic rules (repeated tools, multi-file edits, long sessions, plan outcomes, feedback ratios).',
590
+ auth: 'write',
591
+ schema: z.object({
592
+ sessionId: z.string().describe('Session ID to extract knowledge from.'),
593
+ }),
594
+ handler: async (params) => {
595
+ return brainIntelligence.extractKnowledge(params.sessionId as string);
596
+ },
597
+ },
598
+ {
599
+ name: 'brain_archive_sessions',
600
+ description: 'Archive (delete) completed sessions older than N days.',
601
+ auth: 'write',
602
+ schema: z.object({
603
+ olderThanDays: z.number().optional().describe('Days threshold. Default 30.'),
604
+ }),
605
+ handler: async (params) => {
606
+ return brainIntelligence.archiveSessions((params.olderThanDays as number) ?? 30);
607
+ },
608
+ },
609
+ {
610
+ name: 'brain_promote_proposals',
611
+ description:
612
+ 'Promote knowledge proposals to vault entries. Creates intelligence entries from auto-extracted patterns. Gated by governance policies.',
613
+ auth: 'write',
614
+ schema: z.object({
615
+ proposalIds: z.array(z.string()).describe('IDs of proposals to promote.'),
616
+ projectPath: z.string().optional().default('.'),
617
+ }),
618
+ handler: async (params) => {
619
+ const pp = (params.projectPath as string | undefined) ?? '.';
620
+ return brainIntelligence.promoteProposals(params.proposalIds as string[], governance, pp);
621
+ },
622
+ },
623
+ {
624
+ name: 'brain_lifecycle',
625
+ description:
626
+ 'Start or end a brain session. Sessions track tool usage, file changes, and plan context.',
627
+ auth: 'write',
628
+ schema: z.object({
629
+ action: z.enum(['start', 'end']),
630
+ sessionId: z
631
+ .string()
632
+ .optional()
633
+ .describe('Required for end. Auto-generated for start if omitted.'),
634
+ domain: z.string().optional(),
635
+ context: z.string().optional(),
636
+ toolsUsed: z.array(z.string()).optional(),
637
+ filesModified: z.array(z.string()).optional(),
638
+ planId: z.string().optional(),
639
+ planOutcome: z.string().optional(),
640
+ }),
641
+ handler: async (params) => {
642
+ return brainIntelligence.lifecycle({
643
+ action: params.action as 'start' | 'end',
644
+ sessionId: params.sessionId as string | undefined,
645
+ domain: params.domain as string | undefined,
646
+ context: params.context as string | undefined,
647
+ toolsUsed: params.toolsUsed as string[] | undefined,
648
+ filesModified: params.filesModified as string[] | undefined,
649
+ planId: params.planId as string | undefined,
650
+ planOutcome: params.planOutcome as string | undefined,
651
+ });
652
+ },
653
+ },
654
+
655
+ {
656
+ name: 'brain_reset_extracted',
657
+ description:
658
+ 'Reset extraction status on brain sessions, allowing re-extraction. Filter by sessionId, since date, or all.',
659
+ auth: 'write',
660
+ schema: z.object({
661
+ sessionId: z.string().optional().describe('Reset a specific session.'),
662
+ since: z.string().optional().describe('Reset sessions extracted since this ISO date.'),
663
+ all: z.boolean().optional().describe('Reset all extracted sessions.'),
664
+ }),
665
+ handler: async (params) => {
666
+ return brainIntelligence.resetExtracted({
667
+ sessionId: params.sessionId as string | undefined,
668
+ since: params.since as string | undefined,
669
+ all: params.all as boolean | undefined,
670
+ });
671
+ },
672
+ },
673
+
674
+ // ─── Cognee ──────────────────────────────────────────────────
675
+ {
676
+ name: 'cognee_status',
677
+ description:
678
+ 'Cognee vector search health — availability, URL, latency. Checks the Cognee API endpoint.',
679
+ auth: 'read',
680
+ handler: async () => {
681
+ return cognee.healthCheck();
682
+ },
683
+ },
684
+ {
685
+ name: 'cognee_search',
686
+ description:
687
+ 'Vector similarity search via Cognee. Complements TF-IDF vault search with semantic understanding.',
688
+ auth: 'read',
689
+ schema: z.object({
690
+ query: z.string(),
691
+ searchType: z
692
+ .enum([
693
+ 'SUMMARIES',
694
+ 'CHUNKS',
695
+ 'RAG_COMPLETION',
696
+ 'TRIPLET_COMPLETION',
697
+ 'GRAPH_COMPLETION',
698
+ 'GRAPH_SUMMARY_COMPLETION',
699
+ 'NATURAL_LANGUAGE',
700
+ 'GRAPH_COMPLETION_COT',
701
+ 'FEELING_LUCKY',
702
+ 'CHUNKS_LEXICAL',
703
+ ])
704
+ .optional()
705
+ .describe('Cognee search type. Default CHUNKS (pure vector similarity).'),
706
+ limit: z.number().optional(),
707
+ }),
708
+ handler: async (params) => {
709
+ return cognee.search(params.query as string, {
710
+ searchType: params.searchType as CogneeSearchType | undefined,
711
+ limit: (params.limit as number) ?? 10,
712
+ });
713
+ },
714
+ },
715
+ {
716
+ name: 'cognee_add',
717
+ description:
718
+ 'Ingest vault entries into Cognee for vector indexing. Auto-schedules cognify after ingest.',
719
+ auth: 'write',
720
+ schema: z.object({
721
+ entryIds: z.array(z.string()).describe('Vault entry IDs to ingest into Cognee.'),
722
+ }),
723
+ handler: async (params) => {
724
+ const ids = params.entryIds as string[];
725
+ const entries = ids
726
+ .map((id) => vault.get(id))
727
+ .filter((e): e is IntelligenceEntry => e !== null && e !== undefined);
728
+ if (entries.length === 0) return { added: 0, error: 'No matching vault entries found' };
729
+ return cognee.addEntries(entries);
730
+ },
731
+ },
732
+ {
733
+ name: 'cognee_cognify',
734
+ description:
735
+ 'Trigger Cognee knowledge graph processing on the vault dataset. Usually auto-scheduled after add.',
736
+ auth: 'write',
737
+ handler: async () => {
738
+ return cognee.cognify();
739
+ },
740
+ },
741
+ {
742
+ name: 'cognee_config',
743
+ description: 'Get current Cognee client configuration and cached health status.',
744
+ auth: 'read',
745
+ handler: async () => {
746
+ return { config: cognee.getConfig(), cachedStatus: cognee.getStatus() };
747
+ },
748
+ },
749
+
750
+ // ─── LLM ─────────────────────────────────────────────────────
751
+ {
752
+ name: 'llm_rotate',
753
+ description:
754
+ 'Force rotate the active API key for a provider. Useful when rate-limited or key is failing.',
755
+ auth: 'write',
756
+ schema: z.object({
757
+ provider: z.enum(['openai', 'anthropic']),
758
+ }),
759
+ handler: async (params) => {
760
+ const provider = params.provider as 'openai' | 'anthropic';
761
+ const pool = keyPool[provider];
762
+ if (!pool.hasKeys) return { rotated: false, error: `No ${provider} keys configured` };
763
+ const newKey = pool.rotateOnError();
764
+ return {
765
+ rotated: newKey !== null,
766
+ activeKeyIndex: pool.activeKeyIndex,
767
+ poolSize: pool.poolSize,
768
+ exhausted: pool.exhausted,
769
+ };
770
+ },
771
+ },
772
+ {
773
+ name: 'llm_call',
774
+ description: 'Make an LLM completion call. Uses model routing config and key pool rotation.',
775
+ auth: 'write',
776
+ schema: z.object({
777
+ systemPrompt: z.string().describe('System prompt for the LLM.'),
778
+ userPrompt: z.string().describe('User prompt / task input.'),
779
+ model: z
780
+ .string()
781
+ .optional()
782
+ .describe('Model name. Routed via model-routing.json if omitted.'),
783
+ temperature: z.number().optional().describe('Sampling temperature (0-2). Default 0.3.'),
784
+ maxTokens: z.number().optional().describe('Max output tokens. Default 500.'),
785
+ caller: z.string().optional().describe('Caller name for routing. Default "core-ops".'),
786
+ task: z.string().optional().describe('Task name for routing.'),
787
+ }),
788
+ handler: async (params) => {
789
+ return llmClient.complete({
790
+ provider: 'openai',
791
+ model: (params.model as string) ?? '',
792
+ systemPrompt: params.systemPrompt as string,
793
+ userPrompt: params.userPrompt as string,
794
+ temperature: params.temperature as number | undefined,
795
+ maxTokens: params.maxTokens as number | undefined,
796
+ caller: (params.caller as string) ?? 'core-ops',
797
+ task: params.task as string | undefined,
798
+ });
799
+ },
800
+ },
801
+
371
802
  // ─── Curator ─────────────────────────────────────────────────
372
803
  {
373
804
  name: 'curator_status',
@@ -404,7 +835,9 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
404
835
  if (params.detect) {
405
836
  curator.detectContradictions();
406
837
  }
407
- return curator.getContradictions(params.status as 'open' | 'resolved' | 'dismissed' | undefined);
838
+ return curator.getContradictions(
839
+ params.status as 'open' | 'resolved' | 'dismissed' | undefined,
840
+ );
408
841
  },
409
842
  },
410
843
  {
@@ -443,13 +876,23 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
443
876
  },
444
877
  {
445
878
  name: 'curator_consolidate',
446
- description: 'Consolidate vault — find duplicates, stale entries, contradictions. Dry-run by default.',
879
+ description:
880
+ 'Consolidate vault — find duplicates, stale entries, contradictions. Dry-run by default.',
447
881
  auth: 'write',
448
882
  schema: z.object({
449
883
  dryRun: z.boolean().optional().describe('Default true. Set false to apply mutations.'),
450
- staleDaysThreshold: z.number().optional().describe('Days before entry is stale. Default 90.'),
451
- duplicateThreshold: z.number().optional().describe('Cosine similarity threshold. Default 0.45.'),
452
- contradictionThreshold: z.number().optional().describe('Contradiction threshold. Default 0.4.'),
884
+ staleDaysThreshold: z
885
+ .number()
886
+ .optional()
887
+ .describe('Days before entry is stale. Default 90.'),
888
+ duplicateThreshold: z
889
+ .number()
890
+ .optional()
891
+ .describe('Cosine similarity threshold. Default 0.45.'),
892
+ contradictionThreshold: z
893
+ .number()
894
+ .optional()
895
+ .describe('Contradiction threshold. Default 0.4.'),
453
896
  }),
454
897
  handler: async (params) => {
455
898
  return curator.consolidate({
@@ -462,11 +905,289 @@ export function createCoreOps(runtime: AgentRuntime): OpDefinition[] {
462
905
  },
463
906
  {
464
907
  name: 'curator_health_audit',
465
- description: 'Audit vault health — score (0-100), coverage, freshness, quality, tag health, recommendations.',
908
+ description:
909
+ 'Audit vault health — score (0-100), coverage, freshness, quality, tag health, recommendations.',
466
910
  auth: 'read',
467
911
  handler: async () => {
468
912
  return curator.healthAudit();
469
913
  },
470
914
  },
915
+
916
+ // ─── Control ──────────────────────────────────────────────────────
917
+ {
918
+ name: 'get_identity',
919
+ description: 'Get current agent identity with guidelines.',
920
+ auth: 'read',
921
+ schema: z.object({
922
+ agentId: z.string().describe('Agent identifier.'),
923
+ }),
924
+ handler: async (params) => {
925
+ const identity = identityManager.getIdentity(params.agentId as string);
926
+ if (!identity) return { found: false, agentId: params.agentId };
927
+ return identity;
928
+ },
929
+ },
930
+ {
931
+ name: 'update_identity',
932
+ description: 'Update identity fields. Auto-versions and snapshots previous state.',
933
+ auth: 'write',
934
+ schema: z.object({
935
+ agentId: z.string(),
936
+ name: z.string().optional(),
937
+ role: z.string().optional(),
938
+ description: z.string().optional(),
939
+ personality: z.array(z.string()).optional(),
940
+ changedBy: z.string().optional(),
941
+ changeReason: z.string().optional(),
942
+ }),
943
+ handler: async (params) => {
944
+ const identity = identityManager.setIdentity(params.agentId as string, {
945
+ name: params.name as string | undefined,
946
+ role: params.role as string | undefined,
947
+ description: params.description as string | undefined,
948
+ personality: params.personality as string[] | undefined,
949
+ changedBy: params.changedBy as string | undefined,
950
+ changeReason: params.changeReason as string | undefined,
951
+ });
952
+ return { updated: true, identity };
953
+ },
954
+ },
955
+ {
956
+ name: 'add_guideline',
957
+ description: 'Add a behavioral guideline (behavior/preference/restriction/style).',
958
+ auth: 'write',
959
+ schema: z.object({
960
+ agentId: z.string(),
961
+ category: z.enum(['behavior', 'preference', 'restriction', 'style']),
962
+ text: z.string(),
963
+ priority: z.number().optional(),
964
+ }),
965
+ handler: async (params) => {
966
+ const guideline = identityManager.addGuideline(params.agentId as string, {
967
+ category: params.category as GuidelineCategory,
968
+ text: params.text as string,
969
+ priority: params.priority as number | undefined,
970
+ });
971
+ return { added: true, guideline };
972
+ },
973
+ },
974
+ {
975
+ name: 'remove_guideline',
976
+ description: 'Remove a guideline by ID.',
977
+ auth: 'write',
978
+ schema: z.object({
979
+ guidelineId: z.string(),
980
+ }),
981
+ handler: async (params) => {
982
+ const removed = identityManager.removeGuideline(params.guidelineId as string);
983
+ return { removed };
984
+ },
985
+ },
986
+ {
987
+ name: 'rollback_identity',
988
+ description: 'Restore a previous identity version. Creates a new version with the old data.',
989
+ auth: 'write',
990
+ schema: z.object({
991
+ agentId: z.string(),
992
+ version: z.number().describe('Version number to roll back to.'),
993
+ }),
994
+ handler: async (params) => {
995
+ const identity = identityManager.rollback(
996
+ params.agentId as string,
997
+ params.version as number,
998
+ );
999
+ return { rolledBack: true, identity };
1000
+ },
1001
+ },
1002
+ {
1003
+ name: 'route_intent',
1004
+ description: 'Classify a prompt into intent + operational mode via keyword matching.',
1005
+ auth: 'read',
1006
+ schema: z.object({
1007
+ prompt: z.string().describe('The user prompt to classify.'),
1008
+ }),
1009
+ handler: async (params) => {
1010
+ return intentRouter.routeIntent(params.prompt as string);
1011
+ },
1012
+ },
1013
+ {
1014
+ name: 'morph',
1015
+ description: 'Switch operational mode manually.',
1016
+ auth: 'write',
1017
+ schema: z.object({
1018
+ mode: z
1019
+ .string()
1020
+ .describe('The operational mode to switch to (e.g., BUILD-MODE, FIX-MODE).'),
1021
+ }),
1022
+ handler: async (params) => {
1023
+ return intentRouter.morph(params.mode as OperationalMode);
1024
+ },
1025
+ },
1026
+ {
1027
+ name: 'get_behavior_rules',
1028
+ description: 'Get behavior rules for current or specified mode.',
1029
+ auth: 'read',
1030
+ schema: z.object({
1031
+ mode: z.string().optional().describe('Mode to get rules for. Defaults to current mode.'),
1032
+ }),
1033
+ handler: async (params) => {
1034
+ const mode = params.mode as OperationalMode | undefined;
1035
+ const rules = intentRouter.getBehaviorRules(mode);
1036
+ const currentMode = intentRouter.getCurrentMode();
1037
+ return { mode: mode ?? currentMode, rules };
1038
+ },
1039
+ },
1040
+
1041
+ // ─── Governance ─────────────────────────────────────────────────
1042
+ {
1043
+ name: 'governance_policy',
1044
+ description:
1045
+ 'Get, set, or apply a preset to vault governance policies (quota, retention, auto-capture).',
1046
+ auth: 'write',
1047
+ schema: z.object({
1048
+ action: z.enum(['get', 'set', 'applyPreset']),
1049
+ projectPath: z.string(),
1050
+ policyType: z.enum(['quota', 'retention', 'auto-capture']).optional(),
1051
+ config: z.record(z.unknown()).optional(),
1052
+ preset: z.enum(['strict', 'moderate', 'permissive']).optional(),
1053
+ changedBy: z.string().optional(),
1054
+ }),
1055
+ handler: async (params) => {
1056
+ const action = params.action as string;
1057
+ const projectPath = params.projectPath as string;
1058
+ if (action === 'get') {
1059
+ return governance.getPolicy(projectPath);
1060
+ }
1061
+ if (action === 'set') {
1062
+ governance.setPolicy(
1063
+ projectPath,
1064
+ params.policyType as PolicyType,
1065
+ params.config as Record<string, unknown>,
1066
+ params.changedBy as string | undefined,
1067
+ );
1068
+ return { updated: true, policy: governance.getPolicy(projectPath) };
1069
+ }
1070
+ if (action === 'applyPreset') {
1071
+ governance.applyPreset(
1072
+ projectPath,
1073
+ params.preset as PolicyPreset,
1074
+ params.changedBy as string | undefined,
1075
+ );
1076
+ return {
1077
+ applied: true,
1078
+ preset: params.preset,
1079
+ policy: governance.getPolicy(projectPath),
1080
+ };
1081
+ }
1082
+ return { error: 'Unknown action: ' + action };
1083
+ },
1084
+ },
1085
+ {
1086
+ name: 'governance_proposals',
1087
+ description:
1088
+ 'Manage knowledge capture proposals — list, approve, reject, modify, get stats, or expire stale.',
1089
+ auth: 'write',
1090
+ schema: z.object({
1091
+ action: z.enum(['list', 'approve', 'reject', 'modify', 'stats', 'expire']),
1092
+ projectPath: z.string().optional(),
1093
+ proposalId: z.number().optional(),
1094
+ decidedBy: z.string().optional(),
1095
+ note: z.string().optional(),
1096
+ modifications: z.record(z.unknown()).optional(),
1097
+ maxAgeDays: z.number().optional(),
1098
+ limit: z.number().optional(),
1099
+ }),
1100
+ handler: async (params) => {
1101
+ const action = params.action as string;
1102
+ if (action === 'list') {
1103
+ return governance.listPendingProposals(
1104
+ params.projectPath as string | undefined,
1105
+ params.limit as number | undefined,
1106
+ );
1107
+ }
1108
+ if (action === 'approve') {
1109
+ return governance.approveProposal(
1110
+ params.proposalId as number,
1111
+ params.decidedBy as string | undefined,
1112
+ );
1113
+ }
1114
+ if (action === 'reject') {
1115
+ return governance.rejectProposal(
1116
+ params.proposalId as number,
1117
+ params.decidedBy as string | undefined,
1118
+ params.note as string | undefined,
1119
+ );
1120
+ }
1121
+ if (action === 'modify') {
1122
+ return governance.modifyProposal(
1123
+ params.proposalId as number,
1124
+ params.modifications as Record<string, unknown>,
1125
+ params.decidedBy as string | undefined,
1126
+ );
1127
+ }
1128
+ if (action === 'stats') {
1129
+ return governance.getProposalStats(params.projectPath as string | undefined);
1130
+ }
1131
+ if (action === 'expire') {
1132
+ const expired = governance.expireStaleProposals(params.maxAgeDays as number | undefined);
1133
+ return { expired };
1134
+ }
1135
+ return { error: 'Unknown action: ' + action };
1136
+ },
1137
+ },
1138
+ {
1139
+ name: 'governance_stats',
1140
+ description: 'Get governance statistics — quota status and proposal stats for a project.',
1141
+ auth: 'read',
1142
+ schema: z.object({
1143
+ projectPath: z.string(),
1144
+ }),
1145
+ handler: async (params) => {
1146
+ const projectPath = params.projectPath as string;
1147
+ return {
1148
+ quotaStatus: governance.getQuotaStatus(projectPath),
1149
+ proposalStats: governance.getProposalStats(projectPath),
1150
+ };
1151
+ },
1152
+ },
1153
+ {
1154
+ name: 'governance_expire',
1155
+ description: 'Expire stale pending proposals older than a threshold.',
1156
+ auth: 'write',
1157
+ schema: z.object({
1158
+ projectPath: z.string().optional(),
1159
+ maxAgeDays: z.number().optional().describe('Days threshold. Default 14.'),
1160
+ }),
1161
+ handler: async (params) => {
1162
+ const expired = governance.expireStaleProposals(params.maxAgeDays as number | undefined);
1163
+ return { expired };
1164
+ },
1165
+ },
1166
+ {
1167
+ name: 'governance_dashboard',
1168
+ description:
1169
+ 'Get governance dashboard — vault size, quota usage, pending proposals, acceptance rate, evaluation trend.',
1170
+ auth: 'read',
1171
+ schema: z.object({
1172
+ projectPath: z.string(),
1173
+ }),
1174
+ handler: async (params) => {
1175
+ return governance.getDashboard(params.projectPath as string);
1176
+ },
1177
+ },
1178
+
1179
+ // ─── Extra Ops (from dedicated modules) ─────────────────────────
1180
+ ...createPlanningExtraOps(runtime),
1181
+ ...createMemoryExtraOps(runtime),
1182
+ ...createVaultExtraOps(runtime),
1183
+ ...createAdminOps(runtime),
1184
+ ...createAdminExtraOps(runtime),
1185
+ ...createLoopOps(runtime),
1186
+ ...createOrchestrateOps(runtime),
1187
+ ...createGradingOps(runtime),
1188
+ ...createCaptureOps(runtime),
1189
+ ...createCuratorExtraOps(runtime),
1190
+ ...createProjectOps(runtime),
1191
+ ...createMemoryCrossProjectOps(runtime),
471
1192
  ];
472
1193
  }