@hailer/mcp 1.1.16 → 1.1.17-beta.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 (313) hide show
  1. package/.claude/CLAUDE.md +117 -320
  2. package/.claude/commands/app-squad.md +86 -90
  3. package/.claude/commands/audit-squad.md +19 -19
  4. package/.claude/commands/autoplan.md +3 -3
  5. package/.claude/commands/cleanup-squad.md +16 -16
  6. package/.claude/commands/config-squad.md +30 -30
  7. package/.claude/commands/crud-squad.md +23 -23
  8. package/.claude/commands/data-squad.md +21 -21
  9. package/.claude/commands/debug-squad.md +44 -44
  10. package/.claude/commands/doc-squad.md +16 -16
  11. package/.claude/commands/help:agents.md +130 -99
  12. package/.claude/commands/help:commands.md +15 -15
  13. package/.claude/commands/help:faq.md +17 -17
  14. package/.claude/commands/help:plugins.md +1 -1
  15. package/.claude/commands/help:skills.md +18 -24
  16. package/.claude/commands/hotfix-squad.md +22 -22
  17. package/.claude/commands/integration-squad.md +22 -22
  18. package/.claude/commands/janitor-squad.md +31 -31
  19. package/.claude/commands/learn-auto.md +5 -5
  20. package/.claude/commands/learn.md +12 -20
  21. package/.claude/commands/onboard-squad.md +39 -49
  22. package/.claude/commands/plan-workspace.md +2 -2
  23. package/.claude/commands/publish.md +32 -37
  24. package/.claude/commands/review-squad.md +27 -27
  25. package/.claude/commands/stats.md +26 -12
  26. package/.claude/commands/swarm.md +25 -25
  27. package/.claude/skills/chrome-mcp-reference/SKILL.md +5 -0
  28. package/.claude/skills/hailer-api-client/SKILL.md +55 -16
  29. package/.claude/skills/hailer-app-builder/SKILL.md +4 -270
  30. package/.claude/skills/hailer-apps-pictures/SKILL.md +3 -3
  31. package/.claude/skills/hailer-design-system/SKILL.md +96 -4
  32. package/.claude/skills/hailer-monolith-automations/SKILL.md +138 -116
  33. package/.claude/skills/hailer-permissions-system/SKILL.md +6 -9
  34. package/.claude/skills/hailer-project-protocol/SKILL.md +20 -110
  35. package/.claude/skills/integration-patterns/SKILL.md +6 -6
  36. package/.claude/skills/lsp-setup/SKILL.md +8 -9
  37. package/.claude/skills/sdk-activity-patterns/SKILL.md +238 -0
  38. package/.claude/skills/{SDK-document-templates → sdk-document-templates}/SKILL.md +13 -340
  39. package/.claude/skills/{SDK-function-fields → sdk-function-fields}/SKILL.md +8 -40
  40. package/.claude/skills/{SDK-insight-queries → sdk-insight-queries}/SKILL.md +114 -392
  41. package/.claude/skills/{SDK-ws-config-skill → sdk-ws-config-skill}/SKILL.md +79 -310
  42. package/.claude/skills/zapier-hailer-patterns/SKILL.md +84 -361
  43. package/.opencode/package-lock.json +117 -0
  44. package/CLAUDE.md +5 -358
  45. package/dist/app.d.ts.map +1 -1
  46. package/dist/app.js +10 -127
  47. package/dist/app.js.map +1 -1
  48. package/dist/bot/bot-manager.d.ts +3 -14
  49. package/dist/bot/bot-manager.d.ts.map +1 -1
  50. package/dist/bot/bot-manager.js +13 -4
  51. package/dist/bot/bot-manager.js.map +1 -1
  52. package/dist/bot/bot.d.ts +23 -102
  53. package/dist/bot/bot.d.ts.map +1 -1
  54. package/dist/bot/bot.js +356 -1212
  55. package/dist/bot/bot.js.map +1 -1
  56. package/dist/bot/services/bot-permissions.d.ts +50 -0
  57. package/dist/bot/services/bot-permissions.d.ts.map +1 -0
  58. package/dist/bot/services/bot-permissions.js +198 -0
  59. package/dist/bot/services/bot-permissions.js.map +1 -0
  60. package/dist/bot/services/index.d.ts +4 -2
  61. package/dist/bot/services/index.d.ts.map +1 -1
  62. package/dist/bot/services/index.js +10 -5
  63. package/dist/bot/services/index.js.map +1 -1
  64. package/dist/bot/services/message-classifier.d.ts +1 -1
  65. package/dist/bot/services/message-classifier.d.ts.map +1 -1
  66. package/dist/bot/services/message-classifier.js.map +1 -1
  67. package/dist/bot/services/signal-router.d.ts +32 -0
  68. package/dist/bot/services/signal-router.d.ts.map +1 -0
  69. package/dist/bot/services/signal-router.js +132 -0
  70. package/dist/bot/services/signal-router.js.map +1 -0
  71. package/dist/bot/services/system-prompt.d.ts +12 -0
  72. package/dist/bot/services/system-prompt.d.ts.map +1 -0
  73. package/dist/bot/services/system-prompt.js +93 -0
  74. package/dist/bot/services/system-prompt.js.map +1 -0
  75. package/dist/bot/services/types.d.ts +7 -34
  76. package/dist/bot/services/types.d.ts.map +1 -1
  77. package/dist/bot/services/types.js +0 -3
  78. package/dist/bot/services/types.js.map +1 -1
  79. package/dist/bot/services/workspace-refresh.d.ts +47 -0
  80. package/dist/bot/services/workspace-refresh.d.ts.map +1 -0
  81. package/dist/bot/services/workspace-refresh.js +154 -0
  82. package/dist/bot/services/workspace-refresh.js.map +1 -0
  83. package/dist/bot-config/constants.d.ts +0 -36
  84. package/dist/bot-config/constants.d.ts.map +1 -1
  85. package/dist/bot-config/constants.js +1 -76
  86. package/dist/bot-config/constants.js.map +1 -1
  87. package/dist/bot-config/context.d.ts +2 -42
  88. package/dist/bot-config/context.d.ts.map +1 -1
  89. package/dist/bot-config/context.js +13 -134
  90. package/dist/bot-config/context.js.map +1 -1
  91. package/dist/bot-config/index.d.ts +6 -15
  92. package/dist/bot-config/index.d.ts.map +1 -1
  93. package/dist/bot-config/index.js +5 -80
  94. package/dist/bot-config/index.js.map +1 -1
  95. package/dist/bot-config/loader.d.ts +16 -4
  96. package/dist/bot-config/loader.d.ts.map +1 -1
  97. package/dist/bot-config/loader.js +187 -96
  98. package/dist/bot-config/loader.js.map +1 -1
  99. package/dist/bot-config/persistence.d.ts +1 -52
  100. package/dist/bot-config/persistence.d.ts.map +1 -1
  101. package/dist/bot-config/persistence.js +3 -213
  102. package/dist/bot-config/persistence.js.map +1 -1
  103. package/dist/bot-config/state.d.ts +0 -41
  104. package/dist/bot-config/state.d.ts.map +1 -1
  105. package/dist/bot-config/state.js +0 -151
  106. package/dist/bot-config/state.js.map +1 -1
  107. package/dist/bot-config/tools.d.ts +1 -1
  108. package/dist/bot-config/tools.js +27 -27
  109. package/dist/bot-config/tools.js.map +1 -1
  110. package/dist/bot-config/types.d.ts +39 -32
  111. package/dist/bot-config/types.d.ts.map +1 -1
  112. package/dist/bot-config/types.js +0 -3
  113. package/dist/bot-config/types.js.map +1 -1
  114. package/dist/bot-config/webhooks.d.ts +0 -4
  115. package/dist/bot-config/webhooks.d.ts.map +1 -1
  116. package/dist/bot-config/webhooks.js +0 -13
  117. package/dist/bot-config/webhooks.js.map +1 -1
  118. package/dist/commands/seed-config.js +16 -31
  119. package/dist/commands/seed-config.js.map +1 -1
  120. package/dist/config.d.ts +0 -9
  121. package/dist/config.d.ts.map +1 -1
  122. package/dist/config.js +0 -15
  123. package/dist/config.js.map +1 -1
  124. package/dist/mcp/hailer-clients.js +2 -2
  125. package/dist/mcp/hailer-clients.js.map +1 -1
  126. package/dist/mcp/tool-registry.d.ts +10 -115
  127. package/dist/mcp/tool-registry.d.ts.map +1 -1
  128. package/dist/mcp/tool-registry.js +39 -363
  129. package/dist/mcp/tool-registry.js.map +1 -1
  130. package/dist/mcp/tools/activity.d.ts +3 -0
  131. package/dist/mcp/tools/activity.d.ts.map +1 -1
  132. package/dist/mcp/tools/activity.js +8 -1
  133. package/dist/mcp/tools/activity.js.map +1 -1
  134. package/dist/mcp/tools/app-core.d.ts +3 -0
  135. package/dist/mcp/tools/app-core.d.ts.map +1 -1
  136. package/dist/mcp/tools/app-core.js +9 -2
  137. package/dist/mcp/tools/app-core.js.map +1 -1
  138. package/dist/mcp/tools/app-marketplace.d.ts +3 -0
  139. package/dist/mcp/tools/app-marketplace.d.ts.map +1 -1
  140. package/dist/mcp/tools/app-marketplace.js +13 -1
  141. package/dist/mcp/tools/app-marketplace.js.map +1 -1
  142. package/dist/mcp/tools/app-member.d.ts +3 -0
  143. package/dist/mcp/tools/app-member.d.ts.map +1 -1
  144. package/dist/mcp/tools/app-member.js +6 -1
  145. package/dist/mcp/tools/app-member.js.map +1 -1
  146. package/dist/mcp/tools/app-scaffold.d.ts +3 -0
  147. package/dist/mcp/tools/app-scaffold.d.ts.map +1 -1
  148. package/dist/mcp/tools/app-scaffold.js +15 -11
  149. package/dist/mcp/tools/app-scaffold.js.map +1 -1
  150. package/dist/mcp/tools/company.d.ts +3 -0
  151. package/dist/mcp/tools/company.d.ts.map +1 -1
  152. package/dist/mcp/tools/company.js +5 -1
  153. package/dist/mcp/tools/company.js.map +1 -1
  154. package/dist/mcp/tools/discussion.d.ts +3 -0
  155. package/dist/mcp/tools/discussion.d.ts.map +1 -1
  156. package/dist/mcp/tools/discussion.js +13 -2
  157. package/dist/mcp/tools/discussion.js.map +1 -1
  158. package/dist/mcp/tools/file.d.ts +3 -0
  159. package/dist/mcp/tools/file.d.ts.map +1 -1
  160. package/dist/mcp/tools/file.js +6 -1
  161. package/dist/mcp/tools/file.js.map +1 -1
  162. package/dist/mcp/tools/index.d.ts +7 -0
  163. package/dist/mcp/tools/index.d.ts.map +1 -0
  164. package/dist/mcp/tools/index.js +34 -0
  165. package/dist/mcp/tools/index.js.map +1 -0
  166. package/dist/mcp/tools/insight.d.ts +3 -0
  167. package/dist/mcp/tools/insight.d.ts.map +1 -1
  168. package/dist/mcp/tools/insight.js +18 -8
  169. package/dist/mcp/tools/insight.js.map +1 -1
  170. package/dist/mcp/tools/user.d.ts +3 -0
  171. package/dist/mcp/tools/user.d.ts.map +1 -1
  172. package/dist/mcp/tools/user.js +6 -1
  173. package/dist/mcp/tools/user.js.map +1 -1
  174. package/dist/mcp/tools/workflow-permissions.d.ts +3 -0
  175. package/dist/mcp/tools/workflow-permissions.d.ts.map +1 -1
  176. package/dist/mcp/tools/workflow-permissions.js +8 -1
  177. package/dist/mcp/tools/workflow-permissions.js.map +1 -1
  178. package/dist/mcp/tools/workflow.d.ts +3 -0
  179. package/dist/mcp/tools/workflow.d.ts.map +1 -1
  180. package/dist/mcp/tools/workflow.js +29 -28
  181. package/dist/mcp/tools/workflow.js.map +1 -1
  182. package/dist/mcp/utils/index.d.ts +4 -11
  183. package/dist/mcp/utils/index.d.ts.map +1 -1
  184. package/dist/mcp/utils/index.js +5 -36
  185. package/dist/mcp/utils/index.js.map +1 -1
  186. package/dist/mcp/utils/role-utils.d.ts +0 -32
  187. package/dist/mcp/utils/role-utils.d.ts.map +1 -1
  188. package/dist/mcp/utils/role-utils.js +0 -73
  189. package/dist/mcp/utils/role-utils.js.map +1 -1
  190. package/dist/mcp/utils/tool-helpers.d.ts +0 -25
  191. package/dist/mcp/utils/tool-helpers.d.ts.map +1 -1
  192. package/dist/mcp/utils/tool-helpers.js +0 -34
  193. package/dist/mcp/utils/tool-helpers.js.map +1 -1
  194. package/dist/mcp/webhook-handler.d.ts +4 -34
  195. package/dist/mcp/webhook-handler.d.ts.map +1 -1
  196. package/dist/mcp/webhook-handler.js +57 -74
  197. package/dist/mcp/webhook-handler.js.map +1 -1
  198. package/dist/mcp-server.d.ts.map +1 -1
  199. package/dist/mcp-server.js +3 -78
  200. package/dist/mcp-server.js.map +1 -1
  201. package/package.json +1 -2
  202. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  203. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  204. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  205. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  206. package/.claude/agents/agent-code-simplifier.md +0 -53
  207. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  208. package/.claude/agents/agent-giuseppe-app-builder.md +0 -208
  209. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  210. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  211. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  212. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  213. package/.claude/agents/agent-ivan-monolith.md +0 -154
  214. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  215. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  216. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  217. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  218. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  219. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  220. package/.claude/agents/agent-permissions-handler.md +0 -208
  221. package/.claude/agents/agent-simple-writer.md +0 -48
  222. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  223. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  224. package/.claude/agents/agent-ui-designer.md +0 -100
  225. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  226. package/.claude/agents/agent-web-search.md +0 -55
  227. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  228. package/.claude/agents/agent-zara-zapier.md +0 -159
  229. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  230. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  231. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  232. package/.claude/skills/agent-structure/SKILL.md +0 -98
  233. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  234. package/.claude/skills/frontend-design/SKILL.md +0 -254
  235. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  236. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  237. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  238. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  239. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  240. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  241. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  242. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  243. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  244. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  245. package/.claude/skills/json-only-output/SKILL.md +0 -72
  246. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  247. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  248. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  249. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  250. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  251. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  252. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  253. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  254. package/.opencode/agent/agent-code-simplifier.md +0 -31
  255. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  256. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  257. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  258. package/.opencode/agent/agent-helga-workflow-config.md +0 -204
  259. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  260. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  261. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  262. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  263. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  264. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  265. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  266. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  267. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  268. package/.opencode/agent/agent-permissions-handler.md +0 -50
  269. package/.opencode/agent/agent-simple-writer.md +0 -45
  270. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  271. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  272. package/.opencode/agent/agent-ui-designer.md +0 -56
  273. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  274. package/.opencode/agent/agent-web-search.md +0 -42
  275. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  276. package/.opencode/agent/agent-zara-zapier.md +0 -53
  277. package/.opencode/commands/app-squad.md +0 -135
  278. package/.opencode/commands/audit-squad.md +0 -158
  279. package/.opencode/commands/autoplan.md +0 -563
  280. package/.opencode/commands/cleanup-squad.md +0 -98
  281. package/.opencode/commands/config-squad.md +0 -106
  282. package/.opencode/commands/crud-squad.md +0 -87
  283. package/.opencode/commands/data-squad.md +0 -97
  284. package/.opencode/commands/debug-squad.md +0 -303
  285. package/.opencode/commands/doc-squad.md +0 -65
  286. package/.opencode/commands/handoff.md +0 -137
  287. package/.opencode/commands/health.md +0 -49
  288. package/.opencode/commands/help-agents.md +0 -151
  289. package/.opencode/commands/help-commands.md +0 -32
  290. package/.opencode/commands/help-faq.md +0 -29
  291. package/.opencode/commands/help-plugins.md +0 -28
  292. package/.opencode/commands/help-skills.md +0 -7
  293. package/.opencode/commands/help-tools.md +0 -40
  294. package/.opencode/commands/help.md +0 -28
  295. package/.opencode/commands/hotfix-squad.md +0 -112
  296. package/.opencode/commands/integration-squad.md +0 -82
  297. package/.opencode/commands/janitor-squad.md +0 -167
  298. package/.opencode/commands/learn-auto.md +0 -120
  299. package/.opencode/commands/learn.md +0 -120
  300. package/.opencode/commands/mcp-list.md +0 -27
  301. package/.opencode/commands/onboard-squad.md +0 -140
  302. package/.opencode/commands/plan-workspace.md +0 -732
  303. package/.opencode/commands/prd.md +0 -131
  304. package/.opencode/commands/project-status.md +0 -82
  305. package/.opencode/commands/publish.md +0 -138
  306. package/.opencode/commands/recap.md +0 -69
  307. package/.opencode/commands/restore.md +0 -64
  308. package/.opencode/commands/review-squad.md +0 -152
  309. package/.opencode/commands/save.md +0 -24
  310. package/.opencode/commands/stats.md +0 -19
  311. package/.opencode/commands/swarm.md +0 -210
  312. package/.opencode/commands/tool-builder.md +0 -39
  313. package/.opencode/commands/ws-pull.md +0 -44
