crewly 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +39 -5
  2. package/config/roles/developer/prompt.md +1 -1
  3. package/config/roles/orchestrator/prompt.md +20 -5
  4. package/config/runtime_scripts/runtime-config.json +7 -0
  5. package/config/skills/agent/core/calendar-create/SKILL.md +62 -0
  6. package/config/skills/agent/core/calendar-create/execute.sh +91 -0
  7. package/config/skills/agent/core/calendar-create/execute.test.sh +80 -0
  8. package/config/skills/agent/core/calendar-list/SKILL.md +58 -0
  9. package/config/skills/agent/core/calendar-list/execute.sh +88 -0
  10. package/config/skills/agent/core/calendar-list/execute.test.sh +71 -0
  11. package/config/skills/agent/core/count-json/SKILL.md +61 -0
  12. package/config/skills/agent/core/count-json/execute.sh +52 -0
  13. package/config/skills/agent/core/count-json/execute.test.sh +35 -0
  14. package/config/skills/agent/core/gmail-read/SKILL.md +61 -0
  15. package/config/skills/agent/core/gmail-read/execute.sh +62 -0
  16. package/config/skills/agent/core/gmail-read/execute.test.sh +68 -0
  17. package/config/skills/agent/core/gmail-search/SKILL.md +64 -0
  18. package/config/skills/agent/core/gmail-search/execute.sh +70 -0
  19. package/config/skills/agent/core/gmail-search/execute.test.sh +67 -0
  20. package/config/skills/agent/core/gmail-send/SKILL.md +69 -0
  21. package/config/skills/agent/core/gmail-send/execute.sh +114 -0
  22. package/config/skills/agent/core/gmail-send/execute.test.sh +83 -0
  23. package/config/skills/agent/core/record-prediction/SKILL.md +61 -0
  24. package/config/skills/agent/core/record-prediction/execute.sh +90 -0
  25. package/config/skills/agent/core/record-prediction/execute.test.sh +67 -0
  26. package/config/skills/agent/core/resolve-prediction/SKILL.md +61 -0
  27. package/config/skills/agent/core/resolve-prediction/execute.sh +87 -0
  28. package/config/skills/agent/core/resolve-prediction/execute.test.sh +74 -0
  29. package/config/skills/agent/core/set-focus/SKILL.md +64 -0
  30. package/config/skills/agent/core/set-focus/execute.sh +73 -0
  31. package/config/skills/agent/core/set-focus/execute.test.sh +67 -0
  32. package/config/skills/agent/core/suppress-noise/SKILL.md +59 -0
  33. package/config/skills/agent/core/suppress-noise/execute.sh +68 -0
  34. package/config/skills/agent/core/suppress-noise/execute.test.sh +58 -0
  35. package/config/skills/orchestrator/list-missions/SKILL.md +47 -0
  36. package/config/skills/orchestrator/list-missions/execute.sh +34 -0
  37. package/config/skills/orchestrator/list-missions/execute.test.sh +33 -0
  38. package/config/slack-master-app-manifest.json +64 -0
  39. package/dist/backend/backend/src/constants.d.ts +186 -0
  40. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  41. package/dist/backend/backend/src/constants.js +196 -0
  42. package/dist/backend/backend/src/constants.js.map +1 -1
  43. package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.d.ts +76 -0
  44. package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.d.ts.map +1 -0
  45. package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.js +262 -0
  46. package/dist/backend/backend/src/controllers/agent-self-improvement/agent-self-improvement.controller.js.map +1 -0
  47. package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
  48. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +3 -1
  49. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
  50. package/dist/backend/backend/src/controllers/google/google.controller.d.ts +100 -0
  51. package/dist/backend/backend/src/controllers/google/google.controller.d.ts.map +1 -0
  52. package/dist/backend/backend/src/controllers/google/google.controller.js +293 -0
  53. package/dist/backend/backend/src/controllers/google/google.controller.js.map +1 -0
  54. package/dist/backend/backend/src/controllers/google/google.routes.d.ts +26 -0
  55. package/dist/backend/backend/src/controllers/google/google.routes.d.ts.map +1 -0
  56. package/dist/backend/backend/src/controllers/google/google.routes.js +38 -0
  57. package/dist/backend/backend/src/controllers/google/google.routes.js.map +1 -0
  58. package/dist/backend/backend/src/controllers/oauth/oauth.routes.d.ts.map +1 -1
  59. package/dist/backend/backend/src/controllers/oauth/oauth.routes.js +31 -0
  60. package/dist/backend/backend/src/controllers/oauth/oauth.routes.js.map +1 -1
  61. package/dist/backend/backend/src/controllers/request-types.d.ts +6 -2
  62. package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
  63. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  64. package/dist/backend/backend/src/controllers/slack/slack.controller.js +209 -2
  65. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  66. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  67. package/dist/backend/backend/src/controllers/team/team.controller.js +4 -0
  68. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  69. package/dist/backend/backend/src/index.d.ts +1 -0
  70. package/dist/backend/backend/src/index.d.ts.map +1 -1
  71. package/dist/backend/backend/src/index.js +92 -8
  72. package/dist/backend/backend/src/index.js.map +1 -1
  73. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  74. package/dist/backend/backend/src/routes/api.routes.js +10 -0
  75. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  76. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +10 -0
  77. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  78. package/dist/backend/backend/src/services/agent/agent-registration.service.js +32 -4
  79. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  80. package/dist/backend/backend/src/services/agent/opencode-runtime.service.d.ts +114 -0
  81. package/dist/backend/backend/src/services/agent/opencode-runtime.service.d.ts.map +1 -0
  82. package/dist/backend/backend/src/services/agent/opencode-runtime.service.js +185 -0
  83. package/dist/backend/backend/src/services/agent/opencode-runtime.service.js.map +1 -0
  84. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  85. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +22 -1
  86. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  87. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +1 -1
  88. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
  89. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +15 -3
  90. package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
  91. package/dist/backend/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -1
  92. package/dist/backend/backend/src/services/agent/runtime-service.factory.js +9 -0
  93. package/dist/backend/backend/src/services/agent/runtime-service.factory.js.map +1 -1
  94. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +23 -0
  95. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
  96. package/dist/backend/backend/src/services/ai/prompt-builder.service.js +45 -0
  97. package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
  98. package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts +43 -3
  99. package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts.map +1 -1
  100. package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.js +85 -4
  101. package/dist/backend/backend/src/services/ai/prompt-modules/memory-reference.module.js.map +1 -1
  102. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +2 -0
  103. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
  104. package/dist/backend/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
  105. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  106. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
  107. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  108. package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts +45 -0
  109. package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts.map +1 -0
  110. package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.js +59 -0
  111. package/dist/backend/backend/src/services/ai/self-improvement/agent-memory-provider.js.map +1 -0
  112. package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.d.ts +137 -0
  113. package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.d.ts.map +1 -0
  114. package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.js +216 -0
  115. package/dist/backend/backend/src/services/ai/self-improvement/consolidation-scheduler.service.js.map +1 -0
  116. package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts +4 -1
  117. package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts.map +1 -1
  118. package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.js +3 -1
  119. package/dist/backend/backend/src/services/ai/self-improvement/prediction-calibration.service.js.map +1 -1
  120. package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts +8 -0
  121. package/dist/backend/backend/src/services/cloud/cloud-initializer.d.ts.map +1 -1
  122. package/dist/backend/backend/src/services/cloud/cloud-initializer.js +25 -0
  123. package/dist/backend/backend/src/services/cloud/cloud-initializer.js.map +1 -1
  124. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  125. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  126. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +1 -0
  127. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  128. package/dist/backend/backend/src/services/google/calendar.service.d.ts +98 -0
  129. package/dist/backend/backend/src/services/google/calendar.service.d.ts.map +1 -0
  130. package/dist/backend/backend/src/services/google/calendar.service.js +125 -0
  131. package/dist/backend/backend/src/services/google/calendar.service.js.map +1 -0
  132. package/dist/backend/backend/src/services/google/gmail.service.d.ts +165 -0
  133. package/dist/backend/backend/src/services/google/gmail.service.d.ts.map +1 -0
  134. package/dist/backend/backend/src/services/google/gmail.service.js +296 -0
  135. package/dist/backend/backend/src/services/google/gmail.service.js.map +1 -0
  136. package/dist/backend/backend/src/services/google/google-api.client.d.ts +44 -0
  137. package/dist/backend/backend/src/services/google/google-api.client.d.ts.map +1 -0
  138. package/dist/backend/backend/src/services/google/google-api.client.js +104 -0
  139. package/dist/backend/backend/src/services/google/google-api.client.js.map +1 -0
  140. package/dist/backend/backend/src/services/google/google-workspace-token.service.d.ts +159 -0
  141. package/dist/backend/backend/src/services/google/google-workspace-token.service.d.ts.map +1 -0
  142. package/dist/backend/backend/src/services/google/google-workspace-token.service.js +274 -0
  143. package/dist/backend/backend/src/services/google/google-workspace-token.service.js.map +1 -0
  144. package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts +1 -1
  145. package/dist/backend/backend/src/services/mcp-tool-definitions.js +1 -1
  146. package/dist/backend/backend/src/services/mcp-tool-definitions.js.map +1 -1
  147. package/dist/backend/backend/src/services/runtime-adapter.d.ts +10 -1
  148. package/dist/backend/backend/src/services/runtime-adapter.d.ts.map +1 -1
  149. package/dist/backend/backend/src/services/runtime-adapter.js +12 -1
  150. package/dist/backend/backend/src/services/runtime-adapter.js.map +1 -1
  151. package/dist/backend/backend/src/services/settings/settings.service.d.ts.map +1 -1
  152. package/dist/backend/backend/src/services/settings/settings.service.js +1 -0
  153. package/dist/backend/backend/src/services/settings/settings.service.js.map +1 -1
  154. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.d.ts +12 -1
  155. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
  156. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js +30 -0
  157. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
  158. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.d.ts +186 -0
  159. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.d.ts.map +1 -0
  160. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js +409 -0
  161. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js.map +1 -0
  162. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts +95 -1
  163. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  164. package/dist/backend/backend/src/services/slack/slack-initializer.js +284 -4
  165. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  166. package/dist/backend/backend/src/services/slack/slack-instance-registry.service.d.ts +178 -0
  167. package/dist/backend/backend/src/services/slack/slack-instance-registry.service.d.ts.map +1 -0
  168. package/dist/backend/backend/src/services/slack/slack-instance-registry.service.js +392 -0
  169. package/dist/backend/backend/src/services/slack/slack-instance-registry.service.js.map +1 -0
  170. package/dist/backend/backend/src/services/slack/slack.service.d.ts +76 -1
  171. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  172. package/dist/backend/backend/src/services/slack/slack.service.js +234 -47
  173. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  174. package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.d.ts +78 -0
  175. package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.d.ts.map +1 -0
  176. package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.js +129 -0
  177. package/dist/backend/backend/src/services/v3/fallback-trigger-cleanup.subscriber.js.map +1 -0
  178. package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.d.ts +117 -0
  179. package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.d.ts.map +1 -0
  180. package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.js +214 -0
  181. package/dist/backend/backend/src/services/v3/kr-skill-measurer.service.js.map +1 -0
  182. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts +6 -0
  183. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -1
  184. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +33 -0
  185. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -1
  186. package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.d.ts +116 -0
  187. package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.d.ts.map +1 -0
  188. package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.js +254 -0
  189. package/dist/backend/backend/src/services/v3/okr-owner-guidance.service.js.map +1 -0
  190. package/dist/backend/backend/src/types/index.d.ts +11 -1
  191. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  192. package/dist/backend/backend/src/types/index.js.map +1 -1
  193. package/dist/backend/backend/src/types/settings.types.d.ts +1 -1
  194. package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
  195. package/dist/backend/backend/src/types/settings.types.js +7 -0
  196. package/dist/backend/backend/src/types/settings.types.js.map +1 -1
  197. package/dist/backend/backend/src/types/slack.types.d.ts +141 -2
  198. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  199. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  200. package/dist/backend/backend/src/types/team-template.types.d.ts +2 -2
  201. package/dist/backend/backend/src/types/team-template.types.d.ts.map +1 -1
  202. package/dist/backend/backend/src/types/team-template.types.js +1 -1
  203. package/dist/backend/backend/src/types/team-template.types.js.map +1 -1
  204. package/dist/backend/backend/src/types/v2/mission.types.d.ts +2 -0
  205. package/dist/backend/backend/src/types/v2/mission.types.d.ts.map +1 -1
  206. package/dist/backend/backend/src/types/v2/mission.types.js.map +1 -1
  207. package/dist/backend/backend/src/utils/terminal-string-ops.d.ts +2 -0
  208. package/dist/backend/backend/src/utils/terminal-string-ops.d.ts.map +1 -1
  209. package/dist/backend/backend/src/utils/terminal-string-ops.js +14 -0
  210. package/dist/backend/backend/src/utils/terminal-string-ops.js.map +1 -1
  211. package/dist/backend/build-info.json +2 -2
  212. package/dist/cli/backend/src/constants.d.ts +186 -0
  213. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  214. package/dist/cli/backend/src/constants.js +196 -0
  215. package/dist/cli/backend/src/constants.js.map +1 -1
  216. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +10 -0
  217. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  218. package/dist/cli/backend/src/services/agent/agent-registration.service.js +32 -4
  219. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  220. package/dist/cli/backend/src/services/agent/opencode-runtime.service.d.ts +114 -0
  221. package/dist/cli/backend/src/services/agent/opencode-runtime.service.d.ts.map +1 -0
  222. package/dist/cli/backend/src/services/agent/opencode-runtime.service.js +185 -0
  223. package/dist/cli/backend/src/services/agent/opencode-runtime.service.js.map +1 -0
  224. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  225. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +22 -1
  226. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  227. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts +1 -1
  228. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
  229. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js +15 -3
  230. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
  231. package/dist/cli/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -1
  232. package/dist/cli/backend/src/services/agent/runtime-service.factory.js +9 -0
  233. package/dist/cli/backend/src/services/agent/runtime-service.factory.js.map +1 -1
  234. package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts +23 -0
  235. package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
  236. package/dist/cli/backend/src/services/ai/prompt-builder.service.js +45 -0
  237. package/dist/cli/backend/src/services/ai/prompt-builder.service.js.map +1 -1
  238. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts +43 -3
  239. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts.map +1 -1
  240. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js +85 -4
  241. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js.map +1 -1
  242. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts +2 -0
  243. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.d.ts.map +1 -1
  244. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-module.interface.js.map +1 -1
  245. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  246. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
  247. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  248. package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts +45 -0
  249. package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.d.ts.map +1 -0
  250. package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.js +59 -0
  251. package/dist/cli/backend/src/services/ai/self-improvement/agent-memory-provider.js.map +1 -0
  252. package/dist/cli/backend/src/services/ai/self-improvement/attention.service.d.ts +74 -0
  253. package/dist/cli/backend/src/services/ai/self-improvement/attention.service.d.ts.map +1 -0
  254. package/dist/cli/backend/src/services/ai/self-improvement/attention.service.js +132 -0
  255. package/dist/cli/backend/src/services/ai/self-improvement/attention.service.js.map +1 -0
  256. package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.d.ts +107 -0
  257. package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.d.ts.map +1 -0
  258. package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.js +183 -0
  259. package/dist/cli/backend/src/services/ai/self-improvement/memory-consolidation.service.js.map +1 -0
  260. package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts +100 -0
  261. package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.d.ts.map +1 -0
  262. package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.js +130 -0
  263. package/dist/cli/backend/src/services/ai/self-improvement/prediction-calibration.service.js.map +1 -0
  264. package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts +1 -1
  265. package/dist/cli/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  266. package/dist/cli/backend/src/services/cloud/cloud-sync.types.js +1 -0
  267. package/dist/cli/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  268. package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts +1 -1
  269. package/dist/cli/backend/src/services/mcp-tool-definitions.js +1 -1
  270. package/dist/cli/backend/src/services/mcp-tool-definitions.js.map +1 -1
  271. package/dist/cli/backend/src/services/settings/settings.service.d.ts.map +1 -1
  272. package/dist/cli/backend/src/services/settings/settings.service.js +1 -0
  273. package/dist/cli/backend/src/services/settings/settings.service.js.map +1 -1
  274. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.d.ts +12 -1
  275. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
  276. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js +30 -0
  277. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
  278. package/dist/cli/backend/src/services/slack/slack.service.d.ts +76 -1
  279. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
  280. package/dist/cli/backend/src/services/slack/slack.service.js +234 -47
  281. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
  282. package/dist/cli/backend/src/types/index.d.ts +11 -1
  283. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  284. package/dist/cli/backend/src/types/index.js.map +1 -1
  285. package/dist/cli/backend/src/types/settings.types.d.ts +1 -1
  286. package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
  287. package/dist/cli/backend/src/types/settings.types.js +7 -0
  288. package/dist/cli/backend/src/types/settings.types.js.map +1 -1
  289. package/dist/cli/backend/src/types/slack.types.d.ts +141 -2
  290. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  291. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  292. package/dist/cli/backend/src/types/team-template.types.d.ts +2 -2
  293. package/dist/cli/backend/src/types/team-template.types.d.ts.map +1 -1
  294. package/dist/cli/backend/src/types/team-template.types.js +1 -1
  295. package/dist/cli/backend/src/types/team-template.types.js.map +1 -1
  296. package/dist/cli/backend/src/types/v2/mission.types.d.ts +2 -0
  297. package/dist/cli/backend/src/types/v2/mission.types.d.ts.map +1 -1
  298. package/dist/cli/backend/src/types/v2/mission.types.js.map +1 -1
  299. package/dist/cli/backend/src/utils/terminal-string-ops.d.ts +2 -0
  300. package/dist/cli/backend/src/utils/terminal-string-ops.d.ts.map +1 -1
  301. package/dist/cli/backend/src/utils/terminal-string-ops.js +14 -0
  302. package/dist/cli/backend/src/utils/terminal-string-ops.js.map +1 -1
  303. package/dist/cli/cli/src/commands/onboard.d.ts +2 -2
  304. package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
  305. package/dist/cli/cli/src/commands/onboard.js +15 -7
  306. package/dist/cli/cli/src/commands/onboard.js.map +1 -1
  307. package/frontend/dist/assets/{index-203224f9.js → index-c87332bf.js} +278 -278
  308. package/frontend/dist/assets/index-f6b4230e.css +42 -0
  309. package/frontend/dist/index.html +2 -2
  310. package/package.json +1 -1
  311. package/frontend/dist/assets/index-dcaf6c88.css +0 -42
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: Count JSON
3
+ description: Run a command that prints JSON and count the entries matching a field=value filter. Built for skill_output Key Results (e.g. "tickets in review") so a KR can be measured from any board or API that speaks JSON.
4
+ version: 1.0.0
5
+ category: measurement
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ - team-leader
10
+ - developer
11
+ - devops
12
+ - operations
13
+ - ops
14
+ triggers:
15
+ - count json
16
+ - measure kr
17
+ tags:
18
+ - okr
19
+ - measurement
20
+ - json
21
+ execution:
22
+ type: script
23
+ script:
24
+ file: execute.sh
25
+ interpreter: bash
26
+ timeoutMs: 60000
27
+ ---
28
+
29
+ # Count JSON
30
+
31
+ Runs a command, reads the JSON it prints (an array, or an object holding an
32
+ array under `items` / `tickets` / `data`), applies an optional `field=value`
33
+ filter, and prints `{"count": N, "total": M, "filter": "..."}`.
34
+
35
+ Made for `measurementSource: "skill_output"` Key Results:
36
+
37
+ ```json
38
+ { "measurementConfig": { "skill": "count-json",
39
+ "args": { "command": "cd /opt/app/web && make tickets TICKET_ARGS=--json",
40
+ "field": "status", "value": "review" },
41
+ "jsonPath": ".count" } }
42
+ ```
43
+
44
+ ## Parameters
45
+
46
+ | Name | Required | Meaning |
47
+ |---|---|---|
48
+ | `command` | yes | Shell command whose stdout is JSON (or a `file` path instead) |
49
+ | `file` | no | Read JSON from this file instead of running a command |
50
+ | `field` | no | Top-level field to filter on |
51
+ | `value` | no | Value that `field` must equal (string compare) |
52
+ | `arrayPath` | no | jq path to the array when it is nested (default: auto-detect) |
53
+
54
+ ## Output
55
+
56
+ ```json
57
+ {"count": 6, "total": 21, "filter": "status=review"}
58
+ ```
59
+
60
+ The command runs with a 50 s timeout; a non-JSON result exits 1 with an error
61
+ object on stderr.
@@ -0,0 +1,52 @@
1
+ #!/bin/bash
2
+ # count-json — run a command (or read a file) that yields JSON, count entries
3
+ # matching field=value. Output: {"count":N,"total":M,"filter":"field=value"}
4
+ #
5
+ # Usage: execute.sh '{"command":"...","field":"status","value":"review"}'
6
+ # execute.sh '{"file":"/tmp/board.json","field":"status","value":"open"}'
7
+ set -uo pipefail
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ source "${SCRIPT_DIR}/../../_common/lib.sh"
10
+
11
+ INPUT="${1:-}"
12
+ [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"command\":\"...\",\"field\":\"status\",\"value\":\"review\"}'"
13
+
14
+ COMMAND=$(printf '%s' "$INPUT" | jq -r '.command // empty')
15
+ FILE=$(printf '%s' "$INPUT" | jq -r '.file // empty')
16
+ FIELD=$(printf '%s' "$INPUT" | jq -r '.field // empty')
17
+ VALUE=$(printf '%s' "$INPUT" | jq -r '.value // empty')
18
+ ARRAY_PATH=$(printf '%s' "$INPUT" | jq -r '.arrayPath // empty')
19
+ TIMEOUT_S="${COUNT_JSON_TIMEOUT_S:-50}"
20
+
21
+ [ -z "$COMMAND" ] && [ -z "$FILE" ] && error_exit "command or file is required"
22
+
23
+ if [ -n "$FILE" ]; then
24
+ [ -f "$FILE" ] || error_exit "file not found: $FILE"
25
+ RAW=$(cat "$FILE")
26
+ else
27
+ if command -v timeout >/dev/null 2>&1; then
28
+ RAW=$(timeout "$TIMEOUT_S" bash -c "$COMMAND" 2>/dev/null)
29
+ else
30
+ RAW=$(bash -c "$COMMAND" 2>/dev/null)
31
+ fi
32
+ [ $? -ne 0 ] && [ -z "$RAW" ] && error_exit "command failed or produced no output"
33
+ fi
34
+
35
+ # Skip any non-JSON preamble (progress lines, banners).
36
+ JSON=$(printf '%s' "$RAW" | awk 'found||/^[[{]/{found=1; print}')
37
+ [ -z "$JSON" ] && error_exit "no JSON found in output"
38
+
39
+ if [ -n "$ARRAY_PATH" ]; then
40
+ SELECT="$ARRAY_PATH"
41
+ else
42
+ SELECT='if type=="array" then . elif (.items|type)=="array" then .items elif (.tickets|type)=="array" then .tickets elif (.data|type)=="array" then .data else [] end'
43
+ fi
44
+
45
+ if [ -n "$FIELD" ]; then
46
+ printf '%s' "$JSON" | jq -c --arg f "$FIELD" --arg v "$VALUE" \
47
+ "($SELECT) as \$arr | {count: (\$arr | map(select((.[\$f] // \"\" | tostring) == \$v)) | length), total: (\$arr | length), filter: (\$f + \"=\" + \$v)}" \
48
+ || error_exit "output is not valid JSON"
49
+ else
50
+ printf '%s' "$JSON" | jq -c "($SELECT) as \$arr | {count: (\$arr | length), total: (\$arr | length), filter: \"\"}" \
51
+ || error_exit "output is not valid JSON"
52
+ fi
@@ -0,0 +1,35 @@
1
+ #!/bin/bash
2
+ # Tests for count-json — run with: bash execute.test.sh
3
+ set -u
4
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ EXEC="$HERE/execute.sh"
6
+ PASS=0; FAIL=0
7
+ check() {
8
+ local name="$1"; local got="$2"; local want="$3"
9
+ if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
10
+ }
11
+ run() { bash "$EXEC" "$1" 2>/dev/null; }
12
+ run_err() { bash "$EXEC" "$1" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
13
+
14
+ TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
15
+ printf '%s' '[{"ticketId":"T1","status":"open"},{"ticketId":"T2","status":"review"},{"ticketId":"T3","status":"review"},{"ticketId":"T4","status":"blocked"}]' > "$TMP/board.json"
16
+ printf '%s' 'fetching...
17
+ {"items":[{"s":"a"},{"s":"b"}]}' > "$TMP/nested.txt"
18
+
19
+ ARGS=$(jq -cn --arg f "$TMP/board.json" '{file:$f, field:"status", value:"review"}')
20
+ check "filter by field=value" "$(run "$ARGS")" '{"count":2,"total":4,"filter":"status=review"}'
21
+
22
+ ARGS=$(jq -cn --arg f "$TMP/board.json" '{file:$f}')
23
+ check "no filter counts all" "$(run "$ARGS")" '{"count":4,"total":4,"filter":""}'
24
+
25
+ ARGS=$(jq -cn --arg c "cat $TMP/nested.txt" '{command:$c, field:"s", value:"b"}')
26
+ check "command with preamble and nested items" "$(run "$ARGS")" '{"count":1,"total":2,"filter":"s=b"}'
27
+
28
+ ARGS=$(jq -cn --arg f "$TMP/board.json" '{file:$f, arrayPath:".", field:"status", value:"open"}')
29
+ check "explicit arrayPath" "$(run "$ARGS")" '{"count":1,"total":4,"filter":"status=open"}'
30
+
31
+ check "non-JSON errors" "$(run_err '{"command":"echo not json"}')" "no JSON found in output"
32
+ check "missing input errors" "$(run_err '{}')" "command or file is required"
33
+
34
+ echo "=== Results: $PASS passed, $FAIL failed ==="
35
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: Gmail Read
3
+ description: Read one message from the owner's Gmail by id — headers, decoded body (plain text, HTML stripped as fallback) and a list of attachments (names only, nothing downloaded). Read-only.
4
+ version: 1.0.0
5
+ category: communication
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ - team-leader
10
+ - developer
11
+ - operations
12
+ - ops
13
+ - sales
14
+ - support
15
+ - generalist
16
+ triggers:
17
+ - read email
18
+ - open email
19
+ - show email
20
+ tags:
21
+ - google
22
+ - gmail
23
+ - email
24
+ execution:
25
+ type: script
26
+ script:
27
+ file: execute.sh
28
+ interpreter: bash
29
+ timeoutMs: 30000
30
+ ---
31
+
32
+ # Gmail Read
33
+
34
+ Fetches one message by the `id` a `gmail-search` hit returned.
35
+
36
+ ```bash
37
+ bash execute.sh --id 18f0a1b2c3d4e5f6
38
+ bash execute.sh '{"id":"18f0a1b2c3d4e5f6"}'
39
+ ```
40
+
41
+ ## Parameters
42
+
43
+ | Name | Required | Meaning |
44
+ |---|---|---|
45
+ | `--id` / `-i` (`id`) | yes | Gmail message id |
46
+
47
+ ## Output
48
+
49
+ ```json
50
+ {"id":"18f…","threadId":"18f…","from":"Ann <ann@example.com>","to":"owner@example.com","cc":"","subject":"Q3 numbers","date":"…","messageId":"<abc@mail.example.com>","body":"Hi —\n…","bodyType":"text","attachments":[{"filename":"deck.pdf","mimeType":"application/pdf","size":12345,"attachmentId":"ANGjd…"}]}
51
+ ```
52
+
53
+ `bodyType` is `text` (text/plain part), `html` (stripped from text/html)
54
+ or `none`. Attachments are listed, never downloaded. To reply in-thread,
55
+ pass `threadId` and `messageId` to `gmail-send`.
56
+
57
+ ## Failures
58
+
59
+ `{"success":false,"reason":"not_connected","hint":"<connect URL>"}` (exit 1)
60
+ when the owner has not connected Google Workspace; `reason` `google_error`
61
+ with a 404 message when the id is unknown.
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # gmail-read — Read one message from the owner's Gmail (read-only)
4
+ #
5
+ # Backed by GET /api/google/gmail/messages/:id.
6
+ #
7
+ # Usage:
8
+ # bash execute.sh --id 18f0a1b2c3d4e5f6
9
+ # bash execute.sh '{"id":"18f0a1b2c3d4e5f6"}'
10
+ # =============================================================================
11
+ set -euo pipefail
12
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ source "${SCRIPT_DIR}/../../_common/lib.sh"
14
+
15
+ print_usage() {
16
+ cat <<'EOF_USAGE'
17
+ Usage:
18
+ bash execute.sh --id <gmail message id>
19
+ bash execute.sh '{"id":"<gmail message id>"}'
20
+
21
+ Options:
22
+ --id | -i Gmail message id (required; from gmail-search)
23
+ --help | -h Show this help
24
+ EOF_USAGE
25
+ }
26
+
27
+ INPUT_JSON=""
28
+ ID=""
29
+
30
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
31
+ INPUT_JSON="$1"
32
+ shift || true
33
+ fi
34
+
35
+ while [[ $# -gt 0 ]]; do
36
+ case "$1" in
37
+ --id|-i) [ $# -ge 2 ] || error_exit "--id requires a value"; ID="$2"; shift 2 ;;
38
+ --help|-h) print_usage; exit 0 ;;
39
+ *) error_exit "Unknown option: $1" ;;
40
+ esac
41
+ done
42
+
43
+ if [ -n "$INPUT_JSON" ]; then
44
+ INPUT=$(read_json_input "$INPUT_JSON")
45
+ [ -z "$ID" ] && ID=$(printf '%s' "$INPUT" | jq -r '.id // .messageId // empty')
46
+ fi
47
+
48
+ require_param "id (--id)" "$ID"
49
+
50
+ ID_ENC=$(jq -rn --arg v "$ID" '$v|@uri')
51
+ RESPONSE=$(api_call GET "/google/gmail/messages/${ID_ENC}" 2>&1) || {
52
+ printf '%s' "$RESPONSE" | jq -c '{success: false, reason: (.details.error // .details // .error // "unknown"), hint: (.details.hint // ""), message: (.details.message // "")}' 2>/dev/null \
53
+ || jq -n --arg r "$RESPONSE" '{success: false, reason: $r}'
54
+ exit 1
55
+ }
56
+
57
+ # Oversized bodies are parked on disk by api_call; pass that envelope through.
58
+ if printf '%s' "$RESPONSE" | jq -e '.truncated == true' >/dev/null 2>&1; then
59
+ printf '%s\n' "$RESPONSE"; exit 0
60
+ fi
61
+
62
+ printf '%s' "$RESPONSE" | jq -c '.data | {id, threadId, from, to, cc, subject, date, messageId, body, bodyType, attachments}'
@@ -0,0 +1,68 @@
1
+ #!/bin/bash
2
+ # Tests for gmail-read — run with: bash execute.test.sh
3
+ # Spins up a python HTTP stub as the backend, asserts the request path the
4
+ # skill sends and the JSON it prints. Exit 0 on pass.
5
+ set -u
6
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ EXEC="$HERE/execute.sh"
8
+ PASS=0; FAIL=0
9
+ check() {
10
+ local name="$1"; local got="$2"; local want="$3"
11
+ if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
12
+ }
13
+
14
+ PORT=18802
15
+ STUB_LOG="$(mktemp)"; export STUB_LOG; export STUB_PORT="$PORT"
16
+ python3 -u <<'PY' >/dev/null 2>&1 &
17
+ from http.server import BaseHTTPRequestHandler, HTTPServer
18
+ import json, os
19
+ LOG = os.environ['STUB_LOG']; PORT = int(os.environ['STUB_PORT'])
20
+ MSG = {'id': 'm1', 'threadId': 't1', 'from': 'ann@example.com', 'to': 'owner@example.com', 'cc': '',
21
+ 'subject': 'Q3', 'date': 'D', 'messageId': '<abc@x>', 'snippet': 's', 'body': 'Hi\nthere', 'bodyType': 'text',
22
+ 'attachments': [{'filename': 'deck.pdf', 'mimeType': 'application/pdf', 'size': 12, 'attachmentId': 'A1'}],
23
+ 'labelIds': ['INBOX']}
24
+ class H(BaseHTTPRequestHandler):
25
+ def do_GET(self):
26
+ open(LOG, 'w').write(json.dumps({'method': 'GET', 'path': self.path}))
27
+ if self.path.endswith('/missing'):
28
+ self.send_response(404); self.send_header('Content-Type', 'application/json'); self.end_headers()
29
+ self.wfile.write(json.dumps({'success': False, 'error': 'google_error', 'message': 'Requested entity was not found.', 'hint': 'Google or Crewly Cloud failed; retry later.'}).encode()); return
30
+ if self.path.endswith('/no-grant'):
31
+ self.send_response(409); self.send_header('Content-Type', 'application/json'); self.end_headers()
32
+ self.wfile.write(json.dumps({'success': False, 'error': 'not_connected', 'message': 'no grant', 'hint': 'https://cloud/start?token=j'}).encode()); return
33
+ self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers()
34
+ self.wfile.write(json.dumps({'success': True, 'data': MSG}).encode())
35
+ def log_message(self, *a, **k): pass
36
+ HTTPServer(('127.0.0.1', PORT), H).serve_forever()
37
+ PY
38
+ STUB_PID=$!
39
+ disown "$STUB_PID" 2>/dev/null || true
40
+ trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
41
+ for i in $(seq 1 30); do curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/" 2>/dev/null && break; sleep 0.1; done
42
+
43
+ run() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
44
+ run_err() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
45
+
46
+ WANT='{"id":"m1","threadId":"t1","from":"ann@example.com","to":"owner@example.com","cc":"","subject":"Q3","date":"D","messageId":"<abc@x>","body":"Hi\nthere","bodyType":"text","attachments":[{"filename":"deck.pdf","mimeType":"application/pdf","size":12,"attachmentId":"A1"}]}'
47
+
48
+ OUT=$(run --id m1)
49
+ check "flags: output (no snippet/labelIds)" "$OUT" "$WANT"
50
+ check "flags: path" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/messages/m1"
51
+
52
+ OUT=$(run '{"id":"m 1"}')
53
+ check "json: output" "$OUT" "$WANT"
54
+ check "json: id is URL-encoded" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/messages/m%201"
55
+
56
+ OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --id missing 2>/dev/null); RC=$?
57
+ check "404: exit code" "$RC" "1"
58
+ check "404: reason" "$(printf '%s' "$OUT" | jq -r .reason)" "google_error"
59
+ check "404: message" "$(printf '%s' "$OUT" | jq -r .message)" "Requested entity was not found."
60
+
61
+ OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --id no-grant 2>/dev/null)
62
+ check "409: hint is the connect URL" "$(printf '%s' "$OUT" | jq -r .hint)" "https://cloud/start?token=j"
63
+
64
+ check "missing id errors" "$(run_err)" "Missing required parameter: id (--id)"
65
+ check "unknown option errors" "$(run_err --bogus 1)" "Unknown option: --bogus"
66
+
67
+ echo "=== Results: $PASS passed, $FAIL failed ==="
68
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: Gmail Search
3
+ description: Search the owner's Gmail (via the Google Workspace grant held by Crewly Cloud) and list matching messages with sender, subject, date and snippet. Read-only.
4
+ version: 1.0.0
5
+ category: communication
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ - team-leader
10
+ - developer
11
+ - operations
12
+ - ops
13
+ - sales
14
+ - support
15
+ - generalist
16
+ triggers:
17
+ - search gmail
18
+ - search email
19
+ - find email
20
+ - check inbox
21
+ tags:
22
+ - google
23
+ - gmail
24
+ - email
25
+ execution:
26
+ type: script
27
+ script:
28
+ file: execute.sh
29
+ interpreter: bash
30
+ timeoutMs: 30000
31
+ ---
32
+
33
+ # Gmail Search
34
+
35
+ Runs a Gmail search on the owner's mailbox and prints the hits. Uses the
36
+ Google Workspace connection the owner made under Settings → Integrations;
37
+ the mail content goes straight from Google to this instance.
38
+
39
+ ```bash
40
+ bash execute.sh --query "is:unread from:ann@example.com newer_than:2d" --max 10
41
+ bash execute.sh '{"query":"subject:invoice has:attachment","max":5}'
42
+ ```
43
+
44
+ ## Parameters
45
+
46
+ | Name | Required | Meaning |
47
+ |---|---|---|
48
+ | `--query` / `-q` (`query`) | yes | Gmail search syntax (`from:`, `subject:`, `is:unread`, `newer_than:7d`, `has:attachment`, …) |
49
+ | `--max` / `-n` (`max`) | no | Result cap, default 20, max 100 |
50
+
51
+ ## Output
52
+
53
+ ```json
54
+ {"query":"is:unread","count":2,"messages":[{"id":"18f…","threadId":"18f…","from":"Ann <ann@example.com>","to":"owner@example.com","subject":"Q3 numbers","date":"Thu, 18 Sep 2026 10:00:00 +0000","snippet":"Here are the…"}]}
55
+ ```
56
+
57
+ Use the `id` with `gmail-read` to get the body; `threadId` + `gmail-read`'s
58
+ `messageId` with `gmail-send` to reply in-thread.
59
+
60
+ ## Failures
61
+
62
+ `{"success":false,"reason":"not_connected","hint":"<connect URL>"}` — the
63
+ owner has not connected Google Workspace yet; hand them the hint URL (or
64
+ point them to Settings → Integrations → Google Workspace). Exit code 1.
@@ -0,0 +1,70 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # gmail-search — Search the owner's Gmail (read-only)
4
+ #
5
+ # Backed by GET /api/google/gmail/search?q=&max= (Cloud holds the Google
6
+ # grant; this instance talks to Gmail directly).
7
+ #
8
+ # Usage:
9
+ # bash execute.sh --query "is:unread from:ann" [--max 10]
10
+ # bash execute.sh '{"query":"is:unread","max":10}'
11
+ # =============================================================================
12
+ set -euo pipefail
13
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
+ source "${SCRIPT_DIR}/../../_common/lib.sh"
15
+
16
+ print_usage() {
17
+ cat <<'EOF_USAGE'
18
+ Usage:
19
+ bash execute.sh --query "is:unread from:ann" [--max 10]
20
+ bash execute.sh '{"query":"is:unread","max":10}'
21
+
22
+ Options:
23
+ --query | -q Gmail search query (required)
24
+ --max | -n Result cap (default 20, max 100)
25
+ --help | -h Show this help
26
+ EOF_USAGE
27
+ }
28
+
29
+ INPUT_JSON=""
30
+ QUERY=""
31
+ MAX=""
32
+
33
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
34
+ INPUT_JSON="$1"
35
+ shift || true
36
+ fi
37
+
38
+ while [[ $# -gt 0 ]]; do
39
+ case "$1" in
40
+ --query|-q) [ $# -ge 2 ] || error_exit "--query requires a value"; QUERY="$2"; shift 2 ;;
41
+ --max|-n) [ $# -ge 2 ] || error_exit "--max requires a value"; MAX="$2"; shift 2 ;;
42
+ --help|-h) print_usage; exit 0 ;;
43
+ *) error_exit "Unknown option: $1" ;;
44
+ esac
45
+ done
46
+
47
+ if [ -n "$INPUT_JSON" ]; then
48
+ INPUT=$(read_json_input "$INPUT_JSON")
49
+ [ -z "$QUERY" ] && QUERY=$(printf '%s' "$INPUT" | jq -r '.query // .q // empty')
50
+ [ -z "$MAX" ] && MAX=$(printf '%s' "$INPUT" | jq -r '.max // empty')
51
+ fi
52
+
53
+ require_param "query (--query)" "$QUERY"
54
+
55
+ Q_ENC=$(jq -rn --arg v "$QUERY" '$v|@uri')
56
+ ENDPOINT="/google/gmail/search?q=${Q_ENC}"
57
+ [ -n "$MAX" ] && ENDPOINT="${ENDPOINT}&max=$(jq -rn --arg v "$MAX" '$v|@uri')"
58
+
59
+ RESPONSE=$(api_call GET "$ENDPOINT" 2>&1) || {
60
+ printf '%s' "$RESPONSE" | jq -c '{success: false, reason: (.details.error // .details // .error // "unknown"), hint: (.details.hint // ""), message: (.details.message // "")}' 2>/dev/null \
61
+ || jq -n --arg r "$RESPONSE" '{success: false, reason: $r}'
62
+ exit 1
63
+ }
64
+
65
+ # Oversized bodies are parked on disk by api_call; pass that envelope through.
66
+ if printf '%s' "$RESPONSE" | jq -e '.truncated == true' >/dev/null 2>&1; then
67
+ printf '%s\n' "$RESPONSE"; exit 0
68
+ fi
69
+
70
+ printf '%s' "$RESPONSE" | jq -c '{query: .data.query, count: .data.count, messages: [.data.messages[] | {id, threadId, from, to, subject, date, snippet}]}'
@@ -0,0 +1,67 @@
1
+ #!/bin/bash
2
+ # Tests for gmail-search — run with: bash execute.test.sh
3
+ # Spins up a python HTTP stub as the backend, asserts the request path the
4
+ # skill sends and the JSON it prints. Exit 0 on pass.
5
+ set -u
6
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ EXEC="$HERE/execute.sh"
8
+ PASS=0; FAIL=0
9
+ check() {
10
+ local name="$1"; local got="$2"; local want="$3"
11
+ if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
12
+ }
13
+
14
+ PORT=18801
15
+ STUB_LOG="$(mktemp)"; export STUB_LOG; export STUB_PORT="$PORT"
16
+ python3 -u <<'PY' >/dev/null 2>&1 &
17
+ from http.server import BaseHTTPRequestHandler, HTTPServer
18
+ from urllib.parse import urlparse, parse_qs
19
+ import json, os
20
+ LOG = os.environ['STUB_LOG']; PORT = int(os.environ['STUB_PORT'])
21
+ HIT = {'id': 'm1', 'threadId': 't1', 'from': 'Ann <ann@example.com>', 'to': 'owner@example.com',
22
+ 'subject': 'Q3 numbers', 'date': 'D', 'snippet': 'hi', 'labelIds': ['INBOX']}
23
+ class H(BaseHTTPRequestHandler):
24
+ def do_GET(self):
25
+ open(LOG, 'w').write(json.dumps({'method': 'GET', 'path': self.path}))
26
+ qs = parse_qs(urlparse(self.path).query)
27
+ q = qs.get('q', [''])[0]
28
+ if q == 'no-grant':
29
+ self.send_response(409); self.send_header('Content-Type', 'application/json'); self.end_headers()
30
+ self.wfile.write(json.dumps({'success': False, 'error': 'not_connected', 'message': 'no grant',
31
+ 'hint': 'https://api.crewlyai.com/api/cloud/google/workspace/start?token=j'}).encode()); return
32
+ self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers()
33
+ self.wfile.write(json.dumps({'success': True, 'data': {'query': q, 'count': 1, 'messages': [HIT]}}).encode())
34
+ def log_message(self, *a, **k): pass
35
+ HTTPServer(('127.0.0.1', PORT), H).serve_forever()
36
+ PY
37
+ STUB_PID=$!
38
+ disown "$STUB_PID" 2>/dev/null || true
39
+ trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
40
+ for i in $(seq 1 30); do curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/" 2>/dev/null && break; sleep 0.1; done
41
+
42
+ run() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
43
+ run_err() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
44
+
45
+ WANT='{"query":"is:unread from:ann","count":1,"messages":[{"id":"m1","threadId":"t1","from":"Ann <ann@example.com>","to":"owner@example.com","subject":"Q3 numbers","date":"D","snippet":"hi"}]}'
46
+
47
+ # --- flags ---
48
+ OUT=$(run --query "is:unread from:ann" --max 5)
49
+ check "flags: output drops labelIds" "$OUT" "$WANT"
50
+ check "flags: path is URL-encoded with max" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/search?q=is%3Aunread%20from%3Aann&max=5"
51
+
52
+ # --- JSON input ---
53
+ OUT=$(run '{"query":"is:unread from:ann"}')
54
+ check "json: output" "$OUT" "$WANT"
55
+ check "json: no max when absent" "$(jq -r .path "$STUB_LOG")" "/api/google/gmail/search?q=is%3Aunread%20from%3Aann"
56
+
57
+ # --- not connected → success:false + hint, exit 1 ---
58
+ OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --query no-grant 2>/dev/null); RC=$?
59
+ check "409: exit code" "$RC" "1"
60
+ check "409: reason + hint" "$OUT" '{"success":false,"reason":"not_connected","hint":"https://api.crewlyai.com/api/cloud/google/workspace/start?token=j","message":"no grant"}'
61
+
62
+ # --- validation ---
63
+ check "missing query errors" "$(run_err --max 3)" "Missing required parameter: query (--query)"
64
+ check "unknown option errors" "$(run_err --bogus 1)" "Unknown option: --bogus"
65
+
66
+ echo "=== Results: $PASS passed, $FAIL failed ==="
67
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: Gmail Send
3
+ description: Send an email from the owner's Gmail account (via the Google Workspace grant held by Crewly Cloud). Sends on the owner's behalf — needs the owner's go-ahead unless the task brief grants it. Supports in-thread replies and a dry-run preview.
4
+ version: 1.0.0
5
+ category: communication
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ - team-leader
10
+ - operations
11
+ - ops
12
+ - sales
13
+ - support
14
+ - generalist
15
+ triggers:
16
+ - send email
17
+ - reply to email
18
+ - email someone
19
+ tags:
20
+ - google
21
+ - gmail
22
+ - email
23
+ execution:
24
+ type: script
25
+ script:
26
+ file: execute.sh
27
+ interpreter: bash
28
+ timeoutMs: 30000
29
+ ---
30
+
31
+ # Gmail Send
32
+
33
+ Sends a plain-text email **as the owner**. Because the message carries the
34
+ owner's name, only send when the owner has said so in this conversation or
35
+ the task brief explicitly grants sending; otherwise draft with `--dry-run`
36
+ and show the preview.
37
+
38
+ ```bash
39
+ bash execute.sh --to ann@example.com --subject "Re: Q3 numbers" --text "Looks good, thanks!"
40
+ bash execute.sh --to ann@example.com --subject "Re: Q3 numbers" --text-file /tmp/reply.txt \
41
+ --thread-id 18f0a1b2c3d4e5f6 --in-reply-to "<abc@mail.example.com>"
42
+ bash execute.sh '{"to":"ann@example.com","subject":"Hi","text":"…"}'
43
+ ```
44
+
45
+ ## Parameters
46
+
47
+ | Name | Required | Meaning |
48
+ |---|---|---|
49
+ | `--to` (`to`) | yes | Recipient(s), comma-separated |
50
+ | `--subject` (`subject`) | yes | Subject (UTF-8 fine) |
51
+ | `--text` / `--text-file` (`text`) | yes | Plain-text body, inline or from a file |
52
+ | `--cc` (`cc`) | no | Cc recipient(s) |
53
+ | `--thread-id` (`threadId`) | no | Gmail thread to reply in (from `gmail-search`) |
54
+ | `--in-reply-to` (`inReplyTo`) | no | `messageId` of the message being answered (from `gmail-read`) |
55
+ | `--dry-run` | no | Print the message preview; send nothing |
56
+
57
+ `CREWLY_GMAIL_SEND_DRY_RUN=1` in the environment forces dry-run for every
58
+ call — nothing is sent, no request leaves this machine.
59
+
60
+ ## Output
61
+
62
+ Sent: `{"success":true,"id":"18f…","threadId":"18f…"}`
63
+
64
+ Dry run: `{"success":true,"dryRun":true,"preview":"To: …\nSubject: …\n\n<body>"}`
65
+
66
+ ## Failures
67
+
68
+ Missing `--to` / `--subject` / body → `{"error":"Missing required parameter: …"}` on stderr, exit 1, nothing sent.
69
+ `{"success":false,"reason":"not_connected","hint":"<connect URL>"}` (exit 1) when the owner has not connected Google Workspace.