@gnar-engine/cli 1.0.0 → 1.0.2

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 (230) hide show
  1. package/assets/gnar-engine-logo-white.svg +9 -0
  2. package/bootstrap/deploy.localdev.yml +51 -0
  3. package/bootstrap/secrets.localdev.yml +27 -0
  4. package/bootstrap/services/agent/Dockerfile +23 -0
  5. package/bootstrap/services/agent/notes.md +28 -0
  6. package/bootstrap/services/agent/package.json +16 -0
  7. package/bootstrap/services/agent/src/app.js +52 -0
  8. package/bootstrap/services/agent/src/commands/agent.handler.js +104 -0
  9. package/bootstrap/services/agent/src/config.js +52 -0
  10. package/bootstrap/services/agent/src/controllers/http.controller.js +44 -0
  11. package/bootstrap/services/agent/src/controllers/message.controller.js +51 -0
  12. package/bootstrap/services/agent/src/db/migrations/01-init.js +50 -0
  13. package/bootstrap/services/agent/src/db/migrations/02-agent-service-init.js +36 -0
  14. package/bootstrap/services/agent/src/policies/agent.policy.js +13 -0
  15. package/bootstrap/services/agent/src/schema/Agent.schema.js +17 -0
  16. package/bootstrap/services/agent/src/services/agent.service.js +259 -0
  17. package/bootstrap/services/agent/src/services/chatgpt.service.js +46 -0
  18. package/bootstrap/services/agent/src/services/manifest.service.js +21 -0
  19. package/bootstrap/services/control/Dockerfile +23 -0
  20. package/bootstrap/services/control/Dockerfile.prod +37 -0
  21. package/bootstrap/services/control/README.md +25 -0
  22. package/bootstrap/services/control/package.json +16 -0
  23. package/bootstrap/services/control/src/app.js +45 -0
  24. package/bootstrap/services/control/src/commands/control.handler.js +231 -0
  25. package/bootstrap/services/control/src/commands/service.handler.js +81 -0
  26. package/bootstrap/services/control/src/commands/task.handler.js +247 -0
  27. package/bootstrap/services/control/src/config.js +55 -0
  28. package/bootstrap/services/control/src/controllers/http.controller.js +228 -0
  29. package/bootstrap/services/control/src/controllers/message.controller.js +40 -0
  30. package/bootstrap/services/control/src/db/migrations/01-init.js +50 -0
  31. package/bootstrap/services/control/src/db/migrations/02-control-service-init.js +60 -0
  32. package/bootstrap/services/control/src/db/migrations/03-alter-tasks.js +29 -0
  33. package/bootstrap/services/control/src/policies/task.policy.js +53 -0
  34. package/bootstrap/services/control/src/schema/control.schema.js +42 -0
  35. package/bootstrap/services/control/src/services/registry.service.js +83 -0
  36. package/bootstrap/services/control/src/services/reset.service.js +28 -0
  37. package/bootstrap/services/control/src/services/task.service.js +153 -0
  38. package/bootstrap/services/control/src/tests/control.test.js +50 -0
  39. package/bootstrap/services/notification/Dockerfile +23 -0
  40. package/bootstrap/services/notification/Dockerfile.prod +37 -0
  41. package/bootstrap/services/notification/README.md +3 -0
  42. package/bootstrap/services/notification/package.json +34 -0
  43. package/bootstrap/services/notification/src/app.js +51 -0
  44. package/bootstrap/services/notification/src/commands/command-bus.js +20 -0
  45. package/bootstrap/services/notification/src/commands/handlers/control.handler.js +18 -0
  46. package/bootstrap/services/notification/src/commands/handlers/notification.handler.js +157 -0
  47. package/bootstrap/services/notification/src/config.js +15 -0
  48. package/bootstrap/services/notification/src/controllers/message.controller.js +82 -0
  49. package/bootstrap/services/notification/src/services/logger.service.js +16 -0
  50. package/bootstrap/services/notification/src/services/ses.service.js +23 -0
  51. package/bootstrap/services/notification/src/templates/admin-order-recieved.hbs +136 -0
  52. package/bootstrap/services/notification/src/templates/admin-subscription-failed.hbs +87 -0
  53. package/bootstrap/services/notification/src/templates/customer-order-recieved.hbs +132 -0
  54. package/bootstrap/services/notification/src/templates/customer-subscription-failed.hbs +77 -0
  55. package/bootstrap/services/notification/src/tests/notification.test.js +0 -0
  56. package/bootstrap/services/portal/Dockerfile +23 -0
  57. package/bootstrap/services/portal/Dockerfile.remote +40 -0
  58. package/bootstrap/services/portal/README.md +22 -0
  59. package/bootstrap/services/portal/nginx.conf +12 -0
  60. package/bootstrap/services/portal/package.json +59 -0
  61. package/bootstrap/services/portal/public/favicon.ico +0 -0
  62. package/bootstrap/services/portal/public/gnar-white.png +0 -0
  63. package/bootstrap/services/portal/public/gnarengine-logo-black.png +0 -0
  64. package/bootstrap/services/portal/public/index.html +43 -0
  65. package/bootstrap/services/portal/public/logo192.png +0 -0
  66. package/bootstrap/services/portal/public/logo512.png +0 -0
  67. package/bootstrap/services/portal/public/manifest.json +25 -0
  68. package/bootstrap/services/portal/public/robots.txt +3 -0
  69. package/bootstrap/services/portal/src/App.js +56 -0
  70. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black.svg +1 -0
  71. package/bootstrap/services/portal/src/assets/Logo_Anchord_Black_Green.svg +1 -0
  72. package/bootstrap/services/portal/src/assets/Logo_Anchord_White_Green.svg +1 -0
  73. package/bootstrap/services/portal/src/assets/activity.svg +3 -0
  74. package/bootstrap/services/portal/src/assets/arrow.svg +3 -0
  75. package/bootstrap/services/portal/src/assets/bin-white.svg +3 -0
  76. package/bootstrap/services/portal/src/assets/bin.svg +3 -0
  77. package/bootstrap/services/portal/src/assets/check.svg +3 -0
  78. package/bootstrap/services/portal/src/assets/chevron.svg +3 -0
  79. package/bootstrap/services/portal/src/assets/contact.svg +3 -0
  80. package/bootstrap/services/portal/src/assets/dots-vertical.svg +5 -0
  81. package/bootstrap/services/portal/src/assets/eye-off.svg +3 -0
  82. package/bootstrap/services/portal/src/assets/eye.svg +4 -0
  83. package/bootstrap/services/portal/src/assets/gnar-engine-black.svg +47 -0
  84. package/bootstrap/services/portal/src/assets/gnar-engine-white.svg +47 -0
  85. package/bootstrap/services/portal/src/assets/gnar_engine.svg +3 -0
  86. package/bootstrap/services/portal/src/assets/gnarengine-logo-black.png +0 -0
  87. package/bootstrap/services/portal/src/assets/home.svg +3 -0
  88. package/bootstrap/services/portal/src/assets/link.svg +3 -0
  89. package/bootstrap/services/portal/src/assets/lock.svg +3 -0
  90. package/bootstrap/services/portal/src/assets/package.svg +4 -0
  91. package/bootstrap/services/portal/src/assets/raffle.svg +3 -0
  92. package/bootstrap/services/portal/src/assets/settings.svg +4 -0
  93. package/bootstrap/services/portal/src/assets/shopping-bag.svg +3 -0
  94. package/bootstrap/services/portal/src/assets/user-black.svg +3 -0
  95. package/bootstrap/services/portal/src/assets/user.svg +3 -0
  96. package/bootstrap/services/portal/src/assets/users.svg +3 -0
  97. package/bootstrap/services/portal/src/assets/wallet.svg +3 -0
  98. package/bootstrap/services/portal/src/css/style.css +1007 -0
  99. package/bootstrap/services/portal/src/data/data.js +70 -0
  100. package/bootstrap/services/portal/src/features/attributeFormRow/AttributeFormRow.jsx +32 -0
  101. package/bootstrap/services/portal/src/features/billingShipping/BillingShipping.jsx +160 -0
  102. package/bootstrap/services/portal/src/features/crud/crudEdit.less +230 -0
  103. package/bootstrap/services/portal/src/features/crud/crudList.less +134 -0
  104. package/bootstrap/services/portal/src/features/crud/crudPage.less +31 -0
  105. package/bootstrap/services/portal/src/features/crudContact/CrudContactList.jsx +108 -0
  106. package/bootstrap/services/portal/src/features/crudContact/CrudContactSingle.jsx +243 -0
  107. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderList.jsx +109 -0
  108. package/bootstrap/services/portal/src/features/crudOrder/CrudOrderSingle.jsx +315 -0
  109. package/bootstrap/services/portal/src/features/crudProducts/CrudProductList.jsx +104 -0
  110. package/bootstrap/services/portal/src/features/crudProducts/CrudProductSingle.jsx +388 -0
  111. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesList.jsx +104 -0
  112. package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesSingle.jsx +208 -0
  113. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionList.jsx +110 -0
  114. package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionSingle.jsx +261 -0
  115. package/bootstrap/services/portal/src/features/crudUser/CrudUserList.jsx +107 -0
  116. package/bootstrap/services/portal/src/features/crudUser/CrudUserSingle.jsx +402 -0
  117. package/bootstrap/services/portal/src/features/inventoryFormRow/InventoryFormRow.jsx +30 -0
  118. package/bootstrap/services/portal/src/features/lineItems/LineItems.jsx +113 -0
  119. package/bootstrap/services/portal/src/features/loginForm/LoginForm.jsx +56 -0
  120. package/bootstrap/services/portal/src/features/loginForm/loginForm.less +56 -0
  121. package/bootstrap/services/portal/src/features/notes/Notes.jsx +18 -0
  122. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetForm.jsx +96 -0
  123. package/bootstrap/services/portal/src/features/passwordReset/PasswordResetRequestForm.jsx +74 -0
  124. package/bootstrap/services/portal/src/features/priceFormRow/PriceFormRow.jsx +102 -0
  125. package/bootstrap/services/portal/src/features/priceFormRow/priceFormRow.less +24 -0
  126. package/bootstrap/services/portal/src/features/raffleEntriesList/RaffleEntriesList.jsx +99 -0
  127. package/bootstrap/services/portal/src/features/raffleProductFormRow/RaffleProductFormRow.jsx +46 -0
  128. package/bootstrap/services/portal/src/features/sidebar/Sidebar.jsx +64 -0
  129. package/bootstrap/services/portal/src/features/sidebar/sidebar.less +49 -0
  130. package/bootstrap/services/portal/src/features/skus/Skus.jsx +109 -0
  131. package/bootstrap/services/portal/src/features/subscriptionSchedule/SubscriptionSchedule.jsx +44 -0
  132. package/bootstrap/services/portal/src/features/taxonomyFormRow/TaxonomyFormRow.jsx +32 -0
  133. package/bootstrap/services/portal/src/features/user/User.jsx +54 -0
  134. package/bootstrap/services/portal/src/features/user/user.less +57 -0
  135. package/bootstrap/services/portal/src/includes/utilities.js +259 -0
  136. package/bootstrap/services/portal/src/index.js +14 -0
  137. package/bootstrap/services/portal/src/layouts/CrudLayout.jsx +50 -0
  138. package/bootstrap/services/portal/src/layouts/LoginLayout.jsx +17 -0
  139. package/bootstrap/services/portal/src/layouts/PortalLayout.jsx +48 -0
  140. package/bootstrap/services/portal/src/layouts/loginLayout.less +33 -0
  141. package/bootstrap/services/portal/src/layouts/portalLayout.less +67 -0
  142. package/bootstrap/services/portal/src/pages/contacts/Contacts.jsx +199 -0
  143. package/bootstrap/services/portal/src/pages/dashboard/Dashboard.jsx +17 -0
  144. package/bootstrap/services/portal/src/pages/integrations/Integrations.jsx +10 -0
  145. package/bootstrap/services/portal/src/pages/login/Login.jsx +15 -0
  146. package/bootstrap/services/portal/src/pages/login/login.less +10 -0
  147. package/bootstrap/services/portal/src/pages/orders/Orders.jsx +199 -0
  148. package/bootstrap/services/portal/src/pages/passwordReset/PasswordResetPage.jsx +15 -0
  149. package/bootstrap/services/portal/src/pages/passwordResetRequest/PasswordResetRequestPage.jsx +15 -0
  150. package/bootstrap/services/portal/src/pages/payments/Payments.jsx +10 -0
  151. package/bootstrap/services/portal/src/pages/portal/Portal.jsx +43 -0
  152. package/bootstrap/services/portal/src/pages/products/Products.jsx +212 -0
  153. package/bootstrap/services/portal/src/pages/raffleEntries/RaffleEntries.jsx +124 -0
  154. package/bootstrap/services/portal/src/pages/raffles/Raffles.jsx +186 -0
  155. package/bootstrap/services/portal/src/pages/reports/Reports.jsx +10 -0
  156. package/bootstrap/services/portal/src/pages/settings/Settings.jsx +10 -0
  157. package/bootstrap/services/portal/src/pages/subscriptions/Subscriptions.jsx +199 -0
  158. package/bootstrap/services/portal/src/pages/users/Users.jsx +193 -0
  159. package/bootstrap/services/portal/src/pages/users/users.less +25 -0
  160. package/bootstrap/services/portal/src/slices/authSlice.js +71 -0
  161. package/bootstrap/services/portal/src/store/configureStore.js +12 -0
  162. package/bootstrap/services/portal/src/styles/global.less +159 -0
  163. package/bootstrap/services/portal/src/styles/inputs.less +157 -0
  164. package/bootstrap/services/portal/src/styles/main.less +26 -0
  165. package/bootstrap/services/portal/src/ui/collapsible/Collapsible.jsx +97 -0
  166. package/bootstrap/services/portal/src/ui/collapsible/collapsible.less +23 -0
  167. package/bootstrap/services/portal/src/ui/customCheckbox/CustomCheckbox.jsx +17 -0
  168. package/bootstrap/services/portal/src/ui/customCheckbox/customCheckbox.less +42 -0
  169. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelect.jsx +63 -0
  170. package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelectPeriod.jsx +63 -0
  171. package/bootstrap/services/portal/src/ui/customSelect/CustomSelect.jsx +63 -0
  172. package/bootstrap/services/portal/src/ui/customSelect/customSelect.less +92 -0
  173. package/bootstrap/services/portal/src/ui/goBack/GoBack.jsx +19 -0
  174. package/bootstrap/services/portal/src/ui/loader/Loader.jsx +12 -0
  175. package/bootstrap/services/portal/src/ui/pagination/Pagination.jsx +23 -0
  176. package/bootstrap/services/portal/src/ui/repeater/Repeater.jsx +29 -0
  177. package/bootstrap/services/portal/src/ui/saveButton/SaveButton.jsx +69 -0
  178. package/bootstrap/services/portal/src/ui/saveButton/saveButton.less +0 -0
  179. package/bootstrap/services/rabbit-mq/Dockerfile.prod +9 -0
  180. package/bootstrap/services/user/Dockerfile +23 -0
  181. package/bootstrap/services/user/Dockerfile.prod +37 -0
  182. package/bootstrap/services/user/README.md +8 -0
  183. package/bootstrap/services/user/package.json +16 -0
  184. package/bootstrap/services/user/src/app.js +45 -0
  185. package/bootstrap/services/user/src/commands/session.handler.js +23 -0
  186. package/bootstrap/services/user/src/commands/user.handler.js +286 -0
  187. package/bootstrap/services/user/src/config.js +73 -0
  188. package/bootstrap/services/user/src/controllers/http.controller.js +156 -0
  189. package/bootstrap/services/user/src/controllers/message.controller.js +51 -0
  190. package/bootstrap/services/user/src/db/migrations/01-init.js +50 -0
  191. package/bootstrap/services/user/src/db/migrations/02-user-service-init.js +63 -0
  192. package/bootstrap/services/user/src/db/migrations/03-unauth-sessions.js +43 -0
  193. package/bootstrap/services/user/src/db/seeders/development/01-root-user.js +29 -0
  194. package/bootstrap/services/user/src/db/seeders/development/02-portal-admin-user.js +27 -0
  195. package/bootstrap/services/user/src/db/seeders/production/01-root-user.js +29 -0
  196. package/bootstrap/services/user/src/policies/user.policy.js +81 -0
  197. package/bootstrap/services/user/src/schema/user.schema.js +69 -0
  198. package/bootstrap/services/user/src/services/authentication.service.js +127 -0
  199. package/bootstrap/services/user/src/services/session.service.js +58 -0
  200. package/bootstrap/services/user/src/services/user.service.js +130 -0
  201. package/bootstrap/services/user/src/tests/user.test.js +126 -0
  202. package/package.json +3 -7
  203. package/src/agent/agent.client.js +28 -0
  204. package/src/agent/commands.js +48 -0
  205. package/src/cli.js +30 -0
  206. package/src/config.js +8 -0
  207. package/src/control/commands.js +156 -0
  208. package/src/control/control.client.js +127 -0
  209. package/src/dev/commands.js +71 -0
  210. package/src/dev/dev.service.js +320 -0
  211. package/src/engine/infra.js +142 -0
  212. package/src/helpers/helpers.js +63 -0
  213. package/src/profiles/command.js +170 -0
  214. package/src/profiles/profiles.client.js +101 -0
  215. package/src/scaffolder/commands.js +123 -0
  216. package/src/scaffolder/scaffolder.handler.js +252 -0
  217. package/src/services/client.js +174 -0
  218. package/templates/service/Dockerfile.hbs +20 -0
  219. package/templates/service/app.js.hbs +38 -0
  220. package/templates/service/commands/{{serviceName}}.handler.js.hbs +97 -0
  221. package/templates/service/config.js.hbs +48 -0
  222. package/templates/service/controllers/http.controller.js.hbs +87 -0
  223. package/templates/service/controllers/message.controller.js.hbs +51 -0
  224. package/templates/service/db/migrations/01-init.js.hbs +50 -0
  225. package/templates/service/db/migrations/02-{{lowerCase serviceName}}-service-init.js.hbs +23 -0
  226. package/templates/service/package.json.hbs +18 -0
  227. package/templates/service/policies/{{serviceName}}.policy.js.hbs +49 -0
  228. package/templates/service/schema/{{serviceName}}.schema.js.hbs +14 -0
  229. package/templates/service/services/{{serviceName}}.service.js.hbs +32 -0
  230. package/dist/cli.js +0 -18
