@soleri/core 9.2.0 → 9.3.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 (298) hide show
  1. package/data/flows/build.flow.yaml +8 -9
  2. package/data/flows/deliver.flow.yaml +9 -10
  3. package/data/flows/design.flow.yaml +3 -4
  4. package/data/flows/enhance.flow.yaml +5 -6
  5. package/data/flows/explore.flow.yaml +3 -4
  6. package/data/flows/fix.flow.yaml +5 -6
  7. package/data/flows/plan.flow.yaml +4 -5
  8. package/data/flows/review.flow.yaml +3 -4
  9. package/dist/curator/curator.d.ts.map +1 -1
  10. package/dist/curator/curator.js +98 -22
  11. package/dist/curator/curator.js.map +1 -1
  12. package/dist/engine/bin/soleri-engine.js.map +1 -1
  13. package/dist/engine/module-manifest.d.ts.map +1 -1
  14. package/dist/engine/module-manifest.js +21 -1
  15. package/dist/engine/module-manifest.js.map +1 -1
  16. package/dist/engine/register-engine.d.ts.map +1 -1
  17. package/dist/engine/register-engine.js +25 -1
  18. package/dist/engine/register-engine.js.map +1 -1
  19. package/dist/flows/gate-evaluator.js.map +1 -1
  20. package/dist/operator/operator-profile.d.ts.map +1 -1
  21. package/dist/operator/operator-profile.js +11 -5
  22. package/dist/operator/operator-profile.js.map +1 -1
  23. package/dist/operator/operator-signals.d.ts.map +1 -1
  24. package/dist/operator/operator-signals.js.map +1 -1
  25. package/dist/planning/evidence-collector.js.map +1 -1
  26. package/dist/planning/gap-passes.d.ts.map +1 -1
  27. package/dist/planning/gap-passes.js +23 -6
  28. package/dist/planning/gap-passes.js.map +1 -1
  29. package/dist/planning/gap-patterns.d.ts.map +1 -1
  30. package/dist/planning/gap-patterns.js +57 -11
  31. package/dist/planning/gap-patterns.js.map +1 -1
  32. package/dist/planning/github-projection.d.ts.map +1 -1
  33. package/dist/planning/github-projection.js +39 -20
  34. package/dist/planning/github-projection.js.map +1 -1
  35. package/dist/planning/impact-analyzer.d.ts.map +1 -1
  36. package/dist/planning/impact-analyzer.js +20 -18
  37. package/dist/planning/impact-analyzer.js.map +1 -1
  38. package/dist/planning/plan-lifecycle.d.ts.map +1 -1
  39. package/dist/planning/plan-lifecycle.js +22 -9
  40. package/dist/planning/plan-lifecycle.js.map +1 -1
  41. package/dist/planning/planner.d.ts.map +1 -1
  42. package/dist/planning/planner.js +60 -17
  43. package/dist/planning/planner.js.map +1 -1
  44. package/dist/planning/rationalization-detector.d.ts.map +1 -1
  45. package/dist/planning/rationalization-detector.js.map +1 -1
  46. package/dist/planning/reconciliation-engine.d.ts.map +1 -1
  47. package/dist/planning/reconciliation-engine.js.map +1 -1
  48. package/dist/planning/task-verifier.d.ts.map +1 -1
  49. package/dist/planning/task-verifier.js +14 -6
  50. package/dist/planning/task-verifier.js.map +1 -1
  51. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  52. package/dist/runtime/admin-setup-ops.js +2 -1
  53. package/dist/runtime/admin-setup-ops.js.map +1 -1
  54. package/dist/runtime/branching-ops.d.ts +12 -0
  55. package/dist/runtime/branching-ops.d.ts.map +1 -0
  56. package/dist/runtime/branching-ops.js +100 -0
  57. package/dist/runtime/branching-ops.js.map +1 -0
  58. package/dist/runtime/context-health.d.ts.map +1 -1
  59. package/dist/runtime/context-health.js.map +1 -1
  60. package/dist/runtime/facades/branching-facade.d.ts +7 -0
  61. package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
  62. package/dist/runtime/facades/branching-facade.js +8 -0
  63. package/dist/runtime/facades/branching-facade.js.map +1 -0
  64. package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -1
  65. package/dist/runtime/facades/chat-service-ops.js +3 -1
  66. package/dist/runtime/facades/chat-service-ops.js.map +1 -1
  67. package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -1
  68. package/dist/runtime/facades/chat-transport-ops.js.map +1 -1
  69. package/dist/runtime/facades/index.d.ts.map +1 -1
  70. package/dist/runtime/facades/index.js +42 -0
  71. package/dist/runtime/facades/index.js.map +1 -1
  72. package/dist/runtime/facades/intake-facade.d.ts +9 -0
  73. package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
  74. package/dist/runtime/facades/intake-facade.js +11 -0
  75. package/dist/runtime/facades/intake-facade.js.map +1 -0
  76. package/dist/runtime/facades/links-facade.d.ts +9 -0
  77. package/dist/runtime/facades/links-facade.d.ts.map +1 -0
  78. package/dist/runtime/facades/links-facade.js +10 -0
  79. package/dist/runtime/facades/links-facade.js.map +1 -0
  80. package/dist/runtime/facades/operator-facade.d.ts.map +1 -1
  81. package/dist/runtime/facades/operator-facade.js.map +1 -1
  82. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  83. package/dist/runtime/facades/plan-facade.js +4 -1
  84. package/dist/runtime/facades/plan-facade.js.map +1 -1
  85. package/dist/runtime/facades/tier-facade.d.ts +7 -0
  86. package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
  87. package/dist/runtime/facades/tier-facade.js +8 -0
  88. package/dist/runtime/facades/tier-facade.js.map +1 -0
  89. package/dist/runtime/facades/vault-facade.d.ts +9 -1
  90. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  91. package/dist/runtime/facades/vault-facade.js +44 -187
  92. package/dist/runtime/facades/vault-facade.js.map +1 -1
  93. package/dist/runtime/github-integration.d.ts.map +1 -1
  94. package/dist/runtime/github-integration.js +11 -4
  95. package/dist/runtime/github-integration.js.map +1 -1
  96. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  97. package/dist/runtime/orchestrate-ops.js +32 -10
  98. package/dist/runtime/orchestrate-ops.js.map +1 -1
  99. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  100. package/dist/runtime/planning-extra-ops.js.map +1 -1
  101. package/dist/runtime/runtime.d.ts.map +1 -1
  102. package/dist/runtime/runtime.js +3 -1
  103. package/dist/runtime/runtime.js.map +1 -1
  104. package/dist/runtime/session-briefing.d.ts.map +1 -1
  105. package/dist/runtime/session-briefing.js +5 -1
  106. package/dist/runtime/session-briefing.js.map +1 -1
  107. package/dist/runtime/tier-ops.d.ts +13 -0
  108. package/dist/runtime/tier-ops.d.ts.map +1 -0
  109. package/dist/runtime/tier-ops.js +110 -0
  110. package/dist/runtime/tier-ops.js.map +1 -0
  111. package/dist/skills/sync-skills.d.ts.map +1 -1
  112. package/dist/skills/sync-skills.js +1 -1
  113. package/dist/skills/sync-skills.js.map +1 -1
  114. package/dist/vault/linking.d.ts.map +1 -1
  115. package/dist/vault/linking.js +41 -5
  116. package/dist/vault/linking.js.map +1 -1
  117. package/dist/vault/vault-entries.d.ts.map +1 -1
  118. package/dist/vault/vault-entries.js +68 -26
  119. package/dist/vault/vault-entries.js.map +1 -1
  120. package/dist/vault/vault-maintenance.d.ts.map +1 -1
  121. package/dist/vault/vault-maintenance.js +6 -2
  122. package/dist/vault/vault-maintenance.js.map +1 -1
  123. package/dist/vault/vault-markdown-sync.d.ts.map +1 -1
  124. package/dist/vault/vault-markdown-sync.js.map +1 -1
  125. package/dist/vault/vault-memories.d.ts.map +1 -1
  126. package/dist/vault/vault-memories.js +3 -1
  127. package/dist/vault/vault-memories.js.map +1 -1
  128. package/dist/vault/vault-schema.js +36 -10
  129. package/dist/vault/vault-schema.js.map +1 -1
  130. package/dist/vault/vault.d.ts.map +1 -1
  131. package/dist/vault/vault.js +5 -1
  132. package/dist/vault/vault.js.map +1 -1
  133. package/package.json +7 -7
  134. package/src/agency/agency-manager.test.ts +60 -40
  135. package/src/agency/default-rules.test.ts +17 -9
  136. package/src/capabilities/registry.test.ts +2 -12
  137. package/src/chat/agent-loop.test.ts +33 -43
  138. package/src/chat/mcp-bridge.test.ts +7 -2
  139. package/src/claudemd/inject.test.ts +2 -12
  140. package/src/context/context-engine.test.ts +96 -51
  141. package/src/control/intent-router.test.ts +3 -3
  142. package/src/curator/classifier.test.ts +14 -8
  143. package/src/curator/contradiction-detector.test.ts +30 -5
  144. package/src/curator/curator.ts +278 -56
  145. package/src/curator/duplicate-detector.test.ts +77 -15
  146. package/src/curator/quality-gate.test.ts +71 -31
  147. package/src/curator/tag-manager.test.ts +12 -4
  148. package/src/domain-packs/knowledge-installer.test.ts +2 -10
  149. package/src/domain-packs/token-resolver.test.ts +1 -3
  150. package/src/domain-packs/types.test.ts +16 -2
  151. package/src/enforcement/registry.test.ts +2 -8
  152. package/src/engine/bin/soleri-engine.ts +3 -1
  153. package/src/engine/module-manifest.test.ts +5 -4
  154. package/src/engine/module-manifest.ts +21 -1
  155. package/src/engine/register-engine.test.ts +6 -1
  156. package/src/engine/register-engine.ts +26 -3
  157. package/src/errors/classify.test.ts +6 -2
  158. package/src/errors/retry.test.ts +1 -4
  159. package/src/facades/facade-factory.test.ts +110 -64
  160. package/src/flows/epilogue.test.ts +16 -10
  161. package/src/flows/gate-evaluator.test.ts +12 -6
  162. package/src/flows/gate-evaluator.ts +1 -3
  163. package/src/governance/governance.test.ts +137 -21
  164. package/src/health/health-registry.test.ts +8 -1
  165. package/src/intake/content-classifier.test.ts +121 -51
  166. package/src/intake/dedup-gate.test.ts +38 -22
  167. package/src/intake/intake-pipeline.test.ts +5 -3
  168. package/src/intake/text-ingester.test.ts +26 -20
  169. package/src/llm/key-pool.test.ts +1 -3
  170. package/src/llm/llm-client.test.ts +1 -4
  171. package/src/llm/oauth-discovery.test.ts +16 -16
  172. package/src/llm/utils.test.ts +62 -18
  173. package/src/logging/logger.test.ts +4 -1
  174. package/src/loop/loop-manager.test.ts +2 -6
  175. package/src/migrations/migration-runner.edge-cases.test.ts +2 -7
  176. package/src/operator/operator-profile-extended.test.ts +15 -5
  177. package/src/operator/operator-profile.test.ts +26 -8
  178. package/src/operator/operator-profile.ts +38 -22
  179. package/src/operator/operator-signals-extended.test.ts +35 -23
  180. package/src/operator/operator-signals.test.ts +6 -10
  181. package/src/operator/operator-signals.ts +2 -1
  182. package/src/operator/prompts/hook-precompact-operator-dispatch.md +10 -6
  183. package/src/operator/prompts/subagent-soft-signal-extractor.md +5 -0
  184. package/src/operator/prompts/subagent-synthesis-cognition.md +19 -10
  185. package/src/operator/prompts/subagent-synthesis-communication.md +13 -7
  186. package/src/operator/prompts/subagent-synthesis-technical.md +19 -9
  187. package/src/operator/prompts/subagent-synthesis-trust.md +27 -21
  188. package/src/persona/defaults.test.ts +1 -5
  189. package/src/planning/evidence-collector.test.ts +147 -38
  190. package/src/planning/evidence-collector.ts +1 -4
  191. package/src/planning/gap-analysis-alternatives.test.ts +41 -11
  192. package/src/planning/gap-passes.test.ts +215 -33
  193. package/src/planning/gap-passes.ts +115 -46
  194. package/src/planning/gap-patterns.test.ts +87 -13
  195. package/src/planning/gap-patterns.ts +114 -31
  196. package/src/planning/github-projection.test.ts +6 -1
  197. package/src/planning/github-projection.ts +41 -20
  198. package/src/planning/impact-analyzer.test.ts +10 -23
  199. package/src/planning/impact-analyzer.ts +33 -46
  200. package/src/planning/plan-lifecycle.test.ts +103 -36
  201. package/src/planning/plan-lifecycle.ts +49 -18
  202. package/src/planning/planner.test.ts +12 -2
  203. package/src/planning/planner.ts +198 -58
  204. package/src/planning/rationalization-detector.test.ts +5 -20
  205. package/src/planning/rationalization-detector.ts +14 -16
  206. package/src/planning/reconciliation-engine.test.ts +20 -3
  207. package/src/planning/reconciliation-engine.ts +1 -2
  208. package/src/planning/task-verifier.test.ts +59 -27
  209. package/src/planning/task-verifier.ts +15 -9
  210. package/src/playbooks/playbook-executor.test.ts +1 -3
  211. package/src/plugins/plugin-loader.test.ts +19 -14
  212. package/src/plugins/plugin-registry.test.ts +45 -33
  213. package/src/project/project-registry.test.ts +23 -12
  214. package/src/prompts/template-manager.test.ts +4 -1
  215. package/src/queue/job-queue.test.ts +10 -14
  216. package/src/runtime/admin-extra-ops.test.ts +5 -19
  217. package/src/runtime/admin-ops.test.ts +1 -3
  218. package/src/runtime/admin-setup-ops.test.ts +3 -4
  219. package/src/runtime/admin-setup-ops.ts +9 -2
  220. package/src/runtime/archive-ops.test.ts +4 -1
  221. package/src/runtime/branching-ops.test.ts +144 -0
  222. package/src/runtime/branching-ops.ts +107 -0
  223. package/src/runtime/capture-ops.test.ts +7 -21
  224. package/src/runtime/chain-ops.test.ts +16 -6
  225. package/src/runtime/claude-md-helpers.test.ts +1 -3
  226. package/src/runtime/context-health.test.ts +1 -3
  227. package/src/runtime/context-health.ts +1 -3
  228. package/src/runtime/curator-extra-ops.test.ts +3 -1
  229. package/src/runtime/domain-ops.test.ts +46 -36
  230. package/src/runtime/facades/admin-facade.test.ts +1 -4
  231. package/src/runtime/facades/archive-facade.test.ts +21 -7
  232. package/src/runtime/facades/brain-facade.test.ts +176 -72
  233. package/src/runtime/facades/branching-facade.test.ts +43 -0
  234. package/src/runtime/facades/branching-facade.ts +11 -0
  235. package/src/runtime/facades/chat-facade.test.ts +81 -28
  236. package/src/runtime/facades/chat-service-ops.test.ts +178 -73
  237. package/src/runtime/facades/chat-service-ops.ts +3 -1
  238. package/src/runtime/facades/chat-session-ops.test.ts +25 -10
  239. package/src/runtime/facades/chat-transport-ops.test.ts +101 -34
  240. package/src/runtime/facades/chat-transport-ops.ts +0 -1
  241. package/src/runtime/facades/context-facade.test.ts +19 -4
  242. package/src/runtime/facades/control-facade.test.ts +3 -3
  243. package/src/runtime/facades/index.ts +42 -0
  244. package/src/runtime/facades/intake-facade.test.ts +215 -0
  245. package/src/runtime/facades/intake-facade.ts +14 -0
  246. package/src/runtime/facades/links-facade.test.ts +203 -0
  247. package/src/runtime/facades/links-facade.ts +13 -0
  248. package/src/runtime/facades/loop-facade.test.ts +22 -5
  249. package/src/runtime/facades/memory-facade.test.ts +19 -5
  250. package/src/runtime/facades/operator-facade.test.ts +17 -4
  251. package/src/runtime/facades/operator-facade.ts +11 -3
  252. package/src/runtime/facades/orchestrate-facade.test.ts +7 -1
  253. package/src/runtime/facades/plan-facade.test.ts +29 -12
  254. package/src/runtime/facades/plan-facade.ts +7 -2
  255. package/src/runtime/facades/tier-facade.test.ts +47 -0
  256. package/src/runtime/facades/tier-facade.ts +11 -0
  257. package/src/runtime/facades/vault-facade.test.ts +174 -242
  258. package/src/runtime/facades/vault-facade.ts +55 -199
  259. package/src/runtime/github-integration.ts +11 -8
  260. package/src/runtime/grading-ops.test.ts +39 -8
  261. package/src/runtime/intake-ops.test.ts +69 -16
  262. package/src/runtime/loop-ops.test.ts +16 -6
  263. package/src/runtime/memory-cross-project-ops.test.ts +25 -14
  264. package/src/runtime/orchestrate-ops.ts +54 -27
  265. package/src/runtime/pack-ops.test.ts +23 -6
  266. package/src/runtime/planning-extra-ops.test.ts +17 -7
  267. package/src/runtime/planning-extra-ops.ts +3 -1
  268. package/src/runtime/playbook-ops.test.ts +26 -3
  269. package/src/runtime/plugin-ops.test.ts +83 -25
  270. package/src/runtime/project-ops.test.ts +26 -6
  271. package/src/runtime/runtime.ts +3 -1
  272. package/src/runtime/session-briefing.test.ts +183 -54
  273. package/src/runtime/session-briefing.ts +8 -2
  274. package/src/runtime/sync-ops.test.ts +3 -12
  275. package/src/runtime/telemetry-ops.test.ts +31 -6
  276. package/src/runtime/tier-ops.test.ts +159 -0
  277. package/src/runtime/tier-ops.ts +119 -0
  278. package/src/runtime/vault-extra-ops.test.ts +32 -8
  279. package/src/runtime/vault-sharing-ops.test.ts +1 -4
  280. package/src/skills/sync-skills.ts +2 -12
  281. package/src/transport/ws-server.test.ts +7 -4
  282. package/src/vault/__tests__/vault-characterization.test.ts +492 -81
  283. package/src/vault/linking.test.ts +50 -17
  284. package/src/vault/linking.ts +48 -7
  285. package/src/vault/obsidian-sync.test.ts +6 -3
  286. package/src/vault/scope-detector.test.ts +1 -3
  287. package/src/vault/vault-branching.test.ts +9 -7
  288. package/src/vault/vault-entries.ts +209 -65
  289. package/src/vault/vault-maintenance.ts +7 -12
  290. package/src/vault/vault-manager.test.ts +10 -10
  291. package/src/vault/vault-markdown-sync.ts +4 -1
  292. package/src/vault/vault-memories.ts +7 -7
  293. package/src/vault/vault-schema.ts +72 -15
  294. package/src/vault/vault.ts +55 -9
  295. package/src/brain/strength-scorer.ts +0 -404
  296. package/src/engine/index.ts +0 -21
  297. package/src/persona/index.ts +0 -9
  298. package/src/vault/vault-interfaces.ts +0 -56
