@enfyra/mcp-server 0.1.69 → 0.1.71

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 (248) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/config-local-adapters.d.ts +18 -0
  3. package/dist/lib/config-local-adapters.js +271 -0
  4. package/dist/lib/config-local-adapters.js.map +1 -0
  5. package/dist/lib/config-local-contracts.d.ts +28 -0
  6. package/dist/lib/config-local-contracts.js +200 -0
  7. package/dist/lib/config-local-contracts.js.map +1 -0
  8. package/dist/lib/config-local-prompts.d.ts +10 -0
  9. package/dist/lib/config-local-prompts.js +185 -0
  10. package/dist/lib/config-local-prompts.js.map +1 -0
  11. package/dist/lib/config-local-types.d.ts +23 -0
  12. package/dist/lib/config-local-types.js +2 -0
  13. package/dist/lib/config-local-types.js.map +1 -0
  14. package/dist/lib/config-local.js +3 -649
  15. package/dist/lib/config-local.js.map +1 -1
  16. package/dist/lib/discovery-tools.d.ts +4 -0
  17. package/dist/lib/discovery-tools.js +546 -0
  18. package/dist/lib/discovery-tools.js.map +1 -0
  19. package/dist/lib/dynamic-repository-builder.d.ts +1 -1
  20. package/dist/lib/dynamic-script-context-contract.d.ts +100 -0
  21. package/dist/lib/dynamic-script-context-contract.js +163 -0
  22. package/dist/lib/dynamic-script-context-contract.js.map +1 -0
  23. package/dist/lib/enfyra-mcp-server.d.ts +3 -0
  24. package/dist/lib/enfyra-mcp-server.js +79 -0
  25. package/dist/lib/enfyra-mcp-server.js.map +1 -0
  26. package/dist/lib/enfyra-tool-logic.d.ts +7 -0
  27. package/dist/lib/enfyra-tool-logic.js +8 -0
  28. package/dist/lib/enfyra-tool-logic.js.map +1 -0
  29. package/dist/lib/enfyra-tool-types.d.ts +27 -0
  30. package/dist/lib/enfyra-tool-types.js +2 -0
  31. package/dist/lib/enfyra-tool-types.js.map +1 -0
  32. package/dist/lib/extension-api-builders.d.ts +17 -0
  33. package/dist/lib/extension-api-builders.js +235 -0
  34. package/dist/lib/extension-api-builders.js.map +1 -0
  35. package/dist/lib/extension-component-builders.d.ts +87 -0
  36. package/dist/lib/extension-component-builders.js +623 -0
  37. package/dist/lib/extension-component-builders.js.map +1 -0
  38. package/dist/lib/extension-contract-review.d.ts +26 -0
  39. package/dist/lib/extension-contract-review.js +187 -0
  40. package/dist/lib/extension-contract-review.js.map +1 -0
  41. package/dist/lib/extension-theme-contract.d.ts +63 -0
  42. package/dist/lib/extension-theme-contract.js +417 -0
  43. package/dist/lib/extension-theme-contract.js.map +1 -0
  44. package/dist/lib/identity-tools.d.ts +4 -0
  45. package/dist/lib/identity-tools.js +46 -0
  46. package/dist/lib/identity-tools.js.map +1 -0
  47. package/dist/lib/log-tools.d.ts +4 -0
  48. package/dist/lib/log-tools.js +65 -0
  49. package/dist/lib/log-tools.js.map +1 -0
  50. package/dist/lib/mcp-example-connect.d.ts +9 -0
  51. package/dist/lib/mcp-example-connect.js +442 -0
  52. package/dist/lib/mcp-example-connect.js.map +1 -0
  53. package/dist/lib/mcp-example-extensions.d.ts +9 -0
  54. package/dist/lib/mcp-example-extensions.js +729 -0
  55. package/dist/lib/mcp-example-extensions.js.map +1 -0
  56. package/dist/lib/mcp-example-files.d.ts +9 -0
  57. package/dist/lib/mcp-example-files.js +51 -0
  58. package/dist/lib/mcp-example-files.js.map +1 -0
  59. package/dist/lib/mcp-example-flows.d.ts +9 -0
  60. package/dist/lib/mcp-example-flows.js +76 -0
  61. package/dist/lib/mcp-example-flows.js.map +1 -0
  62. package/dist/lib/mcp-example-graphql.d.ts +9 -0
  63. package/dist/lib/mcp-example-graphql.js +57 -0
  64. package/dist/lib/mcp-example-graphql.js.map +1 -0
  65. package/dist/lib/mcp-example-handlers-hooks.d.ts +9 -0
  66. package/dist/lib/mcp-example-handlers-hooks.js +328 -0
  67. package/dist/lib/mcp-example-handlers-hooks.js.map +1 -0
  68. package/dist/lib/mcp-example-oauth-setup.d.ts +9 -0
  69. package/dist/lib/mcp-example-oauth-setup.js +41 -0
  70. package/dist/lib/mcp-example-oauth-setup.js.map +1 -0
  71. package/dist/lib/mcp-example-permissions-rls.d.ts +9 -0
  72. package/dist/lib/mcp-example-permissions-rls.js +210 -0
  73. package/dist/lib/mcp-example-permissions-rls.js.map +1 -0
  74. package/dist/lib/mcp-example-queries-deep.d.ts +9 -0
  75. package/dist/lib/mcp-example-queries-deep.js +220 -0
  76. package/dist/lib/mcp-example-queries-deep.js.map +1 -0
  77. package/dist/lib/mcp-example-schema-relations.d.ts +9 -0
  78. package/dist/lib/mcp-example-schema-relations.js +148 -0
  79. package/dist/lib/mcp-example-schema-relations.js.map +1 -0
  80. package/dist/lib/mcp-example-websocket.d.ts +9 -0
  81. package/dist/lib/mcp-example-websocket.js +103 -0
  82. package/dist/lib/mcp-example-websocket.js.map +1 -0
  83. package/dist/lib/mcp-examples.d.ts +5 -5
  84. package/dist/lib/mcp-examples.js +22 -2394
  85. package/dist/lib/mcp-examples.js.map +1 -1
  86. package/dist/lib/method-tools.d.ts +4 -0
  87. package/dist/lib/method-tools.js +217 -0
  88. package/dist/lib/method-tools.js.map +1 -0
  89. package/dist/lib/package-tools.d.ts +4 -0
  90. package/dist/lib/package-tools.js +98 -0
  91. package/dist/lib/package-tools.js.map +1 -0
  92. package/dist/lib/platform-data-operations.d.ts +24 -0
  93. package/dist/lib/platform-data-operations.js +71 -0
  94. package/dist/lib/platform-data-operations.js.map +1 -0
  95. package/dist/lib/platform-endpoint-workflow.d.ts +42 -0
  96. package/dist/lib/platform-endpoint-workflow.js +382 -0
  97. package/dist/lib/platform-endpoint-workflow.js.map +1 -0
  98. package/dist/lib/platform-extension-source.d.ts +487 -0
  99. package/dist/lib/platform-extension-source.js +524 -0
  100. package/dist/lib/platform-extension-source.js.map +1 -0
  101. package/dist/lib/platform-extension-tools.d.ts +1 -0
  102. package/dist/lib/platform-extension-tools.js +416 -0
  103. package/dist/lib/platform-extension-tools.js.map +1 -0
  104. package/dist/lib/platform-extension-ui.d.ts +4 -0
  105. package/dist/lib/platform-extension-ui.js +5 -0
  106. package/dist/lib/platform-extension-ui.js.map +1 -0
  107. package/dist/lib/platform-extension-workflow.d.ts +54 -0
  108. package/dist/lib/platform-extension-workflow.js +194 -0
  109. package/dist/lib/platform-extension-workflow.js.map +1 -0
  110. package/dist/lib/platform-flow-operations.d.ts +554 -0
  111. package/dist/lib/platform-flow-operations.js +317 -0
  112. package/dist/lib/platform-flow-operations.js.map +1 -0
  113. package/dist/lib/platform-flow-tools.d.ts +1 -0
  114. package/dist/lib/platform-flow-tools.js +248 -0
  115. package/dist/lib/platform-flow-tools.js.map +1 -0
  116. package/dist/lib/platform-operation-logic.d.ts +10 -0
  117. package/dist/lib/platform-operation-logic.js +11 -0
  118. package/dist/lib/platform-operation-logic.js.map +1 -0
  119. package/dist/lib/platform-operation-tools.d.ts +1 -324
  120. package/dist/lib/platform-operation-tools.js +13 -4620
  121. package/dist/lib/platform-operation-tools.js.map +1 -1
  122. package/dist/lib/platform-operation-types.d.ts +46 -0
  123. package/dist/lib/platform-operation-types.js +2 -0
  124. package/dist/lib/platform-operation-types.js.map +1 -0
  125. package/dist/lib/platform-policy-tools.d.ts +1 -0
  126. package/dist/lib/platform-policy-tools.js +248 -0
  127. package/dist/lib/platform-policy-tools.js.map +1 -0
  128. package/dist/lib/platform-resource-operations.d.ts +124 -0
  129. package/dist/lib/platform-resource-operations.js +109 -0
  130. package/dist/lib/platform-resource-operations.js.map +1 -0
  131. package/dist/lib/platform-resource-tools.d.ts +1 -0
  132. package/dist/lib/platform-resource-tools.js +70 -0
  133. package/dist/lib/platform-resource-tools.js.map +1 -0
  134. package/dist/lib/platform-route-operations.d.ts +222 -0
  135. package/dist/lib/platform-route-operations.js +290 -0
  136. package/dist/lib/platform-route-operations.js.map +1 -0
  137. package/dist/lib/platform-route-tools.d.ts +1 -0
  138. package/dist/lib/platform-route-tools.js +307 -0
  139. package/dist/lib/platform-route-tools.js.map +1 -0
  140. package/dist/lib/platform-shared-operations.d.ts +7 -0
  141. package/dist/lib/platform-shared-operations.js +4 -0
  142. package/dist/lib/platform-shared-operations.js.map +1 -0
  143. package/dist/lib/platform-websocket-tools.d.ts +1 -0
  144. package/dist/lib/platform-websocket-tools.js +70 -0
  145. package/dist/lib/platform-websocket-tools.js.map +1 -0
  146. package/dist/lib/record-tools.d.ts +4 -0
  147. package/dist/lib/record-tools.js +418 -0
  148. package/dist/lib/record-tools.js.map +1 -0
  149. package/dist/lib/required-knowledge.d.ts +1 -1
  150. package/dist/lib/required-knowledge.js +3 -2
  151. package/dist/lib/required-knowledge.js.map +1 -1
  152. package/dist/lib/route-access-tools.d.ts +4 -0
  153. package/dist/lib/route-access-tools.js +172 -0
  154. package/dist/lib/route-access-tools.js.map +1 -0
  155. package/dist/lib/route-definition-tools.d.ts +4 -0
  156. package/dist/lib/route-definition-tools.js +285 -0
  157. package/dist/lib/route-definition-tools.js.map +1 -0
  158. package/dist/lib/route-inspection-tools.d.ts +4 -0
  159. package/dist/lib/route-inspection-tools.js +319 -0
  160. package/dist/lib/route-inspection-tools.js.map +1 -0
  161. package/dist/lib/route-tools.d.ts +1 -0
  162. package/dist/lib/route-tools.js +9 -0
  163. package/dist/lib/route-tools.js.map +1 -0
  164. package/dist/lib/runtime-zone-registry.d.ts +27 -0
  165. package/dist/lib/runtime-zone-registry.js +81 -0
  166. package/dist/lib/runtime-zone-registry.js.map +1 -0
  167. package/dist/lib/runtime-zone-search.d.ts +303 -0
  168. package/dist/lib/runtime-zone-search.js +596 -0
  169. package/dist/lib/runtime-zone-search.js.map +1 -0
  170. package/dist/lib/runtime-zone-tools.d.ts +2 -307
  171. package/dist/lib/runtime-zone-tools.js +2 -674
  172. package/dist/lib/runtime-zone-tools.js.map +1 -1
  173. package/dist/lib/schema-column-tools.d.ts +3 -0
  174. package/dist/lib/schema-column-tools.js +80 -0
  175. package/dist/lib/schema-column-tools.js.map +1 -0
  176. package/dist/lib/schema-mutation-coordinator.d.ts +28 -0
  177. package/dist/lib/schema-mutation-coordinator.js +154 -0
  178. package/dist/lib/schema-mutation-coordinator.js.map +1 -0
  179. package/dist/lib/schema-relation-contracts.d.ts +39 -0
  180. package/dist/lib/schema-relation-contracts.js +160 -0
  181. package/dist/lib/schema-relation-contracts.js.map +1 -0
  182. package/dist/lib/schema-relation-tools.d.ts +3 -0
  183. package/dist/lib/schema-relation-tools.js +61 -0
  184. package/dist/lib/schema-relation-tools.js.map +1 -0
  185. package/dist/lib/schema-table-contracts.d.ts +28 -0
  186. package/dist/lib/schema-table-contracts.js +263 -0
  187. package/dist/lib/schema-table-contracts.js.map +1 -0
  188. package/dist/lib/schema-table-tools.d.ts +3 -0
  189. package/dist/lib/schema-table-tools.js +297 -0
  190. package/dist/lib/schema-table-tools.js.map +1 -0
  191. package/dist/lib/schema-tool-operations.d.ts +150 -0
  192. package/dist/lib/schema-tool-operations.js +468 -0
  193. package/dist/lib/schema-tool-operations.js.map +1 -0
  194. package/dist/lib/schema-tool-types.d.ts +38 -0
  195. package/dist/lib/schema-tool-types.js +2 -0
  196. package/dist/lib/schema-tool-types.js.map +1 -0
  197. package/dist/lib/schema-verification.d.ts +14 -0
  198. package/dist/lib/schema-verification.js +105 -0
  199. package/dist/lib/schema-verification.js.map +1 -0
  200. package/dist/lib/script-tools.d.ts +4 -0
  201. package/dist/lib/script-tools.js +127 -0
  202. package/dist/lib/script-tools.js.map +1 -0
  203. package/dist/lib/system-tools.d.ts +4 -0
  204. package/dist/lib/system-tools.js +41 -0
  205. package/dist/lib/system-tools.js.map +1 -0
  206. package/dist/lib/table-tool-logic.d.ts +5 -0
  207. package/dist/lib/table-tool-logic.js +6 -0
  208. package/dist/lib/table-tool-logic.js.map +1 -0
  209. package/dist/lib/table-tools.d.ts +1 -84
  210. package/dist/lib/table-tools.js +7 -1522
  211. package/dist/lib/table-tools.js.map +1 -1
  212. package/dist/lib/tool-catalog.d.ts +2 -1
  213. package/dist/lib/tool-catalog.js +23 -2
  214. package/dist/lib/tool-catalog.js.map +1 -1
  215. package/dist/lib/tool-metadata-operations.d.ts +27 -0
  216. package/dist/lib/tool-metadata-operations.js +93 -0
  217. package/dist/lib/tool-metadata-operations.js.map +1 -0
  218. package/dist/lib/tool-permission-profile.d.ts +37 -0
  219. package/dist/lib/tool-permission-profile.js +106 -0
  220. package/dist/lib/tool-permission-profile.js.map +1 -0
  221. package/dist/lib/tool-record-operations.d.ts +102 -0
  222. package/dist/lib/tool-record-operations.js +260 -0
  223. package/dist/lib/tool-record-operations.js.map +1 -0
  224. package/dist/lib/tool-route-inspection.d.ts +47 -0
  225. package/dist/lib/tool-route-inspection.js +168 -0
  226. package/dist/lib/tool-route-inspection.js.map +1 -0
  227. package/dist/lib/tool-routing.d.ts +3 -417
  228. package/dist/lib/tool-routing.js +3 -1038
  229. package/dist/lib/tool-routing.js.map +1 -1
  230. package/dist/lib/tool-runtime-config.d.ts +33 -0
  231. package/dist/lib/tool-runtime-config.js +237 -0
  232. package/dist/lib/tool-runtime-config.js.map +1 -0
  233. package/dist/lib/tool-script-operations.d.ts +34 -0
  234. package/dist/lib/tool-script-operations.js +153 -0
  235. package/dist/lib/tool-script-operations.js.map +1 -0
  236. package/dist/lib/workflow-definitions.d.ts +366 -0
  237. package/dist/lib/workflow-definitions.js +703 -0
  238. package/dist/lib/workflow-definitions.js.map +1 -0
  239. package/dist/lib/workflow-planner.d.ts +45 -0
  240. package/dist/lib/workflow-planner.js +338 -0
  241. package/dist/lib/workflow-planner.js.map +1 -0
  242. package/dist/lib/workflow-types.d.ts +39 -0
  243. package/dist/lib/workflow-types.js +2 -0
  244. package/dist/lib/workflow-types.js.map +1 -0
  245. package/dist/mcp-server-entry.d.ts +0 -3
  246. package/dist/mcp-server-entry.js +2 -3249
  247. package/dist/mcp-server-entry.js.map +1 -1
  248. package/package.json +1 -1