@@ -0,0 +1,9 @@
1
+ <svg width="344" height="61" viewBox="0 0 344 61" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
2
+ <rect width="344" height="61" fill="url(#pattern0_238_39)"/>
3
+ <defs>
4
+ <pattern id="pattern0_238_39" patternContentUnits="objectBoundingBox" width="1" height="1">
5
+ <use xlink:href="#image0_238_39" transform="matrix(0.001 0 0 0.00563934 0 -0.0103607)"/>
6
+ </pattern>
7
+ <image id="image0_238_39" width="1000" height="181" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAC1CAYAAADMW9VQAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7tnQn8ddX0/wslmlMpRY/mpEkalQZS0kCSIVFIIcQflX6ojEmUmUiTMSkRDRo10KyZVE+T5jSiNPzfn6d7c5793ffec+89wz7nftbrtV7f791nn7XX+uy9z9lr77X3mWUWkxEwAkbACBgBI2AEjIARMAJGIILAk08+uSZ8Kvxf+FH49/AqkaxOMgJGwAgYASNgBIyAETACRsAIGAEjYATKQABHfD34P3BID5GwehllWqYRMAJGwAgYASNgBIyAETACRsAIGAEjECCAE35p6Jlnfp9twIyAETACRsAIGAEjYASMgBEwAkbACBiBkhHAEV+0j3OuS0/A85SshsUbgYlD4BkTZ7ENNgJGwAgYASNgBIyAETACRmAQArMPyDAr1wflGSDCl42AETACRsAIGAEjYASMgBEwAkbACBiBvgiwOj4rfHOfVfRr+grwRSNgBIyAETACRsAIGAEjYASMgBEwAkagGARwzt/ew0FXePvriynFUoyAETACRsAIGAEjYASMgBEwAkbACBiBgQjgiL8LvivjqN/G/28ZeKMzGAEjMBIC2jtiMgJGwAgYASNgBIyAETACRsAIRBHAIZ+NCyvBT8BXzDrrrI9FMzrRCBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYARKQ2DW0iTXJPjJJ5+cnaLn7BR/36yzzvpkTaq42JYiQBubC9Nm65j3EG3svy01tfFmUVdzY8SzZAj19M/GG2QDhkaANjB/56YHaQOP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"/>
8
+ </defs>
9
+ </svg>
@@ -0,0 +1,51 @@
1
+ # deploy.localdev.yml
2
+
3
+ # - This file is used to orchestrate locally running containers for development
4
+ # - environment: localdev is a named convention required for local development
5
+
6
+ config:
7
+ core-version: 1.0
8
+ architecture: microservice
9
+ region: eu-west-2
10
+ environment: localdev
11
+ namespace: my-project
12
+
13
+ services:
14
+ - name: control
15
+ listener_rules:
16
+ paths:
17
+ - /control
18
+ - /tasks
19
+ min-tasks: 1
20
+ max-tasks: 1
21
+ depends_on:
22
+ - control-db
23
+ command: ["npm", "run", "start:dev"]
24
+ ports:
25
+ - "4001:3000"
26
+
27
+ - name: user
28
+ listener_rules:
29
+ paths:
30
+ - /authenticate
31
+ - /users
32
+ min-tasks: 1
33
+ max-tasks: 1
34
+ depends_on:
35
+ - control-db
36
+ command: ["npm", "run", "start:dev"]
37
+ ports:
38
+ - "4002:3000"
39
+
40
+ - name: agent
41
+ listener_rules:
42
+ paths:
43
+ - /agent
44
+ min-tasks: 1
45
+ max-tasks: 1
46
+ depends_on:
47
+ - agent-db
48
+ command: ["npm", "run", "start:dev"]
49
+ ports:
50
+ - "4003:3000"
51
+
@@ -0,0 +1,27 @@
1
+ global:
2
+ RABBITMQ_URL: amqp://gnar_engine_rabbit_user:gn4rlyRaB81Tw4sh@rabbitmq:5672
3
+ RABBITMQ_USER: gnar_engine_rabbit_user
4
+ RABBITMQ_PASS: gn4rlyRaB81Tw4sh
5
+ services:
6
+ control:
7
+ MYSQL_HOST: control-db
8
+ MYSQL_DATABASE: ge_control_db
9
+ MYSQL_USER: ge_control_db_user
10
+ MYSQL_PASSWORD: zWF85kfGJNRA9ayp
11
+ MYSQL_RANDOM_ROOT_PASSWORD: wH0Pzkht75NvMd3b
12
+ user:
13
+ MYSQL_HOST: user-db
14
+ MYSQL_DATABASE: ge_user_db
15
+ MYSQL_USER: ge_user_db_user
16
+ MYSQL_PASSWORD: WTEYWqs6wDBX459p
17
+ MYSQL_RANDOM_ROOT_PASSWORD: GXEy5T7Cp2zuOTah
18
+ ROOT_ADMIN_EMAIL: adam@gnar.co.uk
19
+ ROOT_ADMIN_USERNAME: engineadmin
20
+ ROOT_ADMIN_PASSWORD: n0eYk6aoiYAeSur1
21
+ ROOT_ADMIN_API_KEY: qydfeMcyutzIXBvHjrB2qGL9hTdco81X
22
+ agent:
23
+ MYSQL_HOST: agent-db
24
+ MYSQL_DATABASE: ge_agent_db
25
+ MYSQL_USER: ge_agent_db_user
26
+ MYSQL_PASSWORD: 4BARYvygGSv6BRPH
27
+ MYSQL_RANDOM_ROOT_PASSWORD: s27o951anIt8Lqmy
@@ -0,0 +1,23 @@
1
+ # Dockerfile for Agent Service
2
+ FROM node:20-alpine
3
+
4
+ # Set the working directory
5
+ WORKDIR /usr/gnar_engine/app
6
+
7
+ # Define a global env var
8
+ ENV GLOBAL_SERVICE_BASE_DIR=/usr/gnar_engine/app/src/
9
+
10
+ # Copy package.json and package-lock.json
11
+ COPY ./services/agent/package*.json ./
12
+
13
+ # Install nodemon
14
+ RUN npm install -g nodemon
15
+
16
+ # Install app dependencies
17
+ RUN npm install
18
+
19
+ # Expose the port the service will run on
20
+ EXPOSE 3000
21
+
22
+ # Start the application
23
+ CMD ["nodemon", "--watch", "./gnar_engine", "./gnar_engine/app.js"]
@@ -0,0 +1,28 @@
1
+ # Gnar MCP Notes
2
+
3
+ ### Aims
4
+
5
+ - We don't want to provide all command implementations (with payload information) until we know what commands are required.
6
+
7
+ Step 1: Gather Facts
8
+
9
+ - All first prompts (no chatId provided) are 'gather facts'.
10
+ - This prompt will be augmented with the all service/model schemas and a list of all available commands e.g. userService.create, userService.update.
11
+ - From the client input the model should generate an action plan with an ordered list of the commands required, and also request the exact data required from the user to carry out the plan (based on the schemas provided in the augmented prompt).
12
+
13
+ Step 2: Confirm plan
14
+
15
+ - All further prompts (chatId provided) that do not have a 'confirmed plan' are 'confirm plan'.
16
+ - This prompt will be augmented with the all service/model schemas, a list of all available commands, a manifest containing the command implementations (including payload information) for each command in the most recently proposed action plan, the most recently proposed action plan itself, and a list of all previous user inputs and response texts.
17
+ - The model should determine from the resources provided if the action plan is accurate and if we have enough information, request conmfirmation from the user to action the request. If not we should request further information from the user until all information is provided. Should reassess the proposed plan based on user input and the command implementations provided in the prompt augmentation. If the plan is suitable, we have all the required information, and the user has confirmed that we can action the request, the model should include - actionPlanGoAhead = true in the response, and also the first command execution payload in the actionPlan.
18
+
19
+
20
+ // should we postback before actioning?
21
+ Step 3: Action plan loop
22
+ - Before returning back to the client - if the agent response has 'actionPlanGoAhead' = true, we should initalise the action plan execution loop
23
+ - Action Plan Execution Loop (foreach action plan command):
24
+ - The command will be triggered with the included payload.
25
+ - The result of the first command will be passed back to the agent with the system prompt, action plan, all messages, schemas, relevant command implementations.
26
+ - This prompt should confirm the payload for the next command in the action Plan.
27
+
28
+ - Upon the last command being executed, the model will be prompted to provide a text output to confirm the result of the action plan.
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "agent-service",
3
+ "version": "1.0.0",
4
+ "description": "LLM Agent microservice for Gnar Engine",
5
+ "type": "module",
6
+ "scripts": {
7
+ "start": "node ./src/app.js",
8
+ "start:dev": "nodemon --watch ./src ./src/app.js"
9
+ },
10
+ "dependencies": {
11
+ "@gnar-engine/core": "^1.0.1",
12
+ "openai": "5.13.1"
13
+ },
14
+ "author": "Gnar Software",
15
+ "license": "MIT"
16
+ }
@@ -0,0 +1,52 @@
1
+ import { message, http, logger, db, registerService } from '@gnar-engine/core';
2
+ import { config } from './config.js';
3
+ import { messageHandlers } from './controllers/message.controller.js';
4
+ import { httpController as AgentPlatformHttpController } from './controllers/http.controller.js';
5
+ import { manifestService } from './services/manifest.service.js';
6
+ import { Agent } from './services/agent.service.js';
7
+
8
+ /**
9
+ * Initialise service
10
+ */
11
+ export const initService = async () => {
12
+
13
+ // Run migrations
14
+ db.migrations.runMigrations({config});
15
+ db.seeders.runSeeders({config});
16
+
17
+ // Import command handlers after the command bus is initialised
18
+ await import('./commands/agent.handler.js');
19
+ // Add more handlers as needed
20
+
21
+ // Initialise and register message handlers
22
+ await message.init({
23
+ config: config.message,
24
+ handlers: messageHandlers
25
+ });
26
+
27
+ // Register http routes
28
+ await http.registerRoutes({
29
+ controllers: [
30
+ AgentPlatformHttpController,
31
+ ]
32
+ });
33
+
34
+ // Initialise agent client
35
+ await Agent.init();
36
+
37
+ // Start the HTTP server
38
+ await http.start();
39
+
40
+ // Register service with control service
41
+ await registerService();
42
+
43
+ // Start manifest generation poll
44
+ //setInterval(() => {
45
+ manifestService.generateServiceManifests();
46
+ //}, 3600);
47
+
48
+ logger.info('G n a r E n g i n e | Agent Service initialised successfully.');
49
+ }
50
+
51
+ initService();
52
+
@@ -0,0 +1,104 @@
1
+ import { commands, logger } from '@gnar-engine/core';
2
+ import { Agent } from '../services/agent.service.js';
3
+ import { config } from '../config.js';
4
+
5
+
6
+ /**
7
+ * Prompt the LLM agent
8
+ */
9
+ commands.register('agentService.prompt', async ({input, chatId, authUser}) => {
10
+ try {
11
+ logger.info('recieved input' + JSON.stringify(input));
12
+ let chatContextToStore = {};
13
+
14
+ const [manifests, resolvedChatId, chat] = await Promise.all([
15
+ // Get the manifests
16
+ commands.execute('controlService.getManifests'),
17
+
18
+ // Create a new chat if chatId is not provided
19
+ (async () => {
20
+ if (!chatId) {
21
+ return await Agent.createChat({
22
+ userId: '',
23
+ title: input.substring(0, 50),
24
+ sessionKey: input.sessionKey
25
+ });
26
+ }
27
+
28
+ return chatId
29
+ })(),
30
+
31
+ // Retrieve existing chat if chatId is provided
32
+ (async () => {
33
+ if (chatId) {
34
+ return await Agent.getChat({chatId});
35
+ }
36
+
37
+ return null;
38
+ })()
39
+ ]);
40
+
41
+ let preparedInput;
42
+
43
+ // Gather facts
44
+ if (!chatId) {
45
+ preparedInput = await Agent.prepareGatherFactsPrompt({inputText: input, manifests: manifests});
46
+ }
47
+
48
+ // Prepare Plan
49
+ else if (chat) {
50
+ await logger.info('GOT HERE WITH CHAT: ' + JSON.stringify(chat));
51
+ preparedInput = await Agent.preparePlanPrompt({inputText: input, manifests: manifests, chat: chat});
52
+ }
53
+
54
+ // Infer
55
+ let agentResponse = await Agent.infer({preparedInput});
56
+ logger.info('Agent response: ' + agentResponse);
57
+ agentResponse = JSON.parse(agentResponse);
58
+
59
+ // Collect context from response
60
+ chatContextToStore.actionPlan = agentResponse.actionPlan || null;
61
+ chatContextToStore.input = input;
62
+ chatContextToStore.responseText = agentResponse.responseText || null;
63
+
64
+ // Collect required command implementations from manifests to store for next time
65
+ if (agentResponse.commandsRequired) {
66
+ chatContextToStore.commandsManifest = [];
67
+
68
+ agentResponse.commandsRequired.forEach((commandRequired) => {
69
+ manifests.manifests.forEach((manifest) => {
70
+ //logger.info('got here ' + commandRequired + ' ' + JSON.stringify(manifest.manifest) );
71
+ if (manifest.manifest?.commandImplementations?.[commandRequired]) {
72
+ chatContextToStore.commandsManifest.push(manifest.manifest.commandImplementations[commandRequired]);
73
+ }
74
+ })
75
+ });
76
+ }
77
+
78
+ logger.info('Chat context to store: ' + JSON.stringify(chatContextToStore));
79
+
80
+ // Store chat messages
81
+ chatId = resolvedChatId;
82
+ Agent.createChatMessage({
83
+ chatId: chatId,
84
+ userName: authUser.username,
85
+ context: chatContextToStore
86
+ });
87
+
88
+ // Plan execution loop
89
+ if (agentResponse.actionPlan) {
90
+ logger.info('Executing plan: ' + agentResponse.actionPlan);
91
+
92
+ }
93
+
94
+ let response = {
95
+ structuredResponse: agentResponse,
96
+ chatId: chatId
97
+ };
98
+
99
+ return response;
100
+ } catch (err) {
101
+ logger.error("Error handling LLM agent prompt: " + err);
102
+ throw err;
103
+ }
104
+ });
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Gnar Engine Service Config
3
+ */
4
+ export const config = {
5
+ // service name
6
+ serviceName: 'agentService',
7
+
8
+ // microservice | modular-monolith
9
+ architecture: process.env.GLOBAL_ARCHITECTURE || 'microservice',
10
+
11
+ // web server
12
+ http: {
13
+ allowedOrigins: [],
14
+ allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
15
+ allowedHeaders: ['Content-Type', 'Authorization'],
16
+ rateLimiting: {
17
+ max: 3,
18
+ timeWindow: '1 second',
19
+ }
20
+ },
21
+
22
+ // database
23
+ db: {
24
+ // type: mongodb | mysql
25
+ type: 'mysql',
26
+
27
+ // MongoDB
28
+ connectionUrl: process.env.AGENT_MONGO_URL,
29
+ connectionArgs: {},
30
+
31
+ // MySQL
32
+ host: process.env.AGENT_MYSQL_HOST,
33
+ user: process.env.AGENT_MYSQL_USER,
34
+ password: process.env.AGENT_MYSQL_PASSWORD,
35
+ database: process.env.AGENT_MYSQL_DATABASE,
36
+ connectionLimit: 10,
37
+ queueLimit: 20,
38
+ maxRetries: 5
39
+ },
40
+
41
+ // message broker
42
+ message: {
43
+ url: process.env.RABBITMQ_URL,
44
+ queueName: 'agentServiceQueue',
45
+ prefetch: 20
46
+ },
47
+
48
+ hashNameSpace: '',
49
+
50
+ // Default agent type
51
+ agent: 'chatgpt'
52
+ }
@@ -0,0 +1,44 @@
1
+ import { commands, logger } from '@gnar-engine/core';
2
+ import { authorise } from '../policies/agent.policy.js';
3
+
4
+ /**
5
+ * HTTP controller
6
+ */
7
+ export const httpController = {
8
+
9
+ /**
10
+ * Prompt the agent
11
+ */
12
+ agentPrompt: {
13
+ method: 'POST',
14
+ url: '/agent/prompt',
15
+ preHandler: async (request, reply) => authorise.agentPrompt(request, reply),
16
+ handler: async (request, reply) => {
17
+ logger.info('Received agent prompt request' + JSON.stringify(request.body));
18
+ const params = {
19
+ input: request.body.textInput,
20
+ chatId: request.body.chatId || '',
21
+ authUser: request.user
22
+ };
23
+
24
+ // Sanitize input (remove all JSON delimiters)
25
+ params.input = params.input.replace(/[\{\}\[\]\"\'\:\,]/g, '');
26
+
27
+ // execute
28
+ let response;
29
+ logger.info('params' + JSON.stringify(params));
30
+ try {
31
+ response = await commands.execute('prompt', params);
32
+ } catch (error) {
33
+ logger.error(error.message);
34
+ return reply.code(500).send({ error: error.message});
35
+ }
36
+
37
+ logger.info('response is: ' + JSON.stringify(response));
38
+
39
+ // handle response
40
+ reply.code(200).send(response);
41
+ }
42
+ },
43
+
44
+ }
@@ -0,0 +1,51 @@
1
+ import { commands } from '@gnar-engine/core';
2
+
3
+ export const messageHandlers = {
4
+
5
+ getAgent: async (payload) => {
6
+ let result;
7
+ if (payload.data?.id) {
8
+ result = await commands.execute('getSingleAgent', {
9
+ id: payload.data.id
10
+ });
11
+ } else if (payload.data?.email) {
12
+ result = await commands.execute('getSingleAgent', {
13
+ email: payload.data.email
14
+ });
15
+ } else {
16
+ throw new Error('No Agent ID or email provided');
17
+ }
18
+ if (!result) {
19
+ throw new Error('Agent not found');
20
+ }
21
+ return { Agent: result };
22
+ },
23
+
24
+ getManyAgents: async (payload) => {
25
+ const results = await commands.execute('getManyAgents', {});
26
+ return { agents: results };
27
+ },
28
+
29
+ createAgent: async (payload) => {
30
+ const results = await commands.execute('createAgents', {
31
+ agents: [payload.data.Agent]
32
+ });
33
+ return { agents: results };
34
+ },
35
+
36
+ updateAgent: async (payload) => {
37
+ const result = await commands.execute('updateAgent', {
38
+ id: payload.data.id,
39
+ newAgentData: payload.data
40
+ });
41
+ return { Agent: result };
42
+ },
43
+
44
+ deleteAgent: async (payload) => {
45
+ await commands.execute('deleteAgent', {
46
+ id: payload.data.id
47
+ });
48
+ return { message: 'Agent deleted' };
49
+ },
50
+
51
+ };
@@ -0,0 +1,50 @@
1
+ import { logger, db } from '@gnar-engine/core';
2
+
3
+ /**
4
+ * Up
5
+ */
6
+ export const up = async () => {
7
+ await initDatabaseTables();
8
+ }
9
+
10
+ /**
11
+ * Down
12
+ */
13
+ export const down = async () => {
14
+ await dropDatabaseTables();
15
+ }
16
+
17
+ /**
18
+ * Create all tables
19
+ */
20
+ export const initDatabaseTables = async () => {
21
+
22
+ // Migrations table
23
+ logger.info("Creating migrations table");
24
+ const createMigrationsTableQuery = `
25
+ CREATE TABLE migrations (
26
+ id INT AUTO_INCREMENT PRIMARY KEY,
27
+ name VARCHAR(255) NOT NULL UNIQUE,
28
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
29
+ )`;
30
+ await db.query(createMigrationsTableQuery);
31
+
32
+ // Seeders table
33
+ logger.info("Creating seeders table");
34
+ const createSeedersTableQuery = `
35
+ CREATE TABLE seeders (
36
+ id INT AUTO_INCREMENT PRIMARY KEY,
37
+ name VARCHAR(255) NOT NULL UNIQUE,
38
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
39
+ )`;
40
+ await db.query(createSeedersTableQuery);
41
+ }
42
+
43
+ /**
44
+ * Drop all tables
45
+ */
46
+ export const dropDatabaseTables = async () => {
47
+ logger.info('Dropping tables');
48
+ await db.query('DROP TABLE IF EXISTS migrations');
49
+ await db.query('DROP TABLE IF EXISTS seeders');
50
+ }
@@ -0,0 +1,36 @@
1
+ import { logger, db } from '@gnar-engine/core';
2
+
3
+ /**
4
+ * Up
5
+ */
6
+ export const up = async () => {
7
+ logger.info('Creating table: agent-chats');
8
+ await db.query(`
9
+ CREATE TABLE agent_chats (
10
+ id CHAR(36) PRIMARY KEY,
11
+ user_id CHAR(36) NOT NULL,
12
+ title VARCHAR(255) NOT NULL,
13
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
14
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
15
+ )
16
+ `);
17
+
18
+ logger.info('Creating table: agent-chat-messages');
19
+ await db.query(`
20
+ CREATE TABLE agent_chat_messages (
21
+ id CHAR(36) PRIMARY KEY,
22
+ chat_id CHAR(36) NOT NULL,
23
+ user_name VARCHAR(255) NOT NULL,
24
+ context MEDIUMTEXT NOT NULL,
25
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
26
+ )
27
+ `);
28
+ }
29
+
30
+ /**
31
+ * Down
32
+ */
33
+ export const down = async () => {
34
+ logger.info('Dropping table: agents');
35
+ await db.query('DROP TABLE IF EXISTS agents');
36
+ }
@@ -0,0 +1,13 @@
1
+ import { config } from '../config.js';
2
+
3
+ export const authorise = {
4
+
5
+ /**
6
+ * Authorise agent prompt
7
+ */
8
+ agentPrompt: async (request, reply) => {
9
+ if (!request.user || request.user.role !== 'service_admin') {
10
+ reply.code(403).send({error: 'not authorised'});
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ import { schema } from '@gnar-engine/core';
2
+ import { config } from '../config.js';
3
+
4
+ export const AgentSchema = {
5
+ schemaName: 'agentService.AgentSchema',
6
+ schema: {
7
+ type: 'object',
8
+ properties: {
9
+ // Add your properties here
10
+
11
+ },
12
+ required: [],
13
+ additionalProperties: false
14
+ }
15
+ };
16
+
17
+ export const validateAgent = schema.compile(AgentSchema);