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
package/README.md CHANGED
@@ -7,12 +7,12 @@
7
7
 
8
8
  **Website:** [crewlyai.com](https://crewlyai.com/)
9
9
 
10
- Crewly is an open-source multi-agent orchestration platform that coordinates AI coding agents (Claude Code, Gemini CLI, Codex) to work together as a team. It provides a web dashboard for real-time monitoring, task management, and team coordination — all running locally on your machine.
10
+ Crewly is an open-source multi-agent orchestration platform that coordinates AI coding agents (Claude Code, Gemini CLI, Codex, OpenCode) to work together as a team. It provides a web dashboard for real-time monitoring, task management, and team coordination — all running locally on your machine.
11
11
 
12
12
  ## Features
13
13
 
14
14
  - **Multi-agent teams** — Create teams with different roles (developer, QA, PM, orchestrator) and watch them collaborate
15
- - **Multi-runtime support** — Use Claude Code, Gemini CLI, or OpenAI Codex — mix and match per agent
15
+ - **Multi-runtime support** — Use Claude Code, Gemini CLI, OpenAI Codex, or OpenCode — mix and match per agent
16
16
  - **Real-time dashboard** — Monitor all agents through live terminal streams, task boards, and activity feeds
17
17
  - **Skill system** — Agents coordinate through bash skills (report status, delegate tasks, manage memory)
18
18
  - **Agent memory** — Persistent knowledge that agents build and share across sessions
@@ -49,8 +49,9 @@ The `init` command walks you through provider selection, installs agent skills,
49
49
  | **Claude Code** (default) | `npm install -g @anthropic-ai/claude-code` | `claude --version` |
50
50
  | **Gemini CLI** | `npm install -g @google/gemini-cli` | `gemini --version` |
51
51
  | **Codex (OpenAI)** | `npm install -g @openai/codex` | `codex --version` |
52
+ | **OpenCode** | `npm install -g opencode-ai` | `opencode --version` |
52
53
 
53
- **API keys:** Gemini CLI requires `GEMINI_API_KEY`. Codex requires an OpenAI API key. Claude Code authenticates through its own login flow.
54
+ **API keys:** Gemini CLI requires `GEMINI_API_KEY`. Codex requires an OpenAI API key. Claude Code authenticates through its own login flow. OpenCode uses whichever provider you connect via `opencode auth login` (or the `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GEMINI_API_KEY` env vars Crewly already exports to agent sessions).
54
55
 
55
56
  ## Architecture
56
57
 
@@ -98,7 +99,8 @@ Storage: ~/.crewly/ (global) + project/.crewly/ (per-project)
98
99
  |---------|-----------------|-------|
99
100
  | **Claude Code** | `claude --dangerously-skip-permissions` | Default runtime |
100
101
  | **Gemini CLI** | `gemini --yolo` | Requires `GEMINI_API_KEY` |
101
- | **Codex (OpenAI)** | `codex --full-auto` | Requires OpenAI API key |
102
+ | **Codex (OpenAI)** | `codex -a never -s danger-full-access` | Requires OpenAI API key |
103
+ | **OpenCode** | `opencode --auto` | Any provider/model (`-m provider/model`); reads `AGENTS.md`; auth via `opencode auth login` |
102
104
 
103
105
  You can change the default runtime or customize launch commands in **Settings**.
104
106
 
@@ -123,9 +125,11 @@ Optional environment variables (`.env` file or shell):
123
125
  ```bash
124
126
  GEMINI_API_KEY=your_key_here # Required for Gemini CLI runtime
125
127
 
126
- SLACK_BOT_TOKEN=xoxb-... # Optional: Slack integration
128
+ SLACK_BOT_TOKEN=xoxb-... # Optional: self-hosted Slack app (see "Slack" below)
127
129
  SLACK_APP_TOKEN=xapp-...
128
130
  SLACK_SIGNING_SECRET=...
131
+ CREWLY_SLACK_SOURCE=cloud # Optional: env | cloud (unset = Cloud wins when both exist)
132
+ CREWLY_SLACK_PRIMARY=1 # Optional: this instance handles DMs / unmapped channels
129
133
 
130
134
  LOG_LEVEL=info # debug, info, warn, error
131
135
  WEB_PORT=8787 # Dashboard port (default: 8787)
@@ -133,6 +137,36 @@ CREWLY_BIND_HOST=0.0.0.0 # Interface to listen on (127.0.0.1 = this ma
133
137
  CREWLY_API_TOKEN=... # Pin the API token (otherwise generated at ~/.crewly/api-token)
134
138
  ```
135
139
 
140
+ ### Slack
141
+
142
+ **One click (recommended).** Log in to Crewly Cloud (Settings → Cloud), open
143
+ Settings → Integrations → Slack and press **Connect Slack**. Slack asks you to
144
+ approve the Crewly app once; from then on every Crewly instance signed in to the
145
+ same Crewly account gets Slack automatically — team channels, and one real Slack
146
+ bot user per agent — with no tokens to copy. The instance pulls its config from
147
+ Cloud on boot and every 10 minutes (cached 0600 at
148
+ `~/.crewly/slack-cloud-config.json`); Slack events reach it through the Cloud
149
+ relay, so no Socket Mode connection is opened.
150
+
151
+ **The one manual step.** Slack only lets an app be created by an *App
152
+ Configuration Token* of a workspace member, and Crewly creates one Slack app per
153
+ agent so each agent is a real bot user (name in the member list, native `@`
154
+ mentions). Generate the token at api.slack.com/apps ("Your App Configuration
155
+ Tokens" → Generate) and paste it in Settings → Slack → Agent Identities. Cloud
156
+ keeps it refreshed. Each new agent then shows an install link you click once.
157
+
158
+ **Several instances, one workspace.** Every instance registers its teams,
159
+ channels and agents with Cloud (on boot, on team changes, every 5 min); Slack
160
+ traffic for a team channel goes to the instance running that team. Direct
161
+ messages to the Crewly bot and channels no team owns go to the **primary**
162
+ instance — the Settings toggle, or `CREWLY_SLACK_PRIMARY=1`.
163
+
164
+ **Self-hosted app.** The original path (your own Slack app, Socket Mode,
165
+ `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` / `SLACK_SIGNING_SECRET` or the form under
166
+ Settings → Slack → Advanced) still works. `CREWLY_SLACK_SOURCE` picks the source:
167
+ `cloud` uses only the Cloud workspace, `env` uses only local tokens and never
168
+ asks Cloud, unset prefers Cloud when both exist (logged once at boot).
169
+
136
170
  ### Securing a server install
137
171
 
138
172
  Crewly agents run as real shells on the host, and `POST /api/terminal/:session/write`
@@ -273,7 +273,7 @@ When you are **idle and have no assigned tasks**, proactively check the Task Poo
273
273
 
274
274
  Call the `poll-tasks` skill to query and claim work from the shared Task Pool:
275
275
  ```bash
276
- bash {{AGENT_SKILLS_PATH}}/core/poll-tasks/execute.sh '{"sessionName":"{{SESSION_NAME}}","role":"{{ROLE}}","skills":["typescript","react"],"projectPath":"{{PROJECT_PATH}}"}'
276
+ bash {{AGENT_SKILLS_PATH}}/core/poll-tasks/execute.sh '{"sessionName":"{{SESSION_NAME}}","role":"{{ROLE}}","skills":{{MEMBER_SKILLS_JSON}},"projectPath":"{{PROJECT_PATH}}"}'
277
277
  ```
278
278
 
279
279
  ### Parameters
@@ -194,17 +194,30 @@ bash {{ORCHESTRATOR_SKILLS_PATH}}/register-self/execute.sh '{"role":"orchestrato
194
194
 
195
195
  After registering, proceed to Step 4.
196
196
 
197
- ### Step 4 — Check Active Goals and Report
197
+ ### Step 4 — Check the Missions (OKRs) and Report
198
198
 
199
- After registration, check for active goals and OKRs:
199
+ After registration, read the real goal layer — the Missions API, not your
200
+ memory (memory only holds what someone happened to save):
200
201
 
201
202
  ```bash
202
- bash {{AGENT_SKILLS_PATH}}/core/recall/execute.sh '{"context":"OKR goals active tasks","scope":"both","agentId":"{{SESSION_ID}}","projectPath":"{{PROJECT_PATH}}"}'
203
+ bash {{ORCHESTRATOR_SKILLS_PATH}}/list-missions/execute.sh
203
204
  ```
204
205
 
205
- **If active OKRs or goals exist:** Report the current status to the user and ask if they want you to take over execution. Do NOT auto-execute unless the user explicitly activates Autonomous Mode (see below). Once the user activates Autonomous Mode in a session, it stays ON for the rest of that session — you do not need to re-ask.
206
+ **If a proposal is `pending_approval`:** tell the owner in one line what is
207
+ waiting (objective + its Key Results) and where to approve it (Missions page).
208
+ Do NOT execute, remind about or decompose it until it is approved.
206
209
 
207
- **If no active goals exist:** Say "Ready" and wait for the user.
210
+ **If live (approved) missions exist:** report each one's KRs (current → target,
211
+ status) in two or three lines and ask whether to take over execution. Do NOT
212
+ auto-execute unless the owner activates Autonomous Mode (below). Once
213
+ activated in a session it stays ON for that session.
214
+
215
+ **If there are no missions at all** and `get-team-status` shows teams that
216
+ completed work in the last week: draft ONE company-level OKR from that work
217
+ (objective + 2–3 Key Results that can be measured from something already in
218
+ the system — a ticket board, a build log, a folder count; see `count-json`
219
+ and `measurementSource: skill_output`) and ask the owner whether to create it.
220
+ Do not create it yourself. If there is no recent work either, say "Ready".
208
221
 
209
222
  ## Pipeline-First Planning Discipline (MANDATORY for planning intent)
210
223
 
@@ -271,6 +284,8 @@ The `delegate-task` skill emits a stderr WARNING when a brief is missing G/O/E m
271
284
 
272
285
  5. **Self-check before dispatch** — diff your composed `Expected Outcome` line items against the user's literal words. Every line in Expected Outcome must trace to a word/phrase the user actually wrote. If a line is justified only by recalled history, move it to `Context` or `Suggested Follow-ups` and surface back for confirmation.
273
286
 
287
+ 6. **Outbound mail under the owner's name is gated.** Sending email from the owner's Gmail (`gmail-send`, or any delegated brief that includes sending) requires the owner's explicit go-ahead in this conversation unless the task brief already grants it in `Decision Rights`; without that grant, draft with the dry-run preview and show it for approval instead of sending.
288
+
274
289
  **Negative pattern to suppress** (the 2026-05-20 ESTestNode shape):
275
290
  > User: "update X" → ORC: `recall_memory(X)` → memory has "X had 3 known issues" → ORC: "while you're updating X, handle the 3 known issues too" → executor does all 4 things → user pays for unauthorized scope on prod.
276
291
 
@@ -21,6 +21,13 @@
21
21
  "timeout": 90000,
22
22
  "description": "OpenAI's Codex CLI for advanced code understanding"
23
23
  },