@@ -8,9 +8,7 @@ function makeMockRuntime(overrides: Record<string, unknown> = {}) {
8
8
  vault: {
9
9
  get: vi.fn().mockReturnValue({ id: 'e1', tags: ['pattern'] }),
10
10
  update: vi.fn(),
11
- searchMemories: vi.fn().mockReturnValue([
12
- { id: 'm1', content: 'memory 1' },
13
- ]),
11
+ searchMemories: vi.fn().mockReturnValue([{ id: 'm1', content: 'memory 1' }]),
14
12
  search: vi.fn().mockReturnValue([
15
13
  { entry: { id: 'g1', tags: ['_global'] }, score: 0.9 },
16
14
  { entry: { id: 'g2', tags: ['other'] }, score: 0.8 },
@@ -25,9 +23,9 @@ function makeMockRuntime(overrides: Record<string, unknown> = {}) {
25
23
  metadata: { memoryConfig: { crossProjectEnabled: true, extraPaths: ['/extra'] } },
26
24
  }),
27
25
  register: vi.fn(),
28
- getLinkedProjects: vi.fn().mockReturnValue([
29
- { project: { path: '/linked', name: 'linked-project' } },
30
- ]),
26
+ getLinkedProjects: vi
27
+ .fn()
28
+ .mockReturnValue([{ project: { path: '/linked', name: 'linked-project' } }]),
31
29
  },
32
30
  } as unknown as AgentRuntime;
33
31
  }
@@ -60,7 +58,9 @@ describe('createMemoryCrossProjectOps', () => {
60
58
  it('promotes entry by adding _global tag', async () => {
61
59
  const runtime = makeMockRuntime();
62
60
  ops = createMemoryCrossProjectOps(runtime);
63
- const result = (await findOp('memory_promote_to_global').handler({ entryId: 'e1' })) as Record<string, unknown>;
61
+ const result = (await findOp('memory_promote_to_global').handler({
62
+ entryId: 'e1',
63
+ })) as Record<string, unknown>;
64
64
  expect(result.promoted).toBe(true);
65
65
  expect(result.tags).toContain('_global');
66
66
  expect(runtime.vault.update).toHaveBeenCalledWith('e1', { tags: ['pattern', '_global'] });
@@ -69,7 +69,9 @@ describe('createMemoryCrossProjectOps', () => {
69
69
  it('returns error when entry not found', async () => {
70
70
  const runtime = makeMockRuntime({ get: vi.fn().mockReturnValue(null) });
71
71
  ops = createMemoryCrossProjectOps(runtime);
72
- const result = (await findOp('memory_promote_to_global').handler({ entryId: 'missing' })) as Record<string, unknown>;
72
+ const result = (await findOp('memory_promote_to_global').handler({
73
+ entryId: 'missing',
74
+ })) as Record<string, unknown>;
73
75
  expect(result.promoted).toBe(false);
74
76
  expect(result.error).toContain('Entry not found');
75
77
  });
@@ -79,7 +81,9 @@ describe('createMemoryCrossProjectOps', () => {
79
81
  get: vi.fn().mockReturnValue({ id: 'e1', tags: ['_global'] }),
80
82
  });
81
83
  ops = createMemoryCrossProjectOps(runtime);
82
- const result = (await findOp('memory_promote_to_global').handler({ entryId: 'e1' })) as Record<string, unknown>;
84
+ const result = (await findOp('memory_promote_to_global').handler({
85
+ entryId: 'e1',
86
+ })) as Record<string, unknown>;
83
87
  expect(result.promoted).toBe(false);
84
88
  expect(result.message).toContain('already promoted');
85
89
  });
@@ -132,12 +136,15 @@ describe('createMemoryCrossProjectOps', () => {
132
136
  const runtime = makeMockRuntime();
133
137
  ops = createMemoryCrossProjectOps(runtime);
134
138
  await findOp('memory_cross_project_search').handler({
135
- query: 'test', projectPath: '/test',
139
+ query: 'test',
140
+ projectPath: '/test',
136
141
  });
137
142
 
138
143
  // Should search current project, linked project, and extra path
139
144
  const searchCalls = (runtime.vault.searchMemories as ReturnType<typeof vi.fn>).mock.calls;
140
- const searchedPaths = searchCalls.map((c: unknown[]) => (c[1] as Record<string, unknown>).projectPath);
145
+ const searchedPaths = searchCalls.map(
146
+ (c: unknown[]) => (c[1] as Record<string, unknown>).projectPath,
147
+ );
141
148
  expect(searchedPaths).toContain('/test');
142
149
  expect(searchedPaths).toContain('/linked');
143
150
  expect(searchedPaths).toContain('/extra');
@@ -151,7 +158,8 @@ describe('createMemoryCrossProjectOps', () => {
151
158
  ]);
152
159
  ops = createMemoryCrossProjectOps(runtime);
153
160
  const result = (await findOp('memory_cross_project_search').handler({
154
- query: 'test', projectPath: '/test',
161
+ query: 'test',
162
+ projectPath: '/test',
155
163
  })) as Record<string, unknown>;
156
164
 
157
165
  // linkedMemories should be empty because m1 was already in current results
@@ -162,12 +170,15 @@ describe('createMemoryCrossProjectOps', () => {
162
170
  it('skips linked search when cross-project disabled', async () => {
163
171
  const runtime = makeMockRuntime();
164
172
  (runtime.projectRegistry.getByPath as ReturnType<typeof vi.fn>).mockReturnValue({
165
- id: 'proj-1', name: 'test', path: '/test',
173
+ id: 'proj-1',
174
+ name: 'test',
175
+ path: '/test',
166
176
  metadata: { memoryConfig: { crossProjectEnabled: false } },
167
177
  });
168
178
  ops = createMemoryCrossProjectOps(runtime);
169
179
  const result = (await findOp('memory_cross_project_search').handler({
170
- query: 'test', projectPath: '/test',
180
+ query: 'test',
181
+ projectPath: '/test',
171
182
  })) as Record<string, unknown>;
172
183
 
173
184
  expect(runtime.projectRegistry.getLinkedProjects).not.toHaveBeenCalled();
@@ -182,10 +182,7 @@ function buildHealthWarning(
182
182
  * Collect all acceptance criteria from a plan's tasks.
183
183
  * Returns empty array if plan not found or has no criteria (graceful skip).
184
184
  */
185
- function collectAcceptanceCriteria(
186
- plannerRef: AgentRuntime['planner'],
187
- planId: string,
188
- ): string[] {
185
+ function collectAcceptanceCriteria(plannerRef: AgentRuntime['planner'], planId: string): string[] {
189
186
  const plan = plannerRef.get(planId);
190
187
  if (!plan) return [];
191
188
  const criteria: string[] = [];
@@ -210,7 +207,8 @@ function captureRationalizationAntiPattern(
210
207
  vaultRef.add({
211
208
  id: `antipattern-rationalization-${Date.now()}`,
212
209
  title: 'Rationalization detected in completion claim',
213
- description: `Detected rationalization patterns: ${patterns}. ` +
210
+ description:
211
+ `Detected rationalization patterns: ${patterns}. ` +
214
212
  `Items: ${report.items.map((i) => `"${i.phrase}" (${i.pattern})`).join('; ')}.`,
215
213
  type: 'anti-pattern',
216
214
  domain: 'planning',
@@ -247,7 +245,10 @@ export function createOrchestrateOps(
247
245
  'a pruned orchestration plan with gate-guarded steps.',
248
246
  auth: 'write',
249
247
  schema: z.object({
250
- prompt: z.string().optional().describe('Natural language description of what to do (or use objective)'),
248
+ prompt: z
249
+ .string()
250
+ .optional()
251
+ .describe('Natural language description of what to do (or use objective)'),
251
252
  projectPath: z.string().optional().default('.').describe('Project root path'),
252
253
  // Legacy params — still accepted for backward compat
253
254
  objective: z.string().optional().describe('(Legacy) Plan objective — use prompt instead'),
@@ -277,9 +278,10 @@ export function createOrchestrateOps(
277
278
  recommendations = raw.map((r) => {
278
279
  // Look up vault entry ID by title for feedback tracking
279
280
  const entries = vault.search(r.pattern, { limit: 1 });
280
- const entryId = entries.length > 0 && entries[0].entry.title === r.pattern
281
- ? entries[0].entry.id
282
- : undefined;
281
+ const entryId =
282
+ entries.length > 0 && entries[0].entry.title === r.pattern
283
+ ? entries[0].entry.id
284
+ : undefined;
283
285
  return { pattern: r.pattern, strength: r.strength, entryId };
284
286
  });
285
287
  } catch {
@@ -307,12 +309,10 @@ export function createOrchestrateOps(
307
309
  planStore.set(plan.planId, { plan, createdAt: Date.now() });
308
310
 
309
311
  // 5. Also create a planner plan for lifecycle tracking (backward compat)
310
- const decisions = recommendations.map(
311
- (r) => {
312
- const base = `Brain pattern: ${r.pattern} (strength: ${r.strength.toFixed(1)})`;
313
- return r.entryId ? `${base} [entryId:${r.entryId}]` : base;
314
- },
315
- );
312
+ const decisions = recommendations.map((r) => {
313
+ const base = `Brain pattern: ${r.pattern} (strength: ${r.strength.toFixed(1)})`;
314
+ return r.entryId ? `${base} [entryId:${r.entryId}]` : base;
315
+ });
316
316
  const tasks = (params.tasks as Array<{ title: string; description: string }>) ?? [];
317
317
 
318
318
  // 5b. Extract GitHub issue context if prompt references #NNN
@@ -333,7 +333,8 @@ export function createOrchestrateOps(
333
333
  }
334
334
  }
335
335
 
336
- const planObjective = (params as Record<string, unknown>)._enrichedObjective as string | undefined ?? prompt;
336
+ const planObjective =
337
+ ((params as Record<string, unknown>)._enrichedObjective as string | undefined) ?? prompt;
337
338
 
338
339
  let legacyPlan;
339
340
  try {
@@ -478,11 +479,21 @@ export function createOrchestrateOps(
478
479
  .optional()
479
480
  .default('completed')
480
481
  .describe('Plan outcome'),
481
- summary: z.string().optional().describe('Completion summary — checked for rationalization language'),
482
+ summary: z
483
+ .string()
484
+ .optional()
485
+ .describe('Completion summary — checked for rationalization language'),
482
486
  toolsUsed: z.array(z.string()).optional().describe('Tools used during execution'),
483
487
  filesModified: z.array(z.string()).optional().describe('Files modified during execution'),
484
- projectPath: z.string().optional().default('.').describe('Project root path for impact analysis'),
485
- overrideRationalization: z.boolean().optional().default(false)
488
+ projectPath: z
489
+ .string()
490
+ .optional()
491
+ .default('.')
492
+ .describe('Project root path for impact analysis'),
493
+ overrideRationalization: z
494
+ .boolean()
495
+ .optional()
496
+ .default(false)
486
497
  .describe('Set true to bypass rationalization gate and impact warnings after review'),
487
498
  }),
488
499
  handler: async (params) => {
@@ -517,9 +528,7 @@ export function createOrchestrateOps(
517
528
  try {
518
529
  const analyzer = new ImpactAnalyzer();
519
530
  const planObj = planner.get(planId);
520
- const scopeHints = planObj?.scope
521
- ? [planObj.scope]
522
- : undefined;
531
+ const scopeHints = planObj?.scope ? [planObj.scope] : undefined;
523
532
  impactReport = analyzer.analyzeImpact(
524
533
  filesModified,
525
534
  (params.projectPath as string) ?? '.',
@@ -710,11 +719,22 @@ export function createOrchestrateOps(
710
719
  auth: 'write',
711
720
  schema: z.object({
712
721
  planId: z.string().describe('ID of the plan to project to GitHub'),
713
- projectPath: z.string().optional().default('.').describe('Project root path for git detection'),
722
+ projectPath: z
723
+ .string()
724
+ .optional()
725
+ .default('.')
726
+ .describe('Project root path for git detection'),
714
727
  milestone: z.number().optional().describe('GitHub milestone number to assign issues to'),
715
728
  labels: z.array(z.string()).optional().describe('Labels to apply to created issues'),
716
- linkToIssue: z.number().optional().describe('Existing issue number to link plan to instead of creating new issues'),
717
- dryRun: z.boolean().optional().default(false).describe('Preview what would be created without actually creating issues'),
729
+ linkToIssue: z
730
+ .number()
731
+ .optional()
732
+ .describe('Existing issue number to link plan to instead of creating new issues'),
733
+ dryRun: z
734
+ .boolean()
735
+ .optional()
736
+ .default(false)
737
+ .describe('Preview what would be created without actually creating issues'),
718
738
  }),
719
739
  handler: async (params) => {
720
740
  const planId = params.planId as string;
@@ -729,7 +749,9 @@ export function createOrchestrateOps(
729
749
  if (!plan) throw new Error(`Plan not found: ${planId}`);
730
750
 
731
751
  if (plan.tasks.length === 0) {
732
- throw new Error('Plan has no tasks — run plan_split first to define tasks before projecting to GitHub');
752
+ throw new Error(
753
+ 'Plan has no tasks — run plan_split first to define tasks before projecting to GitHub',
754
+ );
733
755
  }
734
756
 
735
757
  // 2. Detect GitHub context
@@ -807,7 +829,12 @@ export function createOrchestrateOps(
807
829
 
808
830
  // 6. Create issues per task (with duplicate detection)
809
831
  const created: Array<{ taskId: string; issueNumber: number; title: string }> = [];
810
- const skipped: Array<{ taskId: string; title: string; existingIssue: number; reason: string }> = [];
832
+ const skipped: Array<{
833
+ taskId: string;
834
+ title: string;
835
+ existingIssue: number;
836
+ reason: string;
837
+ }> = [];
811
838
  const failed: Array<{ taskId: string; title: string; reason: string }> = [];
812
839
 
813
840
  for (const task of plan.tasks) {
@@ -54,7 +54,10 @@ describe('createPackOps', () => {
54
54
  runtime = makeMockRuntime();
55
55
  ops = createPackOps(runtime);
56
56
  expect(ops.map((o) => o.name)).toEqual([
57
- 'pack_validate', 'pack_install', 'pack_list', 'pack_uninstall',
57
+ 'pack_validate',
58
+ 'pack_install',
59
+ 'pack_list',
60
+ 'pack_uninstall',
58
61
  ]);
59
62
  });
60
63
 
@@ -91,7 +94,10 @@ describe('createPackOps', () => {
91
94
  const hotRegister = vi.fn();
92
95
  setHotRegister(hotRegister);
93
96
  ops = createPackOps(runtime);
94
- const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<string, unknown>;
97
+ const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<
98
+ string,
99
+ unknown
100
+ >;
95
101
  expect(hotRegister).toHaveBeenCalledWith('test-agent_design', 'Design facade', []);
96
102
  expect(result.hotReloaded).toBe(true);
97
103
  });
@@ -99,14 +105,19 @@ describe('createPackOps', () => {
99
105
  it('skips hot-register when no callback set', async () => {
100
106
  runtime = makeMockRuntime();
101
107
  ops = createPackOps(runtime);
102
- const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<string, unknown>;
108
+ const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<
109
+ string,
110
+ unknown
111
+ >;
103
112
  expect(result.hotReloaded).toBeUndefined();
104
113
  });
105
114
 
106
115
  it('skips hot-register when no facades', async () => {
107
116
  runtime = makeMockRuntime();
108
117
  (runtime.packInstaller.install as ReturnType<typeof vi.fn>).mockResolvedValue({
109
- installed: true, id: 'pack-1', facades: 0,
118
+ installed: true,
119
+ id: 'pack-1',
120
+ facades: 0,
110
121
  });
111
122
  const hotRegister = vi.fn();
112
123
  setHotRegister(hotRegister);
@@ -142,7 +153,10 @@ describe('createPackOps', () => {
142
153
  it('uninstalls a pack', async () => {
143
154
  runtime = makeMockRuntime();
144
155
  ops = createPackOps(runtime);
145
- const result = (await findOp('pack_uninstall').handler({ packId: 'pack-1' })) as Record<string, unknown>;
156
+ const result = (await findOp('pack_uninstall').handler({ packId: 'pack-1' })) as Record<
157
+ string,
158
+ unknown
159
+ >;
146
160
  expect(result.uninstalled).toBe(true);
147
161
  expect(result.id).toBe('pack-1');
148
162
  });
@@ -151,7 +165,10 @@ describe('createPackOps', () => {
151
165
  runtime = makeMockRuntime();
152
166
  (runtime.packInstaller.uninstall as ReturnType<typeof vi.fn>).mockReturnValue(false);
153
167
  ops = createPackOps(runtime);
154
- const result = (await findOp('pack_uninstall').handler({ packId: 'missing' })) as Record<string, unknown>;
168
+ const result = (await findOp('pack_uninstall').handler({ packId: 'missing' })) as Record<
169
+ string,
170
+ unknown
171
+ >;
155
172
  expect(result.error).toContain('Pack not found');
156
173
  });
157
174
  });
@@ -70,11 +70,17 @@ function createMockRuntime(): AgentRuntime {
70
70
  return {
71
71
  planner: {
72
72
  iterate: vi.fn(() => plan),
73
- splitTasks: vi.fn(() => ({ ...plan, tasks: [plan.tasks[0], { id: 'task-2', title: 'Task 2' }] })),
73
+ splitTasks: vi.fn(() => ({
74
+ ...plan,
75
+ tasks: [plan.tasks[0], { id: 'task-2', title: 'Task 2' }],
76
+ })),
74
77
  reconcile: vi.fn(() => ({
75
78
  ...plan,
76
79
  status: 'reconciling',
77
- reconciliation: { accuracy: 85, driftItems: [{ type: 'added', description: 'Extra test' }] },
80
+ reconciliation: {
81
+ accuracy: 85,
82
+ driftItems: [{ type: 'added', description: 'Extra test' }],
83
+ },
78
84
  })),
79
85
  get: vi.fn(() => plan),
80
86
  getDispatch: vi.fn(() => ({ task: plan.tasks[0], ready: true, unmetDeps: [] })),
@@ -147,14 +153,20 @@ describe('createPlanningExtraOps', () => {
147
153
  objective: 'New objective',
148
154
  })) as Record<string, unknown>;
149
155
  expect(result.iterated).toBe(true);
150
- expect(runtime.planner.iterate).toHaveBeenCalledWith('plan-1', expect.objectContaining({ objective: 'New objective' }));
156
+ expect(runtime.planner.iterate).toHaveBeenCalledWith(
157
+ 'plan-1',
158
+ expect.objectContaining({ objective: 'New objective' }),
159
+ );
151
160
  });
152
161
 
153
162
  it('returns error on failure', async () => {
154
163
  vi.mocked(runtime.planner.iterate).mockImplementation(() => {
155
164
  throw new Error('Not a draft');
156
165
  });
157
- const result = (await findOp(ops, 'plan_iterate').handler({ planId: 'x' })) as Record<string, unknown>;
166
+ const result = (await findOp(ops, 'plan_iterate').handler({ planId: 'x' })) as Record<
167
+ string,
168
+ unknown
169
+ >;
158
170
  expect(result.error).toBe('Not a draft');
159
171
  });
160
172
  });
@@ -569,9 +581,7 @@ describe('createPlanningExtraOps', () => {
569
581
  });
570
582
 
571
583
  it('purges specific plans by ID', async () => {
572
- vi.mocked(runtime.planner.list).mockReturnValue([
573
- makePlan({ id: 'plan-1' }),
574
- ] as unknown);
584
+ vi.mocked(runtime.planner.list).mockReturnValue([makePlan({ id: 'plan-1' })] as unknown);
575
585
  const result = (await findOp(ops, 'plan_purge').handler({
576
586
  mode: 'specific',
577
587
  planIds: ['plan-1'],
@@ -46,7 +46,9 @@ export function createPlanningExtraOps(runtime: AgentRuntime): OpDefinition[] {
46
46
  decisions: z
47
47
  .array(z.union([z.string(), z.object({ decision: z.string(), rationale: z.string() })]))
48
48
  .optional()
49
- .describe('New decisions list (replaces existing) — strings or {decision, rationale} objects'),
49
+ .describe(
50
+ 'New decisions list (replaces existing) — strings or {decision, rationale} objects',
51
+ ),
50
52
  addTasks: z
51
53
  .array(z.object({ title: z.string(), description: z.string() }))
52
54
  .optional()
@@ -9,7 +9,19 @@ import type { AgentRuntime } from './types.js';
9
9
 
10
10
  /** Minimal vault stub that stores entries in memory. */
11
11
  function makeVaultStub() {
12
- const entries = new Map<string, { id: string; type: string; domain?: string; title: string; description: string; context?: string; tags?: string[]; severity?: string }>();
12
+ const entries = new Map<
13
+ string,
14
+ {
15
+ id: string;
16
+ type: string;
17
+ domain?: string;
18
+ title: string;
19
+ description: string;
20
+ context?: string;
21
+ tags?: string[];
22
+ severity?: string;
23
+ }
24
+ >();
13
25
  return {
14
26
  list: (opts: { type?: string; domain?: string; limit?: number }) => {
15
27
  let arr = [...entries.values()];
@@ -18,7 +30,16 @@ function makeVaultStub() {
18
30
  return arr.slice(0, opts.limit ?? 50);
19
31
  },
20
32
  get: (id: string) => entries.get(id) ?? null,
21
- add: (entry: { id: string; type: string; title: string; description: string; domain?: string; context?: string; tags?: string[]; severity?: string }) => {
33
+ add: (entry: {
34
+ id: string;
35
+ type: string;
36
+ title: string;
37
+ description: string;
38
+ domain?: string;
39
+ context?: string;
40
+ tags?: string[];
41
+ severity?: string;
42
+ }) => {
22
43
  entries.set(entry.id, entry);
23
44
  },
24
45
  _entries: entries,
@@ -77,7 +98,9 @@ describe('playbook-ops', () => {
77
98
  domain: 'testing',
78
99
  title: 'TDD Workflow',
79
100
  description: 'Test-driven development playbook',
80
- context: JSON.stringify({ steps: [{ order: 1, title: 'Write test', description: 'Write failing test' }] }),
101
+ context: JSON.stringify({
102
+ steps: [{ order: 1, title: 'Write test', description: 'Write failing test' }],
103
+ }),
81
104
  tags: ['tdd'],
82
105
  });
83
106
 
@@ -10,17 +10,28 @@ import type { OpDefinition } from '../facades/types.js';
10
10
 
11
11
  /** Minimal plugin registry stub. */
12
12
  function makePluginRegistryStub() {
13
- const plugins = new Map<string, {
14
- id: string;
15
- manifest: { id: string; name: string; version: string; domain: string; description: string; dependencies: string[]; intelligence: unknown[] };
16
- status: string;
17
- provenance: string;
18
- directory: string;
19
- error?: string;
20
- facades: Array<{ name: string; description: string; ops: OpDefinition[] }>;
21
- registeredAt: number;
22
- activatedAt?: number;
23
- }>();
13
+ const plugins = new Map<
14
+ string,
15
+ {
16
+ id: string;
17
+ manifest: {
18
+ id: string;
19
+ name: string;
20
+ version: string;
21
+ domain: string;
22
+ description: string;
23
+ dependencies: string[];
24
+ intelligence: unknown[];
25
+ };
26
+ status: string;
27
+ provenance: string;
28
+ directory: string;
29
+ error?: string;
30
+ facades: Array<{ name: string; description: string; ops: OpDefinition[] }>;
31
+ registeredAt: number;
32
+ activatedAt?: number;
33
+ }
34
+ >();
24
35
 
25
36
  return {
26
37
  get: (id: string) => plugins.get(id) ?? null,
@@ -43,10 +54,24 @@ function makePluginRegistryStub() {
43
54
  plugin.status = 'registered';
44
55
  return true;
45
56
  }),
46
- _seed: (id: string, overrides?: Partial<{ status: string; facades: Array<{ name: string; description: string; ops: OpDefinition[] }> }>) => {
57
+ _seed: (
58
+ id: string,
59
+ overrides?: Partial<{
60
+ status: string;
61
+ facades: Array<{ name: string; description: string; ops: OpDefinition[] }>;
62
+ }>,
63
+ ) => {
47
64
  plugins.set(id, {
48
65
  id,
49
- manifest: { id, name: `Plugin ${id}`, version: '1.0.0', domain: 'test', description: 'Test plugin', dependencies: [], intelligence: [] },
66
+ manifest: {
67
+ id,
68
+ name: `Plugin ${id}`,
69
+ version: '1.0.0',
70
+ domain: 'test',
71
+ description: 'Test plugin',
72
+ dependencies: [],
73
+ intelligence: [],
74
+ },
50
75
  status: overrides?.status ?? 'registered',
51
76
  provenance: 'local',
52
77
  directory: `/plugins/${id}`,
@@ -63,10 +88,7 @@ describe('plugin-ops', () => {
63
88
  const config = { agentId: 'test-agent' };
64
89
  const opSink = opts?.opSink;
65
90
  const ops = captureOps(
66
- createPluginOps(
67
- { pluginRegistry, config } as unknown as AgentRuntime,
68
- opSink,
69
- ),
91
+ createPluginOps({ pluginRegistry, config } as unknown as AgentRuntime, opSink),
70
92
  );
71
93
  return { pluginRegistry, ops, opSink };
72
94
  }
@@ -83,11 +105,24 @@ describe('plugin-ops', () => {
83
105
 
84
106
  it('lists registered plugins with status', async () => {
85
107
  const { ops, pluginRegistry } = setup();
86
- pluginRegistry._seed('plug-a', { status: 'active', facades: [{ name: 'f1', description: 'F1', ops: [{ name: 'op1', handler: async () => ({}), auth: 'read', description: '' }] }] });
108
+ pluginRegistry._seed('plug-a', {
109
+ status: 'active',
110
+ facades: [
111
+ {
112
+ name: 'f1',
113
+ description: 'F1',
114
+ ops: [{ name: 'op1', handler: async () => ({}), auth: 'read', description: '' }],
115
+ },
116
+ ],
117
+ });
87
118
  pluginRegistry._seed('plug-b', { status: 'registered' });
88
119
 
89
120
  const res = await executeOp(ops, 'plugin_list');
90
- const data = res.data as { count: number; active: number; plugins: Array<{ id: string; status: string; facades: number; ops: number }> };
121
+ const data = res.data as {
122
+ count: number;
123
+ active: number;
124
+ plugins: Array<{ id: string; status: string; facades: number; ops: number }>;
125
+ };
91
126
  expect(data.count).toBe(2);
92
127
  expect(data.active).toBe(1);
93
128
  expect(data.plugins[0].facades).toBe(1);
@@ -108,7 +143,13 @@ describe('plugin-ops', () => {
108
143
  pluginRegistry._seed('my-plug');
109
144
 
110
145
  const res = await executeOp(ops, 'plugin_status', { pluginId: 'my-plug' });
111
- const data = res.data as { id: string; name: string; version: string; status: string; directory: string };
146
+ const data = res.data as {
147
+ id: string;
148
+ name: string;
149
+ version: string;
150
+ status: string;
151
+ directory: string;
152
+ };
112
153
  expect(data.id).toBe('my-plug');
113
154
  expect(data.version).toBe('1.0.0');
114
155
  expect(data.directory).toBe('/plugins/my-plug');
@@ -140,7 +181,10 @@ describe('plugin-ops', () => {
140
181
  pluginRegistry._seed('p2', { status: 'registered', facades: [] });
141
182
 
142
183
  const res = await executeOp(ops, 'plugin_activate', {});
143
- const data = res.data as { activated: number; results: Array<{ id: string; status: string }> };
184
+ const data = res.data as {
185
+ activated: number;
186
+ results: Array<{ id: string; status: string }>;
187
+ };
144
188
  expect(data.activated).toBe(2);
145
189
  expect(data.results).toHaveLength(2);
146
190
  });
@@ -148,8 +192,15 @@ describe('plugin-ops', () => {
148
192
  it('injects plugin ops into opSink on activation', async () => {
149
193
  const opSink: OpDefinition[] = [];
150
194
  const { ops, pluginRegistry } = setup({ opSink });
151
- const testOp: OpDefinition = { name: 'injected_op', handler: async () => 'hi', auth: 'read', description: 'test' };
152
- pluginRegistry._seed('plug-inject', { facades: [{ name: 'test-facade', description: 'TF', ops: [testOp] }] });
195
+ const testOp: OpDefinition = {
196
+ name: 'injected_op',
197
+ handler: async () => 'hi',
198
+ auth: 'read',
199
+ description: 'test',
200
+ };
201
+ pluginRegistry._seed('plug-inject', {
202
+ facades: [{ name: 'test-facade', description: 'TF', ops: [testOp] }],
203
+ });
153
204
 
154
205
  await executeOp(ops, 'plugin_activate', { pluginId: 'plug-inject' });
155
206
  expect(opSink.some((o) => o.name === 'injected_op')).toBe(true);
@@ -177,8 +228,15 @@ describe('plugin-ops', () => {
177
228
  it('removes injected ops from opSink on deactivation', async () => {
178
229
  const opSink: OpDefinition[] = [];
179
230
  const { ops, pluginRegistry } = setup({ opSink });
180
- const testOp: OpDefinition = { name: 'to_remove', handler: async () => 'hi', auth: 'read', description: 'test' };
181
- pluginRegistry._seed('plug-rm', { facades: [{ name: 'f', description: 'F', ops: [testOp] }] });
231
+ const testOp: OpDefinition = {
232
+ name: 'to_remove',
233
+ handler: async () => 'hi',
234
+ auth: 'read',
235
+ description: 'test',
236
+ };
237
+ pluginRegistry._seed('plug-rm', {
238
+ facades: [{ name: 'f', description: 'F', ops: [testOp] }],
239
+ });
182
240
 
183
241
  await executeOp(ops, 'plugin_activate', { pluginId: 'plug-rm' });
184
242
  expect(opSink.some((o) => o.name === 'to_remove')).toBe(true);