@@ -1,1039 +1,4 @@
1
- export const WORKFLOW_SURFACES = [
2
- 'api-endpoint',
3
- 'extension',
4
- 'schema',
5
- 'record-data',
6
- 'dynamic-script',
7
- 'route-access',
8
- 'guards-permissions-rules',
9
- 'flow',
10
- 'websocket',
11
- 'graphql',
12
- 'storage-file',
13
- 'oauth',
14
- 'identity-access',
15
- 'platform-config',
16
- 'package',
17
- 'cache',
18
- 'logs-debug',
19
- 'auth-context',
20
- ];
21
- const ALL_DETAILS = ['summary', 'plan', 'full'];
22
- export const WORKFLOW_SURFACES_BY_PROFILE = {
23
- extension: ['extension'],
24
- schema: ['schema', 'record-data'],
25
- runtime: ['api-endpoint', 'dynamic-script', 'route-access', 'guards-permissions-rules', 'flow', 'websocket', 'graphql'],
26
- operations: ['storage-file', 'oauth', 'identity-access', 'platform-config', 'package', 'cache', 'logs-debug', 'auth-context'],
27
- };
28
- export const TOOL_WORKFLOWS = [
29
- {
30
- key: 'api-endpoint',
31
- title: 'Custom REST endpoint with handler',
32
- useWhen: [
33
- 'Creating or changing a custom API path with handler behavior.',
34
- 'Changing public/private method access on a custom endpoint.',
35
- 'Adding route permissions for endpoint access.',
36
- 'Exposing a third-party or external integration contract whose policy must not change canonical table CRUD.',
37
- ],
38
- keywords: ['endpoint', 'api', 'route handler', 'handler', 'webhook', 'custom route', 'rest path', 'third-party api', 'third party api', 'external integration'],
39
- firstTools: ['get_enfyra_required_knowledge', 'discover_script_contexts', 'inspect_route'],
40
- inspectTools: ['inspect_route', 'get_all_routes', 'trace_metadata_usage'],
41
- knowledgeTools: ['get_enfyra_required_knowledge', 'discover_script_contexts'],
42
- writeTools: ['api_endpoint_workflow', 'create_api_endpoint', 'enable_route', 'public_route_methods', 'private_route_methods', 'ensure_route_access'],
43
- verifyTools: ['test_rest_endpoint', 'run_admin_test'],
44
- avoidTools: [
45
- {
46
- tool: 'create_route',
47
- when: 'a handler-backed endpoint or route permission plan is needed',
48
- useInstead: 'api_endpoint_workflow',
49
- reason: 'The workflow validates source, reads live route/handler/access state, applies one safe step at a time, and returns nextSteps.',
50
- },
51
- {
52
- tool: 'create_tables',
53
- when: 'the user asked for custom behavior at an API path',
54
- useInstead: 'api_endpoint_workflow',
55
- reason: 'Tables create persisted data models; custom route handlers own behavior endpoints.',
56
- },
57
- {
58
- tool: 'create_pre_hook',
59
- when: 'the requirement is third-party-only owner/tenant/business policy',
60
- useInstead: 'api_endpoint_workflow with policy in the handler',
61
- reason: 'A canonical route pre-hook affects every consumer of that canonical CRUD route, including eApp. Keep endpoint-specific policy inside the separate endpoint contract.',
62
- },
63
- ],
64
- requiredAck: ['globalRulesAckKey', 'dynamicCodeAckKey when saving handler source'],
65
- exampleCategories: ['handlers-hooks', 'permissions-rls'],
66
- nextStepTemplate: [
67
- 'For an ambiguous, high-risk, or approval-gated change, inspect the route or run api_endpoint_workflow with apply=false.',
68
- 'Read required knowledge before applying.',
69
- 'Use secure explicit repositories in custom handlers, inspect their live metadata, and keep TypeORM-style data: @BODY unless the business contract requires validation or server-owned field overrides.',
70
- 'For a fully specified non-destructive endpoint, use applyAll after the required narrow reads; otherwise apply one reviewed pending step.',
71
- 'Verify the endpoint with test_rest_endpoint or run_admin_test.',
72
- ],
73
- recommendedScope: 'dynamic-code',
74
- },
75
- {
76
- key: 'extension',
77
- title: 'Admin extension, menu, shell notification, or account panel UI',
78
- useWhen: [
79
- 'Creating or changing Enfyra admin page/widget/global extensions.',
80
- 'Adding menu entries, menu notification dots/counts, account panel rows, or shell actions.',
81
- 'Reviewing extension UI theme/layout/component usage.',
82
- ],
83
- keywords: ['extension', 'menu', 'account panel', 'notification', 'chip', 'badge', 'sidebar', 'shell', 'page ui', 'widget'],
84
- firstTools: ['get_enfyra_required_knowledge', 'get_extension_theme_contract', 'search_admin_extensions'],
85
- inspectTools: ['search_admin_extensions(mode=search)', 'search_admin_extensions(mode=inspect)', 'search_runtime_zone(mode=search, zone=admin_ui)'],
86
- knowledgeTools: ['get_enfyra_required_knowledge', 'get_extension_theme_contract', 'build_extension_ui'],
87
- writeTools: ['extension_workflow', 'ensure_menu', 'reorder_menus', 'patch_extension_code', 'update_extension_code', 'ensure_page_extension', 'ensure_global_extension', 'ensure_widget_extension', 'delete_records'],
88
- verifyTools: ['verify_extension_runtime', 'build_extension_ui(kind=runtime_review|theme_review|review)', 'search_admin_extensions(mode=search)', 'search_runtime_zone(mode=search, zone=admin_ui)'],
89
- avoidTools: [
90
- {
91
- tool: 'create_records/update_records on enfyra_extension',
92
- when: 'creating or changing extension code',
93
- useInstead: 'update_extension_code for an existing extension id/name, or extension_workflow/ensure_*_extension for create/wire flows',
94
- reason: 'Extension operation tools validate local guards plus /enfyra_extension/preview and save only after validation succeeds.',
95
- },
96
- {
97
- tool: 'query_table on destination domain lists',
98
- when: 'decorating menu/account panel notifications',
99
- useInstead: 'notification summary/realtime shell signal plus destination-page fetch on click',
100
- reason: 'Shell notifications should not fetch messages, tickets, orders, or jobs lists solely for a badge.',
101
- },
102
- {
103
- tool: 'update_records/PATCH enfyra_menu for order or parent changes',
104
- when: 'drag-and-drop or programmatic menu ordering changes sibling order or parent',
105
- useInstead: 'reorder_menus',
106
- reason: 'The Enfyra 2.2.6 /admin/menu/reorder route validates menu hierarchy constraints and emits menu cache invalidation.',
107
- },
108
- ],
109
- requiredAck: ['globalRulesAckKey', 'extensionAckKey when saving extension code'],
110
- exampleCategories: ['extensions'],
111
- nextStepTemplate: [
112
- 'Call get_extension_theme_contract before writing or reviewing UI.',
113
- 'Use search_admin_extensions to locate the existing menu/extension/global shell registration, then inspect one candidate before editing.',
114
- 'Use extension_workflow with apply=false only when page/menu wiring is ambiguous or needs approval; use applyAll after narrow inspection when the requested create/wire contract is fully specified.',
115
- 'Use reorder_menus for menu order/parent changes instead of patching individual enfyra_menu records.',
116
- 'For temporary extension cleanup, inspect the exact extension id, preview delete_records on enfyra_extension with confirm=false, repeat with confirm=true, then verify absence with search_admin_extensions.',
117
- 'Choose count only when the source already owns an exact count; choose dot/chip for new-attention signals.',
118
- 'Validate extension code or use an ensure_*_extension tool that validates before saving.',
119
- ],
120
- recommendedScope: 'extension',
121
- },
122
- {
123
- key: 'schema',
124
- title: 'Table, column, relation, validation, or schema metadata change',
125
- useWhen: [
126
- 'Creating or changing tables, columns, relations, indexes, or validation metadata.',
127
- 'Designing relation direction or inverse relation exposure.',
128
- 'Changing GraphQL/table schema flags alongside metadata.',
129
- ],
130
- keywords: ['schema', 'table', 'column', 'relation', 'field', 'index', 'validation', 'inverse'],
131
- firstTools: ['get_enfyra_required_knowledge', 'get_schema_design_context', 'inspect_table', 'get_all_tables'],
132
- inspectTools: ['get_schema_design_context', 'inspect_table', 'get_table_metadata', 'get_all_tables'],
133
- knowledgeTools: ['get_enfyra_required_knowledge', 'get_schema_design_context', 'get_enfyra_examples'],
134
- writeTools: ['create_tables', 'update_tables', 'delete_tables', 'create_columns', 'update_columns', 'delete_columns', 'create_relations', 'delete_relations', 'ensure_column_rule'],
135
- verifyTools: ['inspect_table', 'get_table_metadata'],
136
- avoidTools: [
137
- {
138
- tool: 'create_records/update_records on enfyra_column or enfyra_relation',
139
- when: 'changing schema metadata',
140
- useInstead: 'table/column/relation schema tools',
141
- reason: 'Schema tools resolve table ids, preserve relation contracts, and reject physical FK names.',
142
- },
143
- {
144
- tool: 'manual inversePropertyName',
145
- when: 'there is no concrete response/UI/deep-query/aggregate need for reverse traversal',
146
- useInstead: 'owning relation only',
147
- reason: 'Relation design stays minimal unless the reverse field is actually used.',
148
- },
149
- ],
150
- requiredAck: ['globalRulesAckKey'],
151
- exampleCategories: ['schema-relations'],
152
- nextStepTemplate: [
153
- 'Call get_schema_design_context and read liveColumnTypes plus metadata input attributes before choosing column/table/relation shapes.',
154
- 'Inspect the existing table and relations.',
155
- 'Decide owner relation and whether an inverse is actually needed.',
156
- 'Apply schema tool changes with globalRulesAckKey.',
157
- 'Re-inspect metadata instead of assuming the saved shape.',
158
- ],
159
- recommendedScope: 'schema',
160
- },
161
- {
162
- key: 'record-data',
163
- title: 'Route-backed table data query or CRUD',
164
- useWhen: [
165
- 'Reading or mutating normal route-backed records.',
166
- 'Counting records or finding one row by filter.',
167
- 'Testing filters, fields, deep relations, pagination, or aggregate query shape.',
168
- ],
169
- keywords: ['record', 'crud', 'query', 'count', 'filter', 'aggregate', 'deep', 'sort', 'pagination'],
170
- firstTools: ['inspect_table', 'discover_query_capabilities'],
171
- inspectTools: ['inspect_table', 'get_table_metadata', 'discover_query_capabilities'],
172
- knowledgeTools: ['get_enfyra_required_knowledge'],
173
- writeTools: ['create_records', 'update_records', 'delete_records'],
174
- verifyTools: ['find_one_record', 'query_table', 'count_records', 'debug_field_exposure'],
175
- avoidTools: [
176
- {
177
- tool: 'query_table without limit or all=true',
178
- when: 'listing records',
179
- useInstead: 'query_table with a bounded limit or all=true for intentional complete reads',
180
- reason: 'List/query tools require explicit paging intent.',
181
- },
182
- {
183
- tool: 'single-record CRUD tools',
184
- when: 'creating, updating, or deleting one row',
185
- useInstead: 'plural tools with a one-item array',
186
- reason: 'MCP write tools are bulk envelopes; they accept native arrays, preflight arrays, and run sequentially even for one item.',
187
- },
188
- {
189
- tool: 'generic CRUD on internal/no-route system tables',
190
- when: 'changing schema, sessions, columns, or other no-route internals',
191
- useInstead: 'specific schema/platform tools',
192
- reason: 'Generic CRUD is for route-backed tables only.',
193
- },
194
- {
195
- tool: 'route-local pre-hook or frontend hiding',
196
- when: 'REST fields/deep appears to return an isPublished=false field',
197
- useInstead: 'debug_field_exposure',
198
- reason: 'Unpublished field exposure is a core contract issue; first produce a compact repro and escalation shape.',
199
- },
200
- ],
201
- requiredAck: ['globalRulesAckKey for writes', 'dynamicCodeAckKey for script-backed sourceCode writes', 'extensionAckKey for extension code writes'],
202
- exampleCategories: ['queries-deep'],
203
- nextStepTemplate: [
204
- 'Inspect table metadata and choose fields explicitly.',
205
- 'Use bounded pagination or all=true deliberately.',
206
- 'For suspected hidden/private field leaks through fields/deep, run debug_field_exposure and escalate core exposure instead of patching UI/hooks.',
207
- 'For writes, read required knowledge and use plural mutation tools with native array inputs, even for one item.',
208
- 'Re-read with explicit fields after mutation when saved shape matters.',
209
- ],
210
- recommendedScope: 'schema',
211
- },
212
- {
213
- key: 'dynamic-script',
214
- title: 'Dynamic server code: handlers, hooks, scripts, or source patches',
215
- useWhen: [
216
- 'Writing or reviewing handler, hook, flow step, websocket, or bootstrap sourceCode.',
217
- 'Editing an existing script-backed metadata record.',
218
- 'Debugging macro, repository, or validation behavior.',
219
- ],
220
- keywords: ['sourcecode', 'script', 'hook', 'pre hook', 'post hook', 'compiledcode', 'macro', 'repos', 'bootstrap'],
221
- firstTools: ['get_enfyra_required_knowledge', 'discover_script_contexts', 'build_dynamic_repository_usage', 'search_runtime_zone'],
222
- inspectTools: ['search_runtime_zone(mode=search, zone=api_runtime|flow_runtime|websocket_runtime)', 'search_runtime_zone(mode=inspect)', 'trace_metadata_usage', 'discover_script_contexts'],
223
- knowledgeTools: ['get_enfyra_required_knowledge', 'discover_script_contexts', 'build_dynamic_repository_usage'],
224
- writeTools: ['patch_script_source', 'update_script_source', 'create_handler', 'create_pre_hook', 'create_post_hook', 'api_endpoint_workflow'],
225
- verifyTools: ['validate_dynamic_script', 'run_admin_test', 'test_rest_endpoint', 'test_flow_step'],
226
- avoidTools: [
227
- {
228
- tool: 'update_records with compiledCode',
229
- when: 'editing dynamic scripts',
230
- useInstead: 'patch_script_source or update_script_source with sourceCode',
231
- reason: 'compiledCode is generated and may differ because macros expand.',
232
- },
233
- {
234
- tool: 'throw new Error for intentional user/domain failures',
235
- when: 'writing generated dynamic server code',
236
- useInstead: '@THROW400-style macros or native $ctx.$throw helpers',
237
- reason: 'Intentional domain errors should use the platform error contract.',
238
- },
239
- ],
240
- requiredAck: ['globalRulesAckKey', 'dynamicCodeAckKey'],
241
- exampleCategories: ['handlers-hooks'],
242
- nextStepTemplate: [
243
- 'Discover script context macros for the surface.',
244
- 'Generate repository access with build_dynamic_repository_usage instead of composing secure/trusted syntax from memory.',
245
- 'Use the source artifact returned by search_runtime_zone(mode=inspect) or trace_metadata_usage when patching.',
246
- 'Validate source before save unless the chosen write tool already validates.',
247
- 'Verify behavior with the route/test runner that matches the script surface.',
248
- ],
249
- recommendedScope: 'dynamic-code',
250
- },
251
- {
252
- key: 'route-access',
253
- title: 'Authenticated route access and public/private method state',
254
- useWhen: [
255
- 'Debugging 403/401 route access.',
256
- 'Granting role/user access to a route method.',
257
- 'Changing publicMethods or availableMethods.',
258
- ],
259
- keywords: ['permission', '403', '401', 'role', 'route access', 'public method', 'private method', 'available method'],
260
- firstTools: ['get_permission_profile', 'inspect_route', 'audit_route_access'],
261
- inspectTools: ['get_permission_profile', 'inspect_route', 'audit_route_access'],
262
- knowledgeTools: ['get_enfyra_required_knowledge'],
263
- writeTools: ['ensure_route_access', 'add_route_methods', 'replace_route_methods', 'remove_route_methods', 'public_route_methods', 'private_route_methods', 'enable_route', 'disable_route'],
264
- verifyTools: ['audit_route_access', 'test_rest_endpoint'],
265
- avoidTools: [
266
- {
267
- tool: 'raw enfyra_route_permission CRUD',
268
- when: 'granting route access',
269
- useInstead: 'ensure_route_access',
270
- reason: 'The operation tool resolves roles/methods and merges existing method grants safely.',
271
- },
272
- {
273
- tool: 'public_route_methods',
274
- when: 'the desired behavior is authenticated user access',
275
- useInstead: 'ensure_route_access',
276
- reason: 'publicMethods grants anonymous access; route permissions grant authenticated access.',
277
- },
278
- ],
279
- requiredAck: ['globalRulesAckKey for writes'],
280
- exampleCategories: ['permissions-rls'],
281
- nextStepTemplate: [
282
- 'Inspect route and permission profile before changing access.',
283
- 'Decide anonymous publicMethods versus authenticated route permission.',
284
- 'Use route operation tools instead of raw permission CRUD.',
285
- 'Audit and test the route after the change.',
286
- ],
287
- recommendedScope: 'schema',
288
- },
289
- {
290
- key: 'guards-permissions-rules',
291
- title: 'Guards, field permissions, and column validation rules',
292
- useWhen: [
293
- 'Adding route guards, guard rules, field permissions, or column rules.',
294
- 'Adding request rate limits or throttling to a route.',
295
- 'Restricting field read/write behavior.',
296
- 'Adding body validation rules at metadata level.',
297
- ],
298
- keywords: ['guard', 'rate limit', 'throttle', 'field permission', 'column rule', 'validation rule', 'rule', 'rls'],
299
- firstTools: ['get_enfyra_required_knowledge', 'inspect_table', 'inspect_route'],
300
- inspectTools: ['inspect_table', 'inspect_route', 'discover_query_capabilities'],
301
- knowledgeTools: ['get_enfyra_required_knowledge'],
302
- writeTools: ['ensure_route_rate_limit', 'ensure_guard', 'ensure_field_permission', 'ensure_column_rule', 'create_pre_hook'],
303
- verifyTools: ['test_rest_endpoint', 'query_table', 'run_admin_test'],
304
- avoidTools: [
305
- {
306
- tool: 'raw create_records on guard/rule tables',
307
- when: 'a dedicated ensure_* operation exists',
308
- useInstead: 'ensure_route_rate_limit, ensure_guard, ensure_field_permission, or ensure_column_rule',
309
- reason: 'Ensure tools resolve ids and preserve the current rule contract.',
310
- },
311
- {
312
- tool: 'create_pre_hook',
313
- when: 'the requirement is request throttling or rate limiting',
314
- useInstead: 'ensure_route_rate_limit',
315
- reason: 'Rate limits belong to the built-in guard engine, not custom pre-hook scripts.',
316
- },
317
- {
318
- tool: 'ensure_field_permission',
319
- when: 'the requirement is owner/tenant row scoping or RLS query filtering',
320
- useInstead: 'create_pre_hook for canonical shared policy, or api_endpoint_workflow for third-party-only policy',
321
- reason: 'Field permissions protect field visibility. Canonical shared row ownership belongs in a route pre-hook; endpoint-specific ownership belongs in the custom handler.',
322
- },
323
- ],
324
- requiredAck: ['globalRulesAckKey'],
325
- exampleCategories: ['permissions-rls', 'schema-relations'],
326
- nextStepTemplate: [
327
- 'Inspect the target table/route and decide the security boundary first.',
328
- 'Use a canonical route pre-hook for row filters shared by every canonical CRUD consumer. Use api_endpoint_workflow when the owner/tenant/business policy belongs only to a third-party custom contract.',
329
- 'Use the specific ensure_* operation for guard, field, or column rule surfaces.',
330
- 'Verify with the route/query behavior the rule is meant to protect.',
331
- ],
332
- recommendedScope: 'schema',
333
- },
334
- {
335
- key: 'flow',
336
- title: 'Flow, scheduled/manual flow, or flow step',
337
- useWhen: [
338
- 'Creating or changing manual/scheduled flows.',
339
- 'Choosing or writing a flow step.',
340
- 'Testing or triggering a flow.',
341
- ],
342
- keywords: ['flow', 'scheduled', 'manual flow', 'flow step', 'trigger flow', 'workflow'],
343
- firstTools: ['get_enfyra_required_knowledge', 'flow_workflow', 'plan_flow_steps', 'discover_script_contexts'],
344
- inspectTools: ['inspect_feature', 'query_table'],
345
- knowledgeTools: ['get_enfyra_required_knowledge', 'discover_script_contexts'],
346
- writeTools: ['flow_workflow', 'plan_flow_steps'],
347
- verifyTools: ['test_flow_step', 'run_admin_test', 'trigger_flow'],
348
- avoidTools: [
349
- {
350
- tool: 'ensure_script_flow_step',
351
- when: 'a fixed query/create/update/delete/http/sleep/trigger/log step can express the operation',
352
- useInstead: 'flow_workflow or plan_flow_steps',
353
- reason: 'Atomic step types are easier to inspect, test, and maintain than oversized scripts.',
354
- },
355
- ],
356
- requiredAck: ['globalRulesAckKey', 'dynamicCodeAckKey for script or condition source'],
357
- exampleCategories: ['flows'],
358
- nextStepTemplate: [
359
- 'Use flow_workflow with apply=false for multi-step flows; use plan_flow_steps only for dry-run step selection.',
360
- 'Prefer fixed step types for static config. Fixed-step config is not template-transformed; use one focused script step for @FLOW_PAYLOAD/@FLOW_LAST/@FLOW values.',
361
- 'In scripts call @LOGS(message, details?); @LOGS has no .info/.warn/.error/.debug methods.',
362
- 'Validate/test script or condition steps before relying on the flow.',
363
- 'Trigger manually only after the saved steps are verified.',
364
- ],
365
- recommendedScope: 'flow',
366
- },
367
- {
368
- key: 'websocket',
369
- title: 'Socket.IO gateway or websocket event',
370
- useWhen: [
371
- 'Creating or changing websocket gateways/events.',
372
- 'Writing websocket handler source.',
373
- 'Testing websocket event logic.',
374
- ],
375
- keywords: ['websocket', 'socket', 'socket.io', 'gateway', 'realtime', 'room'],
376
- firstTools: ['get_enfyra_required_knowledge', 'discover_script_contexts', 'inspect_feature'],
377
- inspectTools: ['inspect_feature', 'discover_script_contexts'],
378
- knowledgeTools: ['get_enfyra_required_knowledge', 'discover_script_contexts'],
379
- writeTools: ['ensure_websocket_gateway', 'ensure_websocket_event'],
380
- verifyTools: ['run_admin_test'],
381
- avoidTools: [
382
- {
383
- tool: 'raw CRUD on enfyra_websocket_event',
384
- when: 'saving websocket event source',
385
- useInstead: 'ensure_websocket_event',
386
- reason: 'The operation tool validates script source and preserves gateway/event linkage.',
387
- },
388
- ],
389
- requiredAck: ['globalRulesAckKey', 'dynamicCodeAckKey when saving event source'],
390
- exampleCategories: ['websocket'],
391
- nextStepTemplate: [
392
- 'Discover websocket script context before writing source.',
393
- 'Ensure gateway first, then event.',
394
- 'Use run_admin_test(kind=websocket_event|websocket_connection) to capture emitted calls. This validates runtime script behavior but does not prove a real Socket.IO client transport/handshake.',
395
- ],
396
- recommendedScope: 'dynamic-code',
397
- },
398
- {
399
- key: 'graphql',
400
- title: 'GraphQL enablement and query surface',
401
- useWhen: [
402
- 'Enabling/disabling GraphQL for a table.',
403
- 'Checking GraphQL endpoint/schema behavior.',
404
- 'Clarifying REST route methods versus GraphQL table exposure.',
405
- ],
406
- keywords: ['graphql', 'gql', 'schema endpoint'],
407
- firstTools: ['discover_enfyra_system', 'inspect_table'],
408
- inspectTools: ['discover_enfyra_system', 'inspect_table'],
409
- knowledgeTools: ['get_enfyra_required_knowledge'],
410
- writeTools: ['set_table_graphql', 'update_tables'],
411
- verifyTools: ['test_graphql', 'discover_enfyra_system'],
412
- avoidTools: [
413
- {
414
- tool: 'public_route_methods',
415
- when: 'trying to expose GraphQL table data',
416
- useInstead: 'set_table_graphql plus GraphQL auth planning',
417
- reason: 'REST publicMethods do not make GraphQL table data anonymous.',
418
- },
419
- ],
420
- requiredAck: ['globalRulesAckKey for writes'],
421
- exampleCategories: ['graphql'],
422
- nextStepTemplate: [
423
- 'Inspect the table and GraphQL enablement state.',
424
- 'Use set_table_graphql for enablement changes.',
425
- 'Hide a field from generated GraphQL with table metadata isPublished=false. Use ensure_field_permission only when an explicit role/user subject is part of the requirement.',
426
- 'Run test_graphql with an authenticated query and inspect GraphQL errors as data.',
427
- 'Remember GraphQL table data requires Bearer auth even when REST is public.',
428
- ],
429
- recommendedScope: 'schema',
430
- },
431
- {
432
- key: 'storage-file',
433
- title: 'Files, folders, storage configuration, and file permissions',
434
- useWhen: [
435
- 'Inspecting or configuring storage providers and folders.',
436
- 'Managing file metadata, public state, or file permissions.',
437
- 'Building browser upload behavior and progress handling.',
438
- ],
439
- keywords: ['file upload', 'upload progress', 'storage config', 'storage provider', 'folder', 'file permission', 'asset'],
440
- firstTools: ['search_runtime_zone', 'get_enfyra_examples'],
441
- inspectTools: ['search_runtime_zone(mode=search, zone=storage_file)', 'search_runtime_zone(mode=inspect)', 'inspect_table', 'query_table'],
442
- knowledgeTools: ['get_enfyra_required_knowledge', 'get_enfyra_examples(category=files)'],
443
- writeTools: ['create_records', 'update_records', 'delete_records'],
444
- verifyTools: ['search_runtime_zone', 'query_table'],
445
- avoidTools: [
446
- {
447
- tool: 'create_records on enfyra_file for binary upload',
448
- when: 'uploading file bytes from a browser or dynamic script',
449
- useInstead: 'multipart /enfyra/enfyra_file or @STORAGE helpers',
450
- reason: 'File metadata CRUD does not provide object upload, rollback, or progress behavior.',
451
- },
452
- ],
453
- requiredAck: ['globalRulesAckKey for metadata writes'],
454
- exampleCategories: ['files'],
455
- nextStepTemplate: [
456
- 'Search storage_file runtime state, then inspect the selected record/table.',
457
- 'Use the files examples for browser proxy, multipart, progress, and @STORAGE contracts.',
458
- 'Use generic record tools only for metadata/configuration rows, never as a binary upload substitute.',
459
- 'The guided MCP does not expose a binary/multipart upload input tool. For an execute-now upload request, report that capability boundary before creating metadata-only file artifacts; browser code must use multipart /enfyra/enfyra_file and dynamic code must use @STORAGE.',
460
- ],
461
- recommendedScope: 'schema',
462
- },
463
- {
464
- key: 'oauth',
465
- title: 'Connect a third app, then configure its OAuth provider',
466
- useWhen: [
467
- 'Connecting a third app to Enfyra before creating or updating Google, Facebook, or GitHub OAuth.',
468
- 'Seeding OAuth client credentials and returning the exact provider callback URI.',
469
- 'Continuing third-app OAuth integration after the user confirms the provider console callback.',
470
- ],
471
- keywords: [
472
- 'oauth',
473
- 'google login',
474
- 'google oauth',
475
- 'social login',
476
- 'oauth provider',
477
- 'provider callback',
478
- 'authorized redirect uri',
479
- 'client id client secret',
480
- 'đăng nhập google',
481
- 'cấu hình oauth',
482
- 'tích hợp oauth',
483
- ],
484
- firstTools: ['get_enfyra_api_context', 'get_enfyra_examples'],
485
- inspectTools: ['get_enfyra_api_context'],
486
- knowledgeTools: ['get_enfyra_required_knowledge', 'get_enfyra_examples'],
487
- writeTools: ['setup_oauth_provider'],
488
- verifyTools: ['test_rest_endpoint', 'search_runtime_zone', 'query_table'],
489
- avoidTools: [
490
- {
491
- tool: 'provider state reads before credentials',
492
- when: 'the third app is connected but clientId or clientSecret is absent from the current user request',
493
- useInstead: 'stop and ask only for clientId and clientSecret',
494
- reason: 'setup_oauth_provider owns the existing-row upsert and runtime verification. Pre-reading provider state cannot replace user-supplied credentials and must not trigger an early callback handoff.',
495
- },
496
- {
497
- tool: 'create_records / update_records',
498
- when: 'the user asked to configure a built-in OAuth provider',
499
- useInstead: 'setup_oauth_provider',
500
- reason: 'The OAuth front door upserts credentials, derives the callback, verifies runtime activation, redacts secrets, and returns the provider-console handoff in one operation.',
501
- },
502
- {
503
- tool: 'custom ESV login/logout/me routes',
504
- when: 'the third app can proxy a stable prefix to the Enfyra app /api bridge',
505
- useInstead: 'the built-in Enfyra auth endpoints through the framework-specific third-app proxy',
506
- reason: 'Do not replace Enfyra identity behavior. The Enfyra app bridge already owns cookie storage, refresh, and Bearer forwarding to ESV.',
507
- },
508
- ],
509
- requiredAck: ['globalRulesAckKey for OAuth configuration writes'],
510
- exampleCategories: ['connect', 'oauth-setup'],
511
- nextStepTemplate: [
512
- 'Load category=connect and inspect or implement the third-app connection before asking for provider credentials.',
513
- 'Once the app connection is verified, stop and ask only for clientId and clientSecret. Never inspect provider state or stored credential values, and do not present callbackUri before setup_oauth_provider returns.',
514
- 'Present callbackUri and providerConsole.field, then stop until the user confirms that callback was added in the provider console.',
515
- 'After confirmation, complete a real OAuth login through the existing app button and verify /me before reporting setup success.',
516
- ],
517
- recommendedScope: 'operations',
518
- },
519
- {
520
- key: 'identity-access',
521
- title: 'Users, roles, sessions, and application identity access',
522
- useWhen: [
523
- 'Inspecting or managing Enfyra users and roles.',
524
- 'Designing application login, session, refresh, and role access behavior.',
525
- ],
526
- keywords: ['user role', 'oauth account', 'login flow', 'session refresh', 'identity access'],
527
- firstTools: ['search_runtime_zone', 'get_enfyra_examples'],
528
- inspectTools: ['search_runtime_zone(mode=search, zone=auth_security)', 'search_runtime_zone(mode=inspect)', 'query_table', 'get_permission_profile'],
529
- knowledgeTools: ['get_enfyra_required_knowledge', 'get_enfyra_examples(category=oauth-setup|connect)'],
530
- writeTools: ['create_records', 'update_records', 'delete_records', 'ensure_route_access'],
531
- verifyTools: ['query_table', 'get_permission_profile', 'test_rest_endpoint'],
532
- avoidTools: [
533
- {
534
- tool: 'custom login/logout/me routes',
535
- when: 'a browser app can use the Enfyra same-origin proxy and cookies',
536
- useInstead: 'the built-in /login, /me, /logout, refresh, and OAuth routes through /enfyra',
537
- reason: 'Custom token-cookie routes duplicate the supported identity lifecycle and are easier to get wrong.',
538
- },
539
- ],
540
- requiredAck: ['globalRulesAckKey for identity metadata writes'],
541
- exampleCategories: ['connect'],
542
- nextStepTemplate: [
543
- 'Separate MCP token context from application user/role/OAuth configuration.',
544
- 'Inspect auth_security runtime records and the live table contract before writes.',
545
- 'Verify built-in auth behavior through the app-origin proxy or the narrow REST endpoint.',
546
- ],
547
- recommendedScope: 'schema',
548
- },
549
- {
550
- key: 'platform-config',
551
- title: 'Platform settings and CORS origins',
552
- useWhen: [
553
- 'Inspecting or changing enfyra_setting values.',
554
- 'Adding, updating, or removing allowed CORS origins.',
555
- 'Checking runtime platform configuration before application integration.',
556
- ],
557
- keywords: ['cors', 'allowed origin', 'platform setting', 'enfyra_setting', 'enfyra_cors_origin'],
558
- firstTools: ['inspect_table', 'query_table'],
559
- inspectTools: ['inspect_table', 'query_table', 'discover_runtime_context'],
560
- knowledgeTools: ['get_enfyra_required_knowledge'],
561
- writeTools: ['create_records', 'update_records', 'delete_records'],
562
- verifyTools: ['query_table', 'discover_runtime_context'],
563
- avoidTools: [
564
- {
565
- tool: 'inventing setting keys or CORS fields',
566
- when: 'live metadata has not been inspected',
567
- useInstead: 'inspect_table for enfyra_setting or enfyra_cors_origin',
568
- reason: 'Platform configuration is metadata-backed and field names must come from the current Enfyra version.',
569
- },
570
- ],
571
- requiredAck: ['globalRulesAckKey for writes'],
572
- exampleCategories: [],
573
- nextStepTemplate: [
574
- 'Inspect the exact configuration table and current row first.',
575
- 'Apply a focused generic record mutation with acknowledgement.',
576
- 'Re-read the same row and verify application behavior before manual reloads.',
577
- ],
578
- recommendedScope: 'schema',
579
- },
580
- {
581
- key: 'package',
582
- title: 'Runtime package install or package-backed extension/script support',
583
- useWhen: [
584
- 'Installing npm packages for dynamic code or extension runtime use.',
585
- 'Checking package availability before using getPackages in extensions.',
586
- ],
587
- keywords: ['package', 'npm', 'install', 'dependency', 'getpackages'],
588
- firstTools: ['search_npm', 'get_enfyra_required_knowledge'],
589
- inspectTools: ['search_npm', 'query_table'],
590
- knowledgeTools: ['get_enfyra_required_knowledge'],
591
- writeTools: ['install_package'],
592
- verifyTools: ['query_table'],
593
- avoidTools: [
594
- {
595
- tool: 'raw create_records on enfyra_package',
596
- when: 'installing packages',
597
- useInstead: 'install_package',
598
- reason: 'The package tool resolves package metadata and avoids duplicate package records.',
599
- },
600
- ],
601
- requiredAck: ['globalRulesAckKey'],
602
- exampleCategories: ['extensions', 'handlers-hooks'],
603
- nextStepTemplate: [
604
- 'Search package metadata first.',
605
- 'Install with install_package and globalRulesAckKey.',
606
- 'Use getPackages inside extension runtime code rather than static imports.',
607
- ],
608
- recommendedScope: 'schema',
609
- },
610
- {
611
- key: 'cache',
612
- title: 'Cache reload or stale metadata/runtime diagnosis',
613
- useWhen: [
614
- 'Diagnosing stale routes, metadata, GraphQL, or full runtime cache.',
615
- 'Manually reloading only after natural partial reload appears stale.',
616
- ],
617
- keywords: ['cache', 'reload', 'stale', 'refresh metadata', 'reload routes'],
618
- firstTools: ['inspect_table', 'inspect_route', 'get_enfyra_api_context'],
619
- inspectTools: ['inspect_table', 'inspect_route', 'get_enfyra_api_context'],
620
- knowledgeTools: ['get_enfyra_required_knowledge'],
621
- writeTools: [],
622
- verifyTools: ['inspect_table', 'inspect_route', 'discover_enfyra_system'],
623
- avoidTools: [
624
- {
625
- tool: 'manual reload tools',
626
- when: 'a successful metadata mutation already triggered natural partial reload and no stale evidence exists',
627
- useInstead: 'verify behavior first with inspect/test tools',
628
- reason: 'Manual reloads should be evidence-driven, not reflexive.',
629
- },
630
- ],
631
- requiredAck: ['globalRulesAckKey for manual reload tools'],
632
- exampleCategories: [],
633
- nextStepTemplate: [
634
- 'Verify stale behavior with narrow inspect/test tools.',
635
- 'If stale evidence truly requires manual reload, switch to ENFYRA_MCP_TOOLSET=full and choose the narrowest reload surface.',
636
- 'Re-verify the same narrow behavior after reload.',
637
- ],
638
- recommendedScope: 'schema',
639
- },
640
- {
641
- key: 'logs-debug',
642
- title: 'Logs, runtime diagnostics, and test runner debugging',
643
- useWhen: [
644
- 'Reading app/error logs.',
645
- 'Searching logs for route, flow, websocket, or dynamic script failures.',
646
- 'Running admin tests for supported runtime surfaces.',
647
- ],
648
- keywords: ['log', 'debug', 'error', 'trace', 'tail', 'diagnostic', 'test runner'],
649
- firstTools: ['search_logs', 'tail_log'],
650
- inspectTools: ['search_logs', 'tail_log'],
651
- knowledgeTools: [],
652
- writeTools: [],
653
- verifyTools: ['run_admin_test', 'test_flow_step', 'test_rest_endpoint'],
654
- avoidTools: [
655
- {
656
- tool: 'broad metadata discovery',
657
- when: 'the problem is a concrete runtime error with known log text',
658
- useInstead: 'search_logs or tail_log',
659
- reason: 'Log tools are narrower and cheaper for runtime debugging.',
660
- },
661
- ],
662
- requiredAck: [],
663
- exampleCategories: [],
664
- nextStepTemplate: [
665
- 'Search or tail the narrowest log first.',
666
- 'Use the matching test tool to reproduce once the failing surface is known.',
667
- 'Patch only after the failing step is identified.',
668
- ],
669
- recommendedScope: 'schema',
670
- },
671
- {
672
- key: 'auth-context',
673
- title: 'MCP target, auth token, current user, and permission profile',
674
- useWhen: [
675
- 'Confirming which Enfyra instance MCP is connected to.',
676
- 'Debugging API-token exchange or current MCP user permissions.',
677
- 'Checking whether non-root tokens can call admin helper routes.',
678
- ],
679
- keywords: ['auth', 'token', 'current user', 'permission profile', 'target', 'api base', '403', 'exchange'],
680
- firstTools: ['get_enfyra_api_context', 'get_current_user', 'get_permission_profile'],
681
- inspectTools: ['get_enfyra_api_context', 'get_current_user', 'get_permission_profile'],
682
- knowledgeTools: [],
683
- writeTools: ['login'],
684
- verifyTools: ['get_current_user', 'get_permission_profile'],
685
- avoidTools: [
686
- {
687
- tool: 'discover_enfyra_system',
688
- when: 'only confirming the connected API base',
689
- useInstead: 'get_enfyra_api_context',
690
- reason: 'Target sanity checks should be cheap and should not load broad metadata.',
691
- },
692
- ],
693
- requiredAck: [],
694
- exampleCategories: ['connect', 'oauth-setup'],
695
- nextStepTemplate: [
696
- 'Use get_enfyra_api_context for target sanity checks.',
697
- 'Use get_permission_profile before assuming admin helper route access with non-root tokens.',
698
- 'Use login only when an interactive credential login is explicitly needed.',
699
- ],
700
- recommendedScope: 'schema',
701
- },
702
- ];
703
- function compactWorkflow(workflow) {
704
- return {
705
- key: workflow.key,
706
- title: workflow.title,
707
- useWhen: workflow.useWhen,
708
- recommendedScope: workflow.recommendedScope,
709
- };
710
- }
711
- function step(order, tool, purpose, extra = {}) {
712
- return { order, tool, purpose, ...extra };
713
- }
714
- function primaryPathFor(workflow) {
715
- switch (workflow.key) {
716
- case 'api-endpoint':
717
- return [
718
- step(1, 'get_enfyra_required_knowledge', 'Read mutation/security contracts and collect acknowledgement keys.'),
719
- step(2, 'discover_script_contexts', 'Load handler/hook macros and repository contracts before writing source.'),
720
- step(3, 'api_endpoint_workflow', 'For a fully specified non-destructive endpoint, apply all safe steps in one call. Use apply=false only when a route/access decision is unresolved.'),
721
- step(5, 'test_rest_endpoint', 'Smoke-test the final route contract.'),
722
- ];
723
- case 'extension':
724
- return [
725
- step(1, 'get_enfyra_required_knowledge', 'Read global and extension contracts; collect acknowledgement keys.'),
726
- step(2, 'get_extension_theme_contract', 'Load the required eApp/Nuxt UI theme and component contract.'),
727
- step(3, 'search_admin_extensions', 'Locate the menu/page/widget/global extension by visible text, path, button, icon, tab, or source term.'),
728
- step(4, 'search_admin_extensions', 'Inspect the selected admin UI artifact with mode=inspect using nextInspect.input.'),
729
- step(5, 'build_extension_ui', 'After acknowledgement, generate or review high-contract extension UI lazily by kind: drawer, modal, page shell, permission gate, empty state, resource list, FormEditor, Widget, shell registries, tabs, upload modal, api usage, notify, runtime review, theme classes, theme review, or full review.'),
730
- step(6, 'extension_workflow or patch_extension_code/update_extension_code', 'Use extension_workflow for create/wire flows, patch_extension_code for focused edits, or update_extension_code for full replacements.'),
731
- step(7, 'verify_extension_runtime', 'Extension save operations already return valid saved-state verification. Call this only when that receipt is inconclusive or the task explicitly requires an independent recheck; run browser QA separately when browserRender is not_run.'),
732
- ];
733
- case 'schema':
734
- return [
735
- step(1, 'get_enfyra_required_knowledge', 'Read schema invariants and collect globalRulesAckKey.'),
736
- step(2, 'get_schema_design_context', 'Step zero: read live column types, table/column/relation attributes, constraint shape, and creation order.'),
737
- step(3, 'get_all_tables or inspect_table', 'Check existing tables before naming new tables or adding to an existing table.', { when: 'Use get_all_tables for new app schemas; inspect_table for a known existing table.' }),
738
- step(4, 'create_tables / create_columns / create_relations / update_tables', 'Apply schema changes with native array inputs using only live types and relation propertyName values from the design context. Put relation-based unique/index groups in the same create_tables item as the owning relations, or add them later with update_tables after relations exist.'),
739
- step(5, 'inspect_table', 'Re-read saved metadata before creating records, queries, handlers, or UI against the table.'),
740
- ];
741
- case 'record-data':
742
- return [
743
- step(1, 'inspect_table', 'Read live columns, relations, primary key, route path, and field visibility.'),
744
- step(2, 'discover_query_capabilities', 'Load filter/deep/sort/aggregate shape when query shape is non-trivial.'),
745
- step(3, 'debug_field_exposure', 'Build a compact repro when fields/deep may expose an unpublished field; escalate core exposure instead of adding local fixes.', { when: 'The task is about hidden/private/secret field exposure.' }),
746
- step(4, 'query_table / find_one_record / count_records', 'Read records with explicit fields and bounded pagination.'),
747
- step(5, 'create_records / update_records / delete_records', 'For writes, use only metadata-backed column names and relation propertyName values. Always pass a native array, even for one item.', { when: 'Only after required knowledge is read for writes.' }),
748
- step(6, 'find_one_record or query_table', 'Verify the saved/read shape with explicit fields.'),
749
- ];
750
- case 'dynamic-script':
751
- return [
752
- step(1, 'get_enfyra_required_knowledge', 'Read dynamic-code contracts and collect acknowledgement keys.'),
753
- step(2, 'discover_script_contexts', 'Load macros, repository trust paths, per-surface helpers, and the fields+deep projection contract for script repository reads.'),
754
- step(3, 'build_dynamic_repository_usage', 'Generate secure or intentional trusted repository access when the script reads or writes table data.'),
755
- step(4, 'search_runtime_zone', 'Locate the script-backed runtime artifact in api_runtime, flow_runtime, or websocket_runtime.'),
756
- step(5, 'patch_script_source or update_script_source', 'Patch or replace the inspected source artifact with validation and hash checks.'),
757
- step(6, 'test_rest_endpoint / run_admin_test / test_flow_step', 'Verify through the runtime path that owns the script.'),
758
- ];
759
- case 'route-access':
760
- case 'guards-permissions-rules':
761
- return [
762
- step(1, 'get_enfyra_required_knowledge', 'Read access/security contracts.'),
763
- step(2, 'inspect_route or inspect_table', 'Inspect the exact route/table access surface.'),
764
- step(3, 'audit_route_access', 'Compare current route permissions against expected roles/users/methods.'),
765
- step(4, 'ensure_route_access / ensure_route_rate_limit / create_pre_hook / ensure_field_permission / ensure_guard / ensure_column_rule', 'Apply the specific access/rule operation. Use ensure_route_rate_limit for request throttling and create_pre_hook for owner/tenant row filters.'),
766
- step(5, 'audit_route_access or test_rest_endpoint', 'Verify the access behavior.'),
767
- ];
768
- case 'flow':
769
- return [
770
- step(1, 'get_enfyra_required_knowledge', 'Read flow/dynamic-code contracts.'),
771
- step(2, 'discover_script_contexts', 'Load flow-step macros only when a script or condition step is needed.'),
772
- step(3, 'flow_workflow', 'For a fully specified non-destructive flow, apply the flow and all steps sequentially in one call. Use apply=false only when step selection is unresolved.'),
773
- step(5, 'test_flow_step or trigger_flow', 'Use test_flow_step for disabled flows. Use trigger_flow only for an enabled flow when intentionally verifying the real queue/runtime path.'),
774
- ];
775
- case 'websocket':
776
- return [
777
- step(1, 'get_enfyra_required_knowledge', 'Read websocket/dynamic-code contracts.'),
778
- step(2, 'discover_script_contexts', 'Load socket helpers and room APIs.'),
779
- step(3, 'search_runtime_zone', 'Locate existing websocket gateway/event with zone=websocket_runtime when editing.'),
780
- step(4, 'ensure_websocket_gateway / ensure_websocket_event', 'Create or update gateway/event through validation-aware tools.'),
781
- step(5, 'run_admin_test', 'Verify connection/event handler behavior and captured emits with kind=websocket_event or websocket_connection. This does not prove a real Socket.IO client transport/handshake.'),
782
- ];
783
- case 'graphql':
784
- return [
785
- step(1, 'discover_enfyra_system', 'Read GraphQL endpoint/auth/table enablement context.'),
786
- step(2, 'inspect_table', 'Inspect the table before enabling GraphQL.'),
787
- step(3, 'set_table_graphql', 'Enable or disable generated GraphQL exposure for the table.'),
788
- step(4, 'test_graphql', 'Execute an authenticated GraphQL operation and inspect data/errors.'),
789
- ];
790
- case 'storage-file':
791
- return [
792
- step(1, 'search_runtime_zone', 'Search storage configs, folders, files, and file permissions with zone=storage_file.'),
793
- step(2, 'search_runtime_zone', 'Inspect the selected storage_file result using nextInspect.input.'),
794
- step(3, 'get_enfyra_examples', 'Load category=files when browser multipart, proxy, progress, or @STORAGE behavior is involved.'),
795
- step(4, 'create_records / update_records / delete_records', 'Mutate metadata/configuration rows only after reading required knowledge; do not use record CRUD to upload bytes. This MCP does not expose a binary/multipart upload input tool, so stop and report that boundary for execute-now upload requests.'),
796
- step(5, 'search_runtime_zone or query_table', 'Verify the saved metadata and public/permission state.'),
797
- ];
798
- case 'oauth':
799
- return [
800
- step(1, 'get_enfyra_api_context', 'Confirm the Enfyra API target used to derive the provider callback URI.'),
801
- step(2, 'get_enfyra_examples', 'Load category=connect, inspect the actual third-app framework, and implement or verify the proxy, OAuth start action, cookieBridgePrefix, and /me session check before asking for provider credentials.', {
802
- stopWhen: 'The third app or its framework cannot be located: ask the user which app to connect instead of choosing one by guesswork.',
803
- }),
804
- step(3, 'get_enfyra_required_knowledge', 'After the app connection is verified, load scope=schema to acknowledge global rules before the OAuth config write.'),
805
- step(4, 'setup_oauth_provider', 'After the user supplies clientId and clientSecret, call with appConnectionVerified=true to save the Enfyra config and receive the exact callback handoff. Never inspect or reuse stored credential values. Present callbackUri only from this receipt, then stop for provider-console confirmation; setupComplete remains false.', {
806
- stopWhen: 'Client credentials are missing from the current user request: stop and ask only for clientId and clientSecret. Do not inspect provider state, do not present callbackUri, and do not ask the user to configure the provider console yet.',
807
- }),
808
- step(5, 'test_rest_endpoint', 'Only after the user confirms the callback URI was added, verify runtime availability, then complete a real browser OAuth login through the already connected app and verify /me. Do not declare success from /auth/providers alone.'),
809
- ];
810
- case 'identity-access':
811
- return [
812
- step(1, 'search_runtime_zone', 'Search users, roles, permissions, guards, and OAuth config with zone=auth_security.'),
813
- step(2, 'get_enfyra_examples', 'Load oauth-setup or connect only when that identity path is involved.'),
814
- step(3, 'inspect_table or query_table', 'Inspect the exact user, role, OAuth, or permission contract.'),
815
- step(4, 'create_records / update_records / delete_records / ensure_route_access', 'Apply the narrow identity metadata or access operation after required knowledge.'),
816
- step(5, 'query_table / get_permission_profile / test_rest_endpoint', 'Verify the closest identity/access behavior.'),
817
- ];
818
- case 'platform-config':
819
- return [
820
- step(1, 'inspect_table', 'Inspect enfyra_setting or enfyra_cors_origin before choosing fields or keys.'),
821
- step(2, 'query_table', 'Read the current focused configuration rows.'),
822
- step(3, 'create_records / update_records / delete_records', 'Apply one focused metadata-backed configuration change after required knowledge.'),
823
- step(4, 'query_table', 'Re-read the changed row and verify the saved value.'),
824
- ];
825
- case 'package':
826
- return [
827
- step(1, 'search_npm', 'Find package candidates from npm.'),
828
- step(2, 'get_enfyra_required_knowledge', 'Read package/runtime mutation contracts.'),
829
- step(3, 'install_package', 'Install the selected package through the package operation tool.'),
830
- step(4, 'search_runtime_zone', 'Verify package runtime state with zone=package_runtime when needed.'),
831
- ];
832
- case 'cache':
833
- return [
834
- step(1, 'discover_runtime_context', 'Read runtime/cache context and current app target.'),
835
- step(2, 'inspect_table / inspect_route / search_runtime_zone', 'Confirm the specific stale artifact before reloading.'),
836
- step(3, 'full toolset reload tools', 'Only when stale evidence persists, switch to full toolset and reload the narrowest proven surface; reload_all is last resort.'),
837
- step(4, 'inspect_table / inspect_route / discover_enfyra_system', 'Verify the stale state cleared.'),
838
- ];
839
- case 'logs-debug':
840
- return [
841
- step(1, 'search_logs', 'Search the narrow log pattern/time clue.'),
842
- step(2, 'tail_log', 'Tail only the relevant log when live reproduction is needed.'),
843
- ];
844
- case 'auth-context':
845
- return [
846
- step(1, 'get_enfyra_api_context', 'Confirm the connected target cheaply.'),
847
- step(2, 'get_current_user', 'Read current user/session context.'),
848
- step(3, 'get_permission_profile', 'Check admin helper route permissions for non-root tokens.'),
849
- ];
850
- default:
851
- return workflow.firstTools.map((tool, index) => step(index + 1, tool, 'Follow this workflow step.'));
852
- }
853
- }
854
- function splitCompositeToolName(tool) {
855
- if (tool === 'full toolset reload tools')
856
- return [];
857
- return tool
858
- .split(/\s+or\s+|\s*\/\s*/g)
859
- .map((item) => item.trim().replace(/\(.*/, ''))
860
- .filter(Boolean);
861
- }
862
- export function workflowToolNames(surface) {
863
- const workflow = TOOL_WORKFLOWS.find((item) => item.key === surface);
864
- if (!workflow)
865
- return [];
866
- return [...new Set([
867
- ...workflow.firstTools,
868
- ...workflow.inspectTools,
869
- ...workflow.knowledgeTools,
870
- ...workflow.writeTools,
871
- ...workflow.verifyTools,
872
- ...primaryPathFor(workflow).flatMap((item) => splitCompositeToolName(item.tool)),
873
- ...advancedToolsFor(workflow).flatMap(splitCompositeToolName),
874
- ...verifyPathFor(workflow).flatMap((item) => splitCompositeToolName(item.tool)),
875
- ])];
876
- }
877
- function advancedToolsFor(workflow) {
878
- const primaryTools = new Set(primaryPathFor(workflow).flatMap((item) => splitCompositeToolName(item.tool)));
879
- return [...new Set([
880
- ...workflow.inspectTools,
881
- ...workflow.knowledgeTools,
882
- ...workflow.writeTools,
883
- ...workflow.verifyTools,
884
- ])].filter((tool) => !primaryTools.has(tool));
885
- }
886
- function escapeHatchesFor(workflow) {
887
- const escape = new Set(['create_records', 'update_records', 'delete_records', 'create_route', 'reload_all', 'reload_metadata', 'reload_routes', 'reload_graphql', 'get_all_metadata', 'get_table_metadata']);
888
- return [...new Set([...workflow.writeTools, ...workflow.verifyTools, ...workflow.inspectTools])]
889
- .filter((tool) => escape.has(tool));
890
- }
891
- function verifyPathFor(workflow) {
892
- return workflow.verifyTools.map((tool, index) => step(index + 1, tool, 'Verify the workflow result through the closest runtime/read path.'));
893
- }
894
- function planWorkflow(workflow) {
895
- return {
896
- ...compactWorkflow(workflow),
897
- recommendedScope: workflow.recommendedScope,
898
- primaryPath: primaryPathFor(workflow),
899
- advancedTools: advancedToolsFor(workflow),
900
- escapeHatches: escapeHatchesFor(workflow),
901
- verifyPath: verifyPathFor(workflow),
902
- requiredAck: workflow.requiredAck,
903
- exampleCategories: workflow.exampleCategories,
904
- avoidTools: workflow.avoidTools,
905
- legacyToolSets: {
906
- firstTools: workflow.firstTools,
907
- inspectTools: workflow.inspectTools,
908
- knowledgeTools: workflow.knowledgeTools,
909
- writeTools: workflow.writeTools,
910
- verifyTools: workflow.verifyTools,
911
- },
912
- };
913
- }
914
- function fullWorkflow(workflow) {
915
- return {
916
- ...planWorkflow(workflow),
917
- keywords: workflow.keywords,
918
- };
919
- }
920
- function normalize(value) {
921
- return String(value || '').trim().toLowerCase();
922
- }
923
- function scoreWorkflow(workflow, { intent, surface, risk }) {
924
- let score = 0;
925
- const text = normalize(intent);
926
- if (surface && workflow.key === surface)
927
- score += 20;
928
- if (surface && workflow.key.includes(surface))
929
- score += 8;
930
- if (text) {
931
- for (const keyword of workflow.keywords || []) {
932
- if (text.includes(keyword))
933
- score += 4;
934
- }
935
- for (const phrase of workflow.useWhen || []) {
936
- const words = normalize(phrase).split(/\W+/).filter((word) => word.length > 3);
937
- if (words.some((word) => text.includes(word)))
938
- score += 1;
939
- }
940
- }
941
- if (risk === 'debug' && workflow.key === 'logs-debug')
942
- score += 6;
943
- const oauthIntent = /\b(?:oauth|google login|social login|provider callback)\b|đăng nhập google|cấu hình oauth|tích hợp oauth/u.test(text);
944
- if (oauthIntent && workflow.key === 'oauth')
945
- score += 20;
946
- if (oauthIntent && ['auth-context', 'api-endpoint'].includes(workflow.key))
947
- score -= 8;
948
- if (risk === 'write' && workflow.writeTools.length)
949
- score += 2;
950
- if (risk === 'destructive' && workflow.avoidTools.some((item) => normalize(item.when).includes('delete')))
951
- score += 2;
952
- if (workflow.key === 'dynamic-script' && /\b(patch|edit|update|fix|change)\b/.test(text) && /\b(sourcecode|source|compiledcode|script)\b/.test(text))
953
- score += 10;
954
- if (workflow.key === 'dynamic-script' && /flow step/.test(text) && /\b(sourcecode|source|compiledcode|script)\b/.test(text))
955
- score += 6;
956
- if (workflow.key === 'flow' && /\b(patch|edit|update|fix|change)\b/.test(text) && /\b(sourcecode|source|compiledcode|script)\b/.test(text))
957
- score -= 4;
958
- return score;
959
- }
960
- export function listWorkflowSurfaces() {
961
- return TOOL_WORKFLOWS.map(compactWorkflow);
962
- }
963
- function normalizeDetail(detail) {
964
- return ALL_DETAILS.includes(detail) ? detail : 'summary';
965
- }
966
- function normalizeRisk(risk) {
967
- const value = normalize(risk) || 'unknown';
968
- if (['read', 'write', 'destructive', 'debug', 'unknown'].includes(value))
969
- return value;
970
- if (['low', 'safe', 'readonly', 'read-only'].includes(value))
971
- return 'read';
972
- if (['medium', 'normal', 'moderate', 'mutation', 'mutating'].includes(value))
973
- return 'write';
974
- if (['high', 'danger', 'dangerous', 'delete', 'destructive-write'].includes(value))
975
- return 'destructive';
976
- return 'unknown';
977
- }
978
- export function discoverWorkflowRoutes({ intent = '', surface, risk = 'unknown', detail = 'summary', limit = 5, } = {}, profile = 'all', dynamicToolPacks = false) {
979
- const normalizedSurface = surface ? normalize(surface) : undefined;
980
- const normalizedDetail = normalizeDetail(detail);
981
- const normalizedRisk = normalizeRisk(risk);
982
- const availableSurfaces = profile === 'all' ? WORKFLOW_SURFACES : WORKFLOW_SURFACES_BY_PROFILE[profile];
983
- if (normalizedSurface && !availableSurfaces.includes(normalizedSurface)) {
984
- return {
985
- action: 'enfyra_workflows_discovered',
986
- profile,
987
- intent: intent || null,
988
- requestedSurface: surface || null,
989
- risk: normalizedRisk,
990
- detail: normalizedDetail,
991
- matchedWorkflowCount: 0,
992
- workflows: [],
993
- surfaces: availableSurfaces,
994
- guidance: [
995
- `The ${profile} profile does not expose the ${normalizedSurface} workflow. Reconnect with ENFYRA_MCP_PROFILE=all or the owning domain profile.`,
996
- ],
997
- };
998
- }
999
- const formatter = normalizedDetail === 'full'
1000
- ? fullWorkflow
1001
- : normalizedDetail === 'plan'
1002
- ? planWorkflow
1003
- : compactWorkflow;
1004
- const availableWorkflows = TOOL_WORKFLOWS.filter((workflow) => availableSurfaces.includes(workflow.key));
1005
- const scored = availableWorkflows
1006
- .map((workflow) => ({ workflow, score: scoreWorkflow(workflow, { intent, surface: normalizedSurface, risk: normalizedRisk }) }))
1007
- .filter((item) => !normalizedSurface || item.workflow.key === normalizedSurface || item.score > 0)
1008
- .sort((a, b) => b.score - a.score || a.workflow.key.localeCompare(b.workflow.key));
1009
- const selected = (scored.length ? scored : availableWorkflows.map((workflow) => ({ workflow, score: 0 })))
1010
- .slice(0, Math.max(1, Math.min(Number(limit) || 5, 10)));
1011
- return {
1012
- action: 'enfyra_workflows_discovered',
1013
- profile,
1014
- intent: intent || null,
1015
- requestedSurface: surface || null,
1016
- risk: normalizedRisk,
1017
- detail: normalizedDetail,
1018
- matchedWorkflowCount: scored.length,
1019
- workflows: selected.map((item) => ({
1020
- score: item.score,
1021
- ...formatter(item.workflow),
1022
- })),
1023
- nextSelection: dynamicToolPacks && selected[0]
1024
- ? {
1025
- tool: 'select_enfyra_workflow',
1026
- input: { surface: selected[0].workflow.key, mode: 'replace' },
1027
- }
1028
- : undefined,
1029
- surfaces: normalizedDetail === 'summary' ? availableSurfaces : undefined,
1030
- guidance: [
1031
- ...(dynamicToolPacks ? ['Call select_enfyra_workflow with nextSelection.input before using primaryPath domain tools; do not use search_enfyra_tools for tools already named by the selected workflow.'] : []),
1032
- 'Use this as progressive disclosure: pick the closest workflow and follow primaryPath in order instead of choosing from the flat MCP tool list.',
1033
- 'For writes, call get_enfyra_required_knowledge and pass the returned acknowledgement keys into write tools.',
1034
- 'Treat avoidTools as negative routing boundaries; they prevent near-correct tool choices from crossing the wrong platform contract.',
1035
- 'Use advancedTools only when the primaryPath says they fit; use escapeHatches only with explicit evidence that the front-door tool is insufficient.',
1036
- ],
1037
- };
1038
- }
1
+ export * from './workflow-definitions.js';
2
+ export * from './workflow-planner.js';
3
+ export * from './workflow-types.js';
1039
4
  //# sourceMappingURL=tool-routing.js.map