24
+ "opencode-cli": {
25
+ "displayName": "OpenCode",
26
+ "initScript": "",
27
+ "welcomeMessage": "Ask anything",
28
+ "timeout": 90000,
29
+ "description": "OpenCode open-source TUI coding agent (opencode.ai), any provider/model"
30
+ },
24
31
  "crewly-agent": {
25
32
  "displayName": "Crewly Agent",
26
33
  "initScript": "",
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: Calendar Create
3
+ description: Create an event on the owner's Google Calendar (via the Google Workspace grant held by Crewly Cloud) — timed or all-day, with optional description and attendees. Attendees receive an invitation from the owner, so confirm before inviting others.
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
+ - create event
17
+ - schedule meeting
18
+ - add to calendar
19
+ - book a meeting
20
+ tags:
21
+ - google
22
+ - calendar
23
+ execution:
24
+ type: script
25
+ script:
26
+ file: execute.sh
27
+ interpreter: bash
28
+ timeoutMs: 30000
29
+ ---
30
+
31
+ # Calendar Create
32
+
33
+ ```bash
34
+ bash execute.sh --summary "Design review" --start 2026-09-20T14:00:00 --end 2026-09-20T15:00:00 \
35
+ --timezone Asia/Shanghai --description "Walk through v2" --attendee ann@example.com
36
+ bash execute.sh --summary "Offsite" --start 2026-10-01 --end 2026-10-02 # all-day (end is exclusive)
37
+ bash execute.sh '{"summary":"Standup","start":"2026-09-21T09:00:00Z","end":"2026-09-21T09:15:00Z"}'
38
+ ```
39
+
40
+ ## Parameters
41
+
42
+ | Name | Required | Meaning |
43
+ |---|---|---|
44
+ | `--summary` (`summary`) | yes | Event title |
45
+ | `--start` (`start`) | yes | ISO 8601 date-time, or `YYYY-MM-DD` for all-day |
46
+ | `--end` (`end`) | yes | ISO 8601 date-time, or `YYYY-MM-DD` (exclusive) for all-day |
47
+ | `--timezone` (`timezone`) | no | IANA zone applied to start/end without an offset |
48
+ | `--description` (`description`) | no | Body text |
49
+ | `--attendee` (`attendees`) | no | Email; repeat for several (JSON: array or comma list) |
50
+ | `--calendar` (`calendarId`) | no | Calendar id; default `primary` |
51
+
52
+ ## Output
53
+
54
+ ```json
55
+ {"success":true,"id":"…","summary":"Design review","start":{"dateTime":"…","timeZone":"Asia/Shanghai"},"end":{…},"htmlLink":"https://…","attendees":[{"email":"ann@example.com","responseStatus":"needsAction"}]}
56
+ ```
57
+
58
+ ## Failures
59
+
60
+ Missing `--summary` / `--start` / `--end` → `{"error":"Missing required parameter: …"}` on stderr, exit 1.
61
+ `{"success":false,"reason":"not_connected","hint":"<connect URL>"}` (exit 1) when the owner has not connected Google Workspace;
62
+ `reason` `validation` when Google cannot parse a time.
@@ -0,0 +1,91 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # calendar-create — Create an event on the owner's Google Calendar
4
+ #
5
+ # Backed by POST /api/google/calendar/events.
6
+ #
7
+ # Usage:
8
+ # bash execute.sh --summary "Review" --start 2026-09-20T14:00:00 --end 2026-09-20T15:00:00
9
+ # [--timezone Asia/Shanghai] [--description "…"] [--attendee a@b.c]... [--calendar id]
10
+ # bash execute.sh '{"summary":"Review","start":"…","end":"…","attendees":["a@b.c"]}'
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 --summary "Review" --start <ISO|YYYY-MM-DD> --end <ISO|YYYY-MM-DD>
20
+ [--timezone Asia/Shanghai] [--description "…"] [--attendee a@b.c]... [--calendar <id>]
21
+ bash execute.sh '{"summary":"Review","start":"…","end":"…","attendees":["a@b.c"]}'
22
+
23
+ Options:
24
+ --summary Event title (required)
25
+ --start Start: ISO 8601 date-time, or YYYY-MM-DD for all-day (required)
26
+ --end End: ISO 8601 date-time, or YYYY-MM-DD (exclusive) for all-day (required)
27
+ --timezone IANA zone for start/end without an offset
28
+ --description Body text
29
+ --attendee Attendee email (repeat for several)
30
+ --calendar Calendar id (default: primary)
31
+ --help | -h Show this help
32
+ EOF_USAGE
33
+ }
34
+
35
+ INPUT_JSON=""
36
+ SUMMARY=""; START=""; END=""; TIMEZONE=""; DESCRIPTION=""; CALENDAR=""
37
+ ATTENDEES_JSON='[]'
38
+
39
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
40
+ INPUT_JSON="$1"
41
+ shift || true
42
+ fi
43
+
44
+ while [[ $# -gt 0 ]]; do
45
+ case "$1" in
46
+ --summary|--title) [ $# -ge 2 ] || error_exit "--summary requires a value"; SUMMARY="$2"; shift 2 ;;
47
+ --start) [ $# -ge 2 ] || error_exit "--start requires a value"; START="$2"; shift 2 ;;
48
+ --end) [ $# -ge 2 ] || error_exit "--end requires a value"; END="$2"; shift 2 ;;
49
+ --timezone|--tz) [ $# -ge 2 ] || error_exit "--timezone requires a value"; TIMEZONE="$2"; shift 2 ;;
50
+ --description) [ $# -ge 2 ] || error_exit "--description requires a value"; DESCRIPTION="$2"; shift 2 ;;
51
+ --calendar|-c) [ $# -ge 2 ] || error_exit "--calendar requires a value"; CALENDAR="$2"; shift 2 ;;
52
+ --attendee) [ $# -ge 2 ] || error_exit "--attendee requires a value"
53
+ ATTENDEES_JSON=$(jq -cn --argjson arr "$ATTENDEES_JSON" --arg v "$2" '$arr + [$v]'); shift 2 ;;
54
+ --help|-h) print_usage; exit 0 ;;
55
+ *) error_exit "Unknown option: $1" ;;
56
+ esac
57
+ done
58
+
59
+ if [ -n "$INPUT_JSON" ]; then
60
+ INPUT=$(read_json_input "$INPUT_JSON")
61
+ [ -z "$SUMMARY" ] && SUMMARY=$(printf '%s' "$INPUT" | jq -r '.summary // .title // empty')
62
+ [ -z "$START" ] && START=$(printf '%s' "$INPUT" | jq -r '.start // empty')
63
+ [ -z "$END" ] && END=$(printf '%s' "$INPUT" | jq -r '.end // empty')
64
+ [ -z "$TIMEZONE" ] && TIMEZONE=$(printf '%s' "$INPUT" | jq -r '.timezone // .timeZone // empty')
65
+ [ -z "$DESCRIPTION" ] && DESCRIPTION=$(printf '%s' "$INPUT" | jq -r '.description // empty')
66
+ [ -z "$CALENDAR" ] && CALENDAR=$(printf '%s' "$INPUT" | jq -r '.calendarId // .calendar // empty')
67
+ if [ "$(printf '%s' "$ATTENDEES_JSON" | jq 'length')" -eq 0 ]; then
68
+ ATTENDEES_JSON=$(printf '%s' "$INPUT" | jq -c '(.attendees // []) | if type == "string" then split(",") | map(gsub("^\\s+|\\s+$"; "")) | map(select(. != "")) else . end')
69
+ fi
70
+ fi
71
+
72
+ require_param "summary (--summary)" "$SUMMARY"
73
+ require_param "start (--start)" "$START"
74
+ require_param "end (--end)" "$END"
75
+
76
+ BODY=$(jq -cn --arg summary "$SUMMARY" --arg start "$START" --arg end "$END" \
77
+ --arg timezone "$TIMEZONE" --arg description "$DESCRIPTION" --arg calendarId "$CALENDAR" \
78
+ --argjson attendees "$ATTENDEES_JSON" \
79
+ '{summary: $summary, start: $start, end: $end}
80
+ + (if $timezone != "" then {timezone: $timezone} else {} end)
81
+ + (if $description != "" then {description: $description} else {} end)
82
+ + (if $calendarId != "" then {calendarId: $calendarId} else {} end)
83
+ + (if ($attendees | length) > 0 then {attendees: $attendees} else {} end)')
84
+
85
+ RESPONSE=$(api_call POST "/google/calendar/events" "$BODY" 2>&1) || {
86
+ printf '%s' "$RESPONSE" | jq -c '{success: false, reason: (.details.error // .details // .error // "unknown"), hint: (.details.hint // ""), message: (.details.message // "")}' 2>/dev/null \
87
+ || jq -n --arg r "$RESPONSE" '{success: false, reason: $r}'
88
+ exit 1
89
+ }
90
+
91
+ printf '%s' "$RESPONSE" | jq -c '{success: (.success // false)} + (.data | {id, summary, start, end, htmlLink, attendees})'
@@ -0,0 +1,80 @@
1
+ #!/bin/bash
2
+ # Tests for calendar-create — run with: bash execute.test.sh
3
+ # Spins up a python HTTP stub as the backend, asserts the request body 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=18805
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
+ class H(BaseHTTPRequestHandler):
21
+ def do_POST(self):
22
+ n = int(self.headers.get('content-length', '0')); body = self.rfile.read(n).decode() if n else ''
23
+ data = json.loads(body or '{}')
24
+ open(LOG, 'w').write(json.dumps({'method': 'POST', 'path': self.path, 'body': data}))
25
+ if data.get('summary') == 'no-grant':
26
+ self.send_response(409); self.send_header('Content-Type', 'application/json'); self.end_headers()
27
+ self.wfile.write(json.dumps({'success': False, 'error': 'not_connected', 'message': 'no grant', 'hint': 'https://cloud/start?token=j'}).encode()); return
28
+ if data.get('start') == 'tomorrow':
29
+ self.send_response(400); self.send_header('Content-Type', 'application/json'); self.end_headers()
30
+ self.wfile.write(json.dumps({'success': False, 'error': 'validation', 'message': '"start" must be YYYY-MM-DD or an ISO 8601 date-time', 'hint': 'Fix the request and retry.'}).encode()); return
31
+ tz = data.get('timezone')
32
+ def t(v):
33
+ if len(v) == 10: return {'date': v}
34
+ return {'dateTime': v, 'timeZone': tz} if tz else {'dateTime': v}
35
+ ev = {'id': 'new1', 'summary': data['summary'], 'start': t(data['start']), 'end': t(data['end']), 'htmlLink': 'https://cal/new1',
36
+ 'attendees': [{'email': a, 'responseStatus': 'needsAction'} for a in data.get('attendees', [])], 'status': 'confirmed'}
37
+ self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers()
38
+ self.wfile.write(json.dumps({'success': True, 'data': ev}).encode())
39
+ def log_message(self, *a, **k): pass
40
+ HTTPServer(('127.0.0.1', PORT), H).serve_forever()
41
+ PY
42
+ STUB_PID=$!
43
+ disown "$STUB_PID" 2>/dev/null || true
44
+ trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
45
+ 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
46
+
47
+ run() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
48
+ run_err() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
49
+
50
+ # --- timed event with everything ---
51
+ OUT=$(run --summary "Design review" --start 2026-09-20T14:00:00 --end 2026-09-20T15:00:00 --timezone Asia/Shanghai \
52
+ --description "Walk through v2" --attendee ann@example.com --attendee bob@example.com --calendar ops@example.com)
53
+ check "flags: body" "$(jq -c .body "$STUB_LOG")" '{"summary":"Design review","start":"2026-09-20T14:00:00","end":"2026-09-20T15:00:00","timezone":"Asia/Shanghai","description":"Walk through v2","calendarId":"ops@example.com","attendees":["ann@example.com","bob@example.com"]}'
54
+ check "flags: path" "$(jq -r .path "$STUB_LOG")" "/api/google/calendar/events"
55
+ check "flags: output" "$OUT" '{"success":true,"id":"new1","summary":"Design review","start":{"dateTime":"2026-09-20T14:00:00","timeZone":"Asia/Shanghai"},"end":{"dateTime":"2026-09-20T15:00:00","timeZone":"Asia/Shanghai"},"htmlLink":"https://cal/new1","attendees":[{"email":"ann@example.com","responseStatus":"needsAction"},{"email":"bob@example.com","responseStatus":"needsAction"}]}'
56
+
57
+ # --- all-day via JSON, comma-separated attendees ---
58
+ OUT=$(run '{"summary":"Offsite","start":"2026-10-01","end":"2026-10-02","attendees":"a@b.c, d@e.f"}')
59
+ check "json: body omits optional keys, splits attendees" "$(jq -c .body "$STUB_LOG")" '{"summary":"Offsite","start":"2026-10-01","end":"2026-10-02","attendees":["a@b.c","d@e.f"]}'
60
+ check "json: all-day output" "$(printf '%s' "$OUT" | jq -c '{start, end}')" '{"start":{"date":"2026-10-01"},"end":{"date":"2026-10-02"}}'
61
+
62
+ # --- backend validation surfaces ---
63
+ OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --summary x --start tomorrow --end 2026-10-02 2>/dev/null); RC=$?
64
+ check "400: exit code" "$RC" "1"
65
+ check "400: reason" "$(printf '%s' "$OUT" | jq -r .reason)" "validation"
66
+
67
+ # --- 409 ---
68
+ OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --summary no-grant --start 2026-10-01 --end 2026-10-02 2>/dev/null)
69
+ check "409: reason + hint" "$OUT" '{"success":false,"reason":"not_connected","hint":"https://cloud/start?token=j","message":"no grant"}'
70
+
71
+ # --- local validation (nothing sent) ---
72
+ : > "$STUB_LOG"
73
+ check "missing summary errors" "$(run_err --start 2026-10-01 --end 2026-10-02)" "Missing required parameter: summary (--summary)"
74
+ check "missing start errors" "$(run_err --summary x --end 2026-10-02)" "Missing required parameter: start (--start)"
75
+ check "missing end errors" "$(run_err --summary x --start 2026-10-01)" "Missing required parameter: end (--end)"
76
+ check "validation: no request made" "$(cat "$STUB_LOG")" ""
77
+ check "unknown option errors" "$(run_err --bogus 1)" "Unknown option: --bogus"
78
+
79
+ echo "=== Results: $PASS passed, $FAIL failed ==="
80
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: Calendar List
3
+ description: List upcoming events on the owner's Google Calendar (via the Google Workspace grant held by Crewly Cloud). Defaults to the next 7 days on the primary calendar. 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
+ - list calendar
18
+ - check calendar
19
+ - what's on my calendar
20
+ - upcoming meetings
21
+ tags:
22
+ - google
23
+ - calendar
24
+ execution:
25
+ type: script
26
+ script:
27
+ file: execute.sh
28
+ interpreter: bash
29
+ timeoutMs: 30000
30
+ ---
31
+
32
+ # Calendar List
33
+
34
+ ```bash
35
+ bash execute.sh # next 7 days, primary calendar
36
+ bash execute.sh --from 2026-09-18T00:00:00Z --to 2026-09-19T00:00:00Z --max 20
37
+ bash execute.sh '{"calendarId":"team@group.calendar.google.com","from":"…","to":"…"}'
38
+ ```
39
+
40
+ ## Parameters
41
+
42
+ | Name | Required | Meaning |
43
+ |---|---|---|
44
+ | `--from` (`from`) | no | ISO 8601 lower bound; default now |
45
+ | `--to` (`to`) | no | ISO 8601 upper bound; default now + 7 days |
46
+ | `--calendar` (`calendarId`) | no | Calendar id; default `primary` |
47
+ | `--max` (`max`) | no | Result cap, default 50, max 250 |
48
+
49
+ ## Output
50
+
51
+ ```json
52
+ {"count":2,"events":[{"id":"…","summary":"Standup","start":{"dateTime":"2026-09-18T09:00:00+08:00"},"end":{"dateTime":"…"},"attendees":[{"email":"ann@example.com","responseStatus":"accepted"}],"htmlLink":"https://…"}]}
53
+ ```
54
+
55
+ ## Failures
56
+
57
+ `{"success":false,"reason":"not_connected","hint":"<connect URL>"}` (exit 1)
58
+ when the owner has not connected Google Workspace.
@@ -0,0 +1,88 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # calendar-list — Upcoming events on the owner's Google Calendar (read-only)
4
+ #
5
+ # Backed by GET /api/google/calendar/events?from=&to=&calendarId=&max=.
6
+ # Without --from/--to the window is now → now + 7 days.
7
+ #
8
+ # Usage:
9
+ # bash execute.sh [--from ISO] [--to ISO] [--calendar id] [--max 20]
10
+ # bash execute.sh '{"from":"…","to":"…","calendarId":"primary","max":20}'
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 [--from ISO-8601] [--to ISO-8601] [--calendar <id>] [--max 20]
20
+ bash execute.sh '{"from":"…","to":"…","calendarId":"primary","max":20}'
21
+
22
+ Options:
23
+ --from Lower bound (default: now)
24
+ --to Upper bound (default: now + 7 days)
25
+ --calendar Calendar id (default: primary)
26
+ --max Result cap (default 50, max 250)
27
+ --help | -h Show this help
28
+ EOF_USAGE
29
+ }
30
+
31
+ DEFAULT_WINDOW_DAYS="${CREWLY_CALENDAR_LIST_DAYS:-7}"
32
+
33
+ # Portable "now + N days" in UTC ISO 8601 (macOS `date -v`, GNU `date -d`).
34
+ iso_now_plus_days() {
35
+ local days="$1"
36
+ if date -u -v+"${days}"d +%Y-%m-%dT%H:%M:%SZ >/dev/null 2>&1; then
37
+ date -u -v+"${days}"d +%Y-%m-%dT%H:%M:%SZ
38
+ else
39
+ date -u -d "+${days} days" +%Y-%m-%dT%H:%M:%SZ
40
+ fi
41
+ }
42
+
43
+ INPUT_JSON=""
44
+ FROM=""; TO=""; CALENDAR=""; MAX=""
45
+
46
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
47
+ INPUT_JSON="$1"
48
+ shift || true
49
+ fi
50
+
51
+ while [[ $# -gt 0 ]]; do
52
+ case "$1" in
53
+ --from) [ $# -ge 2 ] || error_exit "--from requires a value"; FROM="$2"; shift 2 ;;
54
+ --to) [ $# -ge 2 ] || error_exit "--to requires a value"; TO="$2"; shift 2 ;;
55
+ --calendar|-c) [ $# -ge 2 ] || error_exit "--calendar requires a value"; CALENDAR="$2"; shift 2 ;;
56
+ --max|-n) [ $# -ge 2 ] || error_exit "--max requires a value"; MAX="$2"; shift 2 ;;
57
+ --help|-h) print_usage; exit 0 ;;
58
+ *) error_exit "Unknown option: $1" ;;
59
+ esac
60
+ done
61
+
62
+ if [ -n "$INPUT_JSON" ]; then
63
+ INPUT=$(read_json_input "$INPUT_JSON")
64
+ [ -z "$FROM" ] && FROM=$(printf '%s' "$INPUT" | jq -r '.from // .timeMin // empty')
65
+ [ -z "$TO" ] && TO=$(printf '%s' "$INPUT" | jq -r '.to // .timeMax // empty')
66
+ [ -z "$CALENDAR" ] && CALENDAR=$(printf '%s' "$INPUT" | jq -r '.calendarId // .calendar // empty')
67
+ [ -z "$MAX" ] && MAX=$(printf '%s' "$INPUT" | jq -r '.max // empty')
68
+ fi
69
+
70
+ [ -z "$FROM" ] && FROM=$(date -u +%Y-%m-%dT%H:%M:%SZ)
71
+ [ -z "$TO" ] && TO=$(iso_now_plus_days "$DEFAULT_WINDOW_DAYS")
72
+
73
+ QS="from=$(jq -rn --arg v "$FROM" '$v|@uri')&to=$(jq -rn --arg v "$TO" '$v|@uri')"
74
+ [ -n "$CALENDAR" ] && QS="${QS}&calendarId=$(jq -rn --arg v "$CALENDAR" '$v|@uri')"
75
+ [ -n "$MAX" ] && QS="${QS}&max=$(jq -rn --arg v "$MAX" '$v|@uri')"
76
+
77
+ RESPONSE=$(api_call GET "/google/calendar/events?${QS}" 2>&1) || {
78
+ printf '%s' "$RESPONSE" | jq -c '{success: false, reason: (.details.error // .details // .error // "unknown"), hint: (.details.hint // ""), message: (.details.message // "")}' 2>/dev/null \
79
+ || jq -n --arg r "$RESPONSE" '{success: false, reason: $r}'
80
+ exit 1
81
+ }
82
+
83
+ # Oversized bodies are parked on disk by api_call; pass that envelope through.
84
+ if printf '%s' "$RESPONSE" | jq -e '.truncated == true' >/dev/null 2>&1; then
85
+ printf '%s\n' "$RESPONSE"; exit 0
86
+ fi
87
+
88
+ printf '%s' "$RESPONSE" | jq -c '{count: .data.count, events: .data.events}'
@@ -0,0 +1,71 @@
1
+ #!/bin/bash
2
+ # Tests for calendar-list — 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=18804
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
+ EV = {'id': 'e1', 'summary': 'Standup', 'start': {'dateTime': '2026-09-18T09:00:00Z'}, 'end': {'dateTime': '2026-09-18T09:15:00Z'}, 'attendees': []}
22
+ class H(BaseHTTPRequestHandler):
23
+ def do_GET(self):
24
+ open(LOG, 'w').write(json.dumps({'method': 'GET', 'path': self.path}))
25
+ qs = parse_qs(urlparse(self.path).query)
26
+ if qs.get('calendarId', [''])[0] == 'no-grant':
27
+ self.send_response(409); self.send_header('Content-Type', 'application/json'); self.end_headers()
28
+ self.wfile.write(json.dumps({'success': False, 'error': 'not_connected', 'message': 'no grant', 'hint': 'https://cloud/start?token=j'}).encode()); return
29
+ self.send_response(200); self.send_header('Content-Type', 'application/json'); self.end_headers()
30
+ self.wfile.write(json.dumps({'success': True, 'data': {'count': 1, 'events': [EV]}}).encode())
31
+ def log_message(self, *a, **k): pass
32
+ HTTPServer(('127.0.0.1', PORT), H).serve_forever()
33
+ PY
34
+ STUB_PID=$!
35
+ disown "$STUB_PID" 2>/dev/null || true
36
+ trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
37
+ 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
38
+
39
+ run() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
40
+ run_err() { CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -r '.error' 2>/dev/null; }
41
+
42
+ WANT='{"count":1,"events":[{"id":"e1","summary":"Standup","start":{"dateTime":"2026-09-18T09:00:00Z"},"end":{"dateTime":"2026-09-18T09:15:00Z"},"attendees":[]}]}'
43
+
44
+ OUT=$(run --from 2026-09-18T00:00:00Z --to 2026-09-19T00:00:00Z --calendar "team@group.calendar.google.com" --max 20)
45
+ check "flags: output" "$OUT" "$WANT"
46
+ check "flags: path" "$(jq -r .path "$STUB_LOG")" "/api/google/calendar/events?from=2026-09-18T00%3A00%3A00Z&to=2026-09-19T00%3A00%3A00Z&calendarId=team%40group.calendar.google.com&max=20"
47
+
48
+ OUT=$(run '{"from":"2026-09-18T00:00:00Z","to":"2026-09-19T00:00:00Z"}')
49
+ check "json: output" "$OUT" "$WANT"
50
+ check "json: path without optional params" "$(jq -r .path "$STUB_LOG")" "/api/google/calendar/events?from=2026-09-18T00%3A00%3A00Z&to=2026-09-19T00%3A00%3A00Z"
51
+
52
+ # --- defaults: now → now + 7 days (shape only; values are wall-clock) ---
53
+ run >/dev/null
54
+ P=$(jq -r .path "$STUB_LOG")
55
+ FROM_V=$(printf '%s' "$P" | sed -E 's/.*[?&]from=([^&]*).*/\1/')
56
+ TO_V=$(printf '%s' "$P" | sed -E 's/.*[?&]to=([^&]*).*/\1/')
57
+ [[ "$FROM_V" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}%3A[0-9]{2}%3A[0-9]{2}Z$ ]] && FROM_OK=yes || FROM_OK=no
58
+ [[ "$TO_V" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}%3A[0-9]{2}%3A[0-9]{2}Z$ ]] && TO_OK=yes || TO_OK=no
59
+ check "defaults: from is ISO UTC" "$FROM_OK" "yes"
60
+ check "defaults: to is ISO UTC" "$TO_OK" "yes"
61
+ [ "$TO_V" \> "$FROM_V" ] && ORDER=yes || ORDER=no
62
+ check "defaults: to is after from" "$ORDER" "yes"
63
+
64
+ OUT=$(CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" --calendar no-grant 2>/dev/null); RC=$?
65
+ check "409: exit code" "$RC" "1"
66
+ check "409: reason + hint" "$OUT" '{"success":false,"reason":"not_connected","hint":"https://cloud/start?token=j","message":"no grant"}'
67
+
68
+ check "unknown option errors" "$(run_err --bogus 1)" "Unknown option: --bogus"
69
+
70
+ echo "=== Results: $PASS passed, $FAIL failed ==="
71
+ [ "$FAIL" -eq 0 ]