@@ -0,0 +1,238 @@
1
+ ---
2
+ name: sdk-activity-patterns
3
+ description: Activity CRUD patterns - field value formats, dates, users, links, dropdowns
4
+ version: 1.5.0
5
+ triggers: Create activity, update activity, field values, date format, activitylink value
6
+ ---
7
+
8
+ # Activity CRUD Patterns
9
+
10
+ ## Create Activity
11
+
12
+ ```javascript
13
+ mcp__hailer__create_activity({
14
+ workflowId: "682ac815fba468d857d498f7",
15
+ phaseId: "682ac815fba468d857d49904",
16
+ name: "New Task", // Optional
17
+ fields: {
18
+ "fieldId1": "value1",
19
+ "fieldId2": "value2"
20
+ }
21
+ })
22
+ ```
23
+
24
+ ## Update Activity
25
+
26
+ ```javascript
27
+ mcp__hailer__update_activity({
28
+ activityId: "692abc123def456",
29
+ fields: { "fieldId1": "new value" },
30
+ phaseId: "682ac815fba468d857d49906" // Optional: move to different phase
31
+ })
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Critical Field Value Rules
37
+
38
+ **All single-value fields use STRING, not array.** No multi-select types exist in Hailer.
39
+
40
+ ```javascript
41
+ // ✅ Correct
42
+ fields: { priority: "High", assignee: "userId", customer: "actId" }
43
+
44
+ // ❌ Wrong — arrays rejected
45
+ fields: { priority: ["High"], assignee: ["userId"], customer: ["actId"] }
46
+ ```
47
+
48
+ **Dates are Unix timestamps in milliseconds** (not ISO strings):
49
+ ```javascript
50
+ fields: { due_date: new Date('2024-11-07').getTime() } // 1730937600000
51
+ ```
52
+
53
+ **Time fields** also use full millisecond timestamps including date:
54
+ ```javascript
55
+ const today = new Date();
56
+ today.setUTCHours(9, 30, 0, 0);
57
+ fields: { start_time: today.getTime() }
58
+ ```
59
+
60
+ **daterange / datetimerange** use object with `start` + `end`:
61
+ ```javascript
62
+ fields: { period: { start: 1730937600000, end: 1731024000000 } }
63
+ ```
64
+
65
+ **activitylink** is plain string ID — READ format (object with `_id`, `name`) differs from WRITE format:
66
+ ```javascript
67
+ // ✅ Write: plain string ID
68
+ fields: { customer: "692abc123def456" }
69
+
70
+ // ❌ Wrong: object (this is what you get when reading)
71
+ fields: { customer: { _id: "692abc123def456", name: "Acme" } }
72
+ ```
73
+
74
+ **textpredefinedoptions** is the exact option string, not an array:
75
+ ```javascript
76
+ fields: { status: "In Progress" }
77
+ ```
78
+
79
+ **text fields must always be strings**, even for numeric-looking values:
80
+ ```javascript
81
+ fields: { code: "300" } // not 300
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Modified Fields (Checkbox & File)
87
+
88
+ These use base types with a `modifier` in the field config:
89
+
90
+ | Config | Write Format |
91
+ |--------|-------------|
92
+ | `numeric` + `modifier.checkbox: true` | `1` (true) or `0` (false) |
93
+ | `text` + `modifier.file: true` | File reference (UI handles upload) |
94
+
95
+ ---
96
+
97
+ ## Clearing Field Values
98
+
99
+ ```javascript
100
+ mcp__hailer__update_activity({
101
+ activityId: "692abc123def456",
102
+ fields: {
103
+ "assignee_abc": "", // Clear user
104
+ "due_date_def": null, // Clear date
105
+ "notes_ghi": "" // Clear text
106
+ }
107
+ })
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Bulk Creation
113
+
114
+ Use the `activities[]` array for bulk creation. **Each activity must include its own `teamId` and `phaseId`.**
115
+
116
+ ```javascript
117
+ mcp__hailer__create_activity({
118
+ workflowId: "682ac815fba468d857d498f7",
119
+ activities: [
120
+ {
121
+ name: "Task 1",
122
+ phaseId: "682ac815fba468d857d49904",
123
+ teamId: "690d2b2e2b3a4c5d6e7f8a9b", // REQUIRED per activity!
124
+ fields: { "priority_abc": "High" }
125
+ },
126
+ {
127
+ name: "Task 2",
128
+ phaseId: "682ac815fba468d857d49904",
129
+ teamId: "690d2b2e2b3a4c5d6e7f8a9b",
130
+ fields: { "priority_abc": "Medium" }
131
+ }
132
+ ]
133
+ })
134
+ ```
135
+
136
+ ### Single vs Bulk: Parameter Placement
137
+
138
+ | Parameter | Single mode | Bulk mode |
139
+ |-----------|-------------|-----------|
140
+ | `name` | Top-level | Inside each `activities[]` item |
141
+ | `phaseId` | Top-level | Inside each `activities[]` item |
142
+ | `teamId` | Top-level | **Inside each `activities[]` item** |
143
+ | `fields` | Top-level | Inside each `activities[]` item |
144
+ | `workflowId` | Top-level | Top-level (shared) |
145
+
146
+ **CRITICAL:** In bulk mode, `teamId` at the top level is **IGNORED**. Each activity in the array must have its own `teamId`. Omitting it causes "Missing team(s)" (code 127) unless the workflow has a default team.
147
+
148
+ ### Team ID Fallback Chain
149
+
150
+ The MCP tool auto-fills `teamId` if omitted:
151
+ 1. Per-activity `teamId` (if provided) — **always provide this**
152
+ 2. Workflow's default team (`workflow.team`)
153
+ 3. First workspace team (last resort, may be wrong team)
154
+
155
+ **Best practice:** Always pass `teamId` explicitly. Get IDs from `workspace/teams.ts`.
156
+
157
+ ### Common Error: "Missing team(s)" (Code 127)
158
+
159
+ **Fix options:**
160
+ 1. Pass `teamId` explicitly in every create call (best)
161
+ 2. Set default team on the workflow in Hailer UI
162
+ 3. Ask orchestrator for available team IDs before creating
163
+
164
+ ---
165
+
166
+ ## Enum Key vs ObjectId Gotcha
167
+
168
+ MCP tools require actual MongoDB ObjectIds (24-char hex strings), not enum key names.
169
+
170
+ ```javascript
171
+ // ❌ WRONG - enum KEY NAME, not the ID
172
+ mcp__hailer__create_activity({
173
+ workflowId: "Asiakkaat", // enum key
174
+ fields: { "projekti_f84": "value" } // enum key
175
+ })
176
+
177
+ // ✅ CORRECT - real ObjectIds
178
+ mcp__hailer__create_activity({
179
+ workflowId: "682ac815fba468d857d498f7",
180
+ fields: { "68cbfec59b3869137fe2af84": "value" }
181
+ })
182
+ ```
183
+
184
+ **TypeScript code vs MCP calls:**
185
+ - **TypeScript:** Use enums for type safety → `WorkflowIds.Asiakkaat` resolves to the ObjectId
186
+ - **MCP tools:** Pass the actual ObjectId string directly
187
+
188
+ **Where to get real IDs:**
189
+ - `workspace/enums.ts` → enum values ARE the real ObjectIds
190
+ - `list_workflows` → workflow `_id` field
191
+ - `get_workflow_schema` → field `_id` property
192
+
193
+ ---
194
+
195
+ ## Phase Transitions
196
+
197
+ ```javascript
198
+ // Move only
199
+ mcp__hailer__update_activity({ activityId: "...", phaseId: "..." })
200
+
201
+ // Move + update fields
202
+ mcp__hailer__update_activity({
203
+ activityId: "692abc123def456",
204
+ phaseId: "682ac815fba468d857d49906",
205
+ fields: { "completed_date_abc": Date.now() }
206
+ })
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Checklist
212
+
213
+ Before creating/updating activities:
214
+
215
+ - [ ] Have workflow ID (from enum or API)
216
+ - [ ] Have phase ID (from enum or API)
217
+ - [ ] Have field IDs (from enum or API)
218
+ - [ ] Have **team ID** (from teams.ts or API) — don't rely on fallbacks
219
+ - [ ] All values are **STRINGS** for select/user/link fields (no multi-select types exist)
220
+ - [ ] Dates are **Unix timestamps in milliseconds**
221
+ - [ ] Times are **Unix timestamps in milliseconds** (like dates)
222
+ - [ ] **Bulk mode:** teamId, phaseId, fields are **inside each activity object**, not top-level
223
+
224
+ ---
225
+
226
+ ## Common Mistakes
227
+
228
+ | Wrong | Right |
229
+ |-------|-------|
230
+ | `{ priority: ["High"] }` | `{ priority: "High" }` (string) |
231
+ | `{ assignee: ["userId"] }` | `{ assignee: "userId" }` (string) |
232
+ | `{ customer: ["actId"] }` | `{ customer: "actId" }` (string) |
233
+ | `{ date: "2024-11-07" }` | `{ date: 1730937600000 }` (timestamp ms) |
234
+ | `{ time: "09:00" }` | `{ time: 1765863000000 }` (ms timestamp) |
235
+ | `{ daterange: 1730937600000 }` | `{ daterange: { start: ..., end: ... } }` |
236
+ | `{ textField: 300 }` | `{ textField: "300" }` (must be string) |
237
+ | Passing enum key names as IDs | Use real 24-char hex ObjectIds |
238
+ | Bulk create with top-level teamId | Put teamId INSIDE each activity object |
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: SDK-document-templates
2
+ name: sdk-document-templates
3
3
  description: PDF/CSV document template patterns - field mappings, pdfmake structure, generation code
4
4
  version: 1.2.0
5
5
  triggers: Document template, PDF generation, CSV export, pdfmake, field mapping
@@ -21,6 +21,17 @@ workspace/[Workflow]_[id]/
21
21
 
22
22
  ## Template Lifecycle
23
23
 
24
+ ### Sync vs Push
25
+
26
+ | Command | Creates new | Updates existing | Deletes removed |
27
+ |---------|-------------|------------------|-----------------|
28
+ | `templates sync` | Yes | No | Yes |
29
+ | `templates push` | No | Yes | No |
30
+
31
+ **New template flow:** Add entry to `templates.ts` → `npm run templates-sync` (creates template on server) → `npm run pull` (downloads generated folder + `template.config.ts` + `template.code.ts`) → edit config/code → `npm run templates-push`.
32
+
33
+ **Updating existing:** Just edit `template.config.ts` or `template.code.ts` and run `npm run templates-push`.
34
+
24
35
  ### Creating New Template
25
36
 
26
37
  ```
@@ -317,91 +328,7 @@ export class invoice_abc {
317
328
 
318
329
  ---
319
330
 
320
- ## pdfmake Patterns
321
-
322
- ### Basic Text
323
- ```javascript
324
- { text: 'Hello World' }
325
- { text: 'Bold text', bold: true }
326
- { text: 'Large text', fontSize: 14 }
327
- ```
328
-
329
- ### Using Field Values
330
- ```javascript
331
- const fields = this.fieldMap.fields;
332
-
333
- { text: fields.invoiceNumber?.value || 'N/A' }
334
- { text: fields.customerName?.label + ': ' + fields.customerName?.value }
335
- ```
336
-
337
- ### Columns
338
- ```javascript
339
- {
340
- columns: [
341
- { width: '*', text: 'Left side' },
342
- { width: 'auto', text: 'Right side' }
343
- ]
344
- }
345
- ```
346
-
347
- ### Tables
348
- ```javascript
349
- {
350
- table: {
351
- headerRows: 1,
352
- widths: ['*', 100, 100],
353
- body: [
354
- // Header row
355
- [
356
- { text: 'Item', bold: true },
357
- { text: 'Qty', bold: true },
358
- { text: 'Price', bold: true }
359
- ],
360
- // Data rows
361
- ['Product A', '10', '€100.00'],
362
- ['Product B', '5', '€50.00']
363
- ]
364
- }
365
- }
366
- ```
367
-
368
- ### Table Spacing for Label:Value Grids
369
-
370
- For 4-column label:value layouts, use narrower label columns to keep values close:
371
- ```javascript
372
- // ✅ Good: Values stay close to labels
373
- {
374
- table: {
375
- widths: [90, 'auto', 90, 'auto'],
376
- body: [
377
- [
378
- { text: 'Tilaaja:', bold: true }, fields.customer?.value || '',
379
- { text: 'Päivämäärä:', bold: true }, fields.date?.value || ''
380
- ]
381
- ]
382
- },
383
- layout: 'noBorders'
384
- }
385
-
386
- // ❌ Avoid: [120, '*', 120, '*'] spreads content too wide
387
- ```
388
- ```
389
-
390
- ### Images
391
- ```javascript
392
- // From fieldMap
393
- {
394
- image: this.fieldMap.images?.logo?.value,
395
- width: 150
396
- }
397
-
398
- // With fallback
399
- this.fieldMap.images?.logo?.value
400
- ? { image: this.fieldMap.images.logo.value, width: 150 }
401
- : { text: 'No logo', italics: true }
402
- ```
403
-
404
- ### Logo in Header (Two-Step Requirement)
331
+ ## Logo in Header (Two-Step Requirement)
405
332
 
406
333
  **CRITICAL:** Logo in PDF header requires BOTH config AND code reference:
407
334
 
@@ -437,111 +364,6 @@ getEmptyPdfDoc(fieldMap) {
437
364
 
438
365
  **Common mistake:** Adding logo to config but not referencing in header function → logo doesn't appear.
439
366
 
440
- ### Margins & Spacing
441
- ```javascript
442
- // [left, top, right, bottom]
443
- { text: 'Padded', margin: [10, 20, 10, 20] }
444
-
445
- // Blank line
446
- { text: ' ' }
447
- { text: '', margin: [0, 10, 0, 0] }
448
- ```
449
-
450
- ### Styles
451
- ```javascript
452
- // Define in getEmptyPdfDoc
453
- styles: {
454
- header: { fontSize: 18, bold: true },
455
- subheader: { fontSize: 14, bold: true },
456
- tableHeader: { bold: true, fillColor: '#eeeeee' }
457
- }
458
-
459
- // Use
460
- { text: 'Title', style: 'header' }
461
- ```
462
-
463
- ---
464
-
465
- ## Complete PDF Example
466
-
467
- ```javascript
468
- async setPdfDefinition() {
469
- const fields = this.fieldMap.fields;
470
- const images = this.fieldMap.images;
471
-
472
- const doc = this.getEmptyPdfDoc(this.fieldMap);
473
-
474
- // Header with logo
475
- doc.content.push({
476
- columns: [
477
- images?.logo?.value
478
- ? { image: images.logo.value, width: 120 }
479
- : { text: '' },
480
- {
481
- alignment: 'right',
482
- stack: [
483
- { text: 'INVOICE', style: 'header' },
484
- { text: fields.invoiceNumber?.value || '' }
485
- ]
486
- }
487
- ]
488
- });
489
-
490
- // Customer info
491
- doc.content.push({ text: ' ' });
492
- doc.content.push({
493
- text: fields.customerName?.value || 'Unknown Customer',
494
- style: 'subheader'
495
- });
496
-
497
- // Line items table
498
- doc.content.push({ text: ' ' });
499
- doc.content.push(this.buildLineItemsTable());
500
-
501
- // Total
502
- doc.content.push({
503
- alignment: 'right',
504
- text: `Total: €${fields.amount?.value || '0.00'}`,
505
- bold: true,
506
- margin: [0, 20, 0, 0]
507
- });
508
-
509
- const filename = `invoice_${fields.invoiceNumber?.value || 'draft'}`;
510
- this.setDocument(doc, filename);
511
- }
512
-
513
- buildLineItemsTable() {
514
- // Build from itemTable if available
515
- const items = this.fieldMap.itemTable || [];
516
-
517
- const body = [
518
- // Header
519
- [
520
- { text: 'Description', bold: true },
521
- { text: 'Qty', bold: true },
522
- { text: 'Price', bold: true }
523
- ]
524
- ];
525
-
526
- // Data rows
527
- items.forEach(item => {
528
- body.push([
529
- item.description || '',
530
- item.quantity || '',
531
- item.price || ''
532
- ]);
533
- });
534
-
535
- return {
536
- table: {
537
- headerRows: 1,
538
- widths: ['*', 60, 80],
539
- body
540
- }
541
- };
542
- }
543
- ```
544
-
545
367
  ---
546
368
 
547
369
  ## CSV Templates
@@ -729,17 +551,6 @@ getEmptyPdfDoc(fieldMap) {
729
551
 
730
552
  ## Additional Patterns
731
553
 
732
- ### Using Raw Field IDs vs Enums
733
-
734
- When orchestrator provides field IDs directly, use them as strings:
735
- ```typescript
736
- // Raw field ID (common)
737
- value: "::67e697da6ada809b961c35b5"
738
-
739
- // With enums (when imported)
740
- value: `::${Workflow_FieldIds.date_abc}`
741
- ```
742
-
743
554
  ### Clickable Links
744
555
  ```javascript
745
556
  if (fields.materialsLink?.value) {
@@ -881,144 +692,6 @@ if (isValidValue(fields.weight?.value)) {
881
692
 
882
693
  ---
883
694
 
884
- ### Distinguishing Meaningful Zero from Empty/Null
885
-
886
- **Problem:** CO2 fields in Spolia required multiple iterations to filter correctly. Some zeros are meaningful (calculated values), others are empty/null placeholders.
887
-
888
- **Solution:** Use type-specific filtering logic:
889
-
890
- ```typescript
891
- // Core pattern: Filter out truly empty values but keep meaningful zeros
892
- function shouldDisplayValue(value: unknown): boolean {
893
- // Null and undefined are always empty
894
- if (value === null || value === undefined) return false;
895
-
896
- // Empty string is empty
897
- if (value === '') return false;
898
-
899
- // NaN is empty (for numeric fields)
900
- if (typeof value === 'number' && isNaN(value)) return false;
901
-
902
- // CRITICAL: Keep 0 - it's a meaningful numeric value
903
- if (value === 0) return true;
904
-
905
- return true;
906
- }
907
-
908
- // Pattern: Filter fields for display based on value type
909
- const displayFields = fields.filter(f => {
910
- const value = activity.fields?.[f.id]?.value;
911
-
912
- // Different rules per field type
913
- switch (f.fieldType) {
914
- case 'number':
915
- // Keep 0, filter null/undefined/NaN
916
- return shouldDisplayValue(value);
917
-
918
- case 'text':
919
- // Filter null, undefined, empty string
920
- // Consider whitespace-only as empty
921
- if (!value) return false;
922
- if (typeof value === 'string' && value.trim() === '') return false;
923
- return true;
924
-
925
- case 'reference':
926
- // Reference fields must have a valid ID string
927
- // ID length varies by workflow - check for non-empty string
928
- return typeof value === 'string' && value.trim().length > 0;
929
-
930
- case 'date':
931
- // Valid ISO date or timestamp
932
- return value && !isNaN(new Date(value).getTime());
933
-
934
- case 'boolean':
935
- // Keep false and true - both are valid
936
- return typeof value === 'boolean';
937
-
938
- default:
939
- return shouldDisplayValue(value);
940
- }
941
- });
942
- ```
943
-
944
- **Field-type specific examples:**
945
-
946
- ```typescript
947
- // Numeric field: 0 is valid, undefined is empty
948
- const co2Value = fields.co2_emissions?.value; // Could be 0, could be undefined
949
- if (shouldDisplayValue(co2Value)) {
950
- // Display: "0 kgCO2e" ✓
951
- // Don't display: undefined/null/NaN ✓
952
- }
953
-
954
- // Text field: Empty string is empty, whitespace-only is empty
955
- const description = fields.description?.value;
956
- if (description && typeof description === 'string' && description.trim() !== '') {
957
- // Display: "Sample text" ✓
958
- // Don't display: "" or " " ✓
959
- }
960
-
961
- // Reference field: Check for non-empty string ID
962
- const linkedActivityId = fields.linked_activity?.value;
963
- if (typeof linkedActivityId === 'string' && linkedActivityId.trim().length > 0) {
964
- // Display: "507f1f77bcf86cd799439011" ✓
965
- // Don't display: "" or null ✓
966
- }
967
-
968
- // Boolean field: Both true and false are valid values
969
- const isActive = fields.active?.value;
970
- if (typeof isActive === 'boolean') {
971
- // Display: false ✓ (don't filter out)
972
- // Don't display: null/undefined ✓
973
- }
974
-
975
- // Function field returning formatted number: Keep meaningful zeros
976
- const calculatedCost = fields.total_cost?.value; // Example: "0 €" or "150 €"
977
- if (shouldDisplayValue(calculatedCost)) {
978
- // Display: "0 €" if it's a calculated zero ✓
979
- // But if underlying value was null, filtered function may still output placeholder
980
- // → Use isValidValue() helper (above) for extra safety
981
- }
982
- ```
983
-
984
- **Real-world scenario from Spolia CO2 case:**
985
-
986
- ```typescript
987
- // ❌ Bad: Filters out valid zeros
988
- const fields = activity.fields.filter(f => f.value); // Loses 0 values!
989
-
990
- // ❌ Also bad: Checks truthiness
991
- if (activity.fields[fieldId]?.value) { // false for 0!
992
- // Won't render CO2: 0 kgCO2e/yksikkö
993
- }
994
-
995
- // ✅ Good: Type-aware filtering
996
- if (shouldDisplayValue(activity.fields[fieldId]?.value)) {
997
- // Renders CO2: 0 kgCO2e/yksikkö ✓
998
- // Skips CO2: undefined ✓
999
- }
1000
-
1001
- // ✅ Better: Field-specific logic
1002
- const co2 = activity.fields[CO2_FIELD_ID]?.value;
1003
- if (co2 !== null && co2 !== undefined && !isNaN(Number(co2))) {
1004
- doc.content.push({
1005
- text: `CO2: ${co2} kgCO2e/yksikkö`
1006
- });
1007
- }
1008
- ```
1009
-
1010
- **Troubleshooting:**
1011
-
1012
- | Symptom | Likely Cause | Fix |
1013
- |---------|--------------|-----|
1014
- | "0 € " values missing from PDF | Using truthiness check (if value) | Use `shouldDisplayValue()` |
1015
- | Function field shows "−" or placeholder | Underlying data is null but function formatted it | Use `isValidValue()` helper |
1016
- | Some zeros showing, some not | Inconsistent filter logic per field type | Use switch statement by fieldType |
1017
- | NaN appearing in output | Not checking `isNaN()` for numbers | Add NaN check |
1018
- | Whitespace-only text showing | Not trimming string values | Use `value.trim() !== ''` for text |
1019
-
1020
- ---
1021
-
1022
695
  ## Checklist
1023
696
 
1024
697
  Before pushing template changes: