@hailer/mcp 1.1.11 → 1.1.13

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 (252) hide show
  1. package/dist/app.js +18 -5
  2. package/dist/bot/bot-config.d.ts +12 -1
  3. package/dist/bot/bot-config.js +98 -14
  4. package/dist/bot/bot-manager.d.ts +13 -3
  5. package/dist/bot/bot-manager.js +80 -25
  6. package/dist/bot/bot.d.ts +46 -0
  7. package/dist/bot/bot.js +542 -166
  8. package/dist/bot/services/message-classifier.js +17 -0
  9. package/dist/bot/services/permission-guard.d.ts +52 -0
  10. package/dist/bot/services/permission-guard.js +149 -0
  11. package/dist/bot/services/types.d.ts +5 -0
  12. package/dist/bot/services/typing-indicator.d.ts +6 -1
  13. package/dist/bot/services/typing-indicator.js +19 -3
  14. package/dist/config.d.ts +6 -1
  15. package/dist/config.js +43 -0
  16. package/dist/core.js +3 -6
  17. package/dist/mcp/UserContextCache.d.ts +5 -0
  18. package/dist/mcp/UserContextCache.js +51 -19
  19. package/dist/mcp/hailer-clients.d.ts +19 -1
  20. package/dist/mcp/hailer-clients.js +157 -20
  21. package/dist/mcp/session-store.d.ts +68 -0
  22. package/dist/mcp/session-store.js +169 -0
  23. package/dist/mcp/signal-handler.js +12 -12
  24. package/dist/mcp/tool-registry.d.ts +17 -4
  25. package/dist/mcp/tool-registry.js +37 -7
  26. package/dist/mcp/tools/activity.js +99 -7
  27. package/dist/mcp/tools/app-scaffold.js +304 -336
  28. package/dist/mcp/tools/company.d.ts +9 -0
  29. package/dist/mcp/tools/company.js +88 -0
  30. package/dist/mcp/tools/discussion.js +68 -0
  31. package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
  32. package/dist/mcp/tools/workflow-permissions.js +204 -0
  33. package/dist/mcp/tools/workflow.js +57 -18
  34. package/dist/mcp/utils/index.d.ts +2 -0
  35. package/dist/mcp/utils/index.js +12 -1
  36. package/dist/mcp/utils/role-utils.d.ts +74 -0
  37. package/dist/mcp/utils/role-utils.js +151 -0
  38. package/dist/mcp/utils/types.d.ts +43 -1
  39. package/dist/mcp/utils/types.js +14 -0
  40. package/dist/mcp/webhook-handler.d.ts +6 -0
  41. package/dist/mcp/webhook-handler.js +11 -0
  42. package/dist/mcp-server.d.ts +23 -2
  43. package/dist/mcp-server.js +639 -111
  44. package/dist/plugins/vipunen/client.d.ts +150 -0
  45. package/dist/plugins/vipunen/client.js +535 -0
  46. package/dist/plugins/vipunen/config/schema-config.json +19 -0
  47. package/dist/plugins/vipunen/config/schema-doc.json +22 -0
  48. package/dist/plugins/vipunen/index.d.ts +41 -0
  49. package/dist/plugins/vipunen/index.js +88 -0
  50. package/dist/plugins/vipunen/tools.d.ts +26 -0
  51. package/dist/plugins/vipunen/tools.js +501 -0
  52. package/package.json +2 -1
  53. package/.claude/.context-watchdog.json +0 -1
  54. package/.claude/.session-checked +0 -1
  55. package/.claude/CLAUDE.md +0 -370
  56. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  57. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  58. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  59. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  60. package/.claude/agents/agent-code-simplifier.md +0 -53
  61. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  62. package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
  63. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  64. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  65. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  66. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  67. package/.claude/agents/agent-ivan-monolith.md +0 -154
  68. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  69. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  70. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  71. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  72. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  73. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  74. package/.claude/agents/agent-permissions-handler.md +0 -208
  75. package/.claude/agents/agent-simple-writer.md +0 -48
  76. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  77. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  78. package/.claude/agents/agent-ui-designer.md +0 -100
  79. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  80. package/.claude/agents/agent-web-search.md +0 -55
  81. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  82. package/.claude/agents/agent-zara-zapier.md +0 -159
  83. package/.claude/commands/app-squad.md +0 -135
  84. package/.claude/commands/audit-squad.md +0 -158
  85. package/.claude/commands/autoplan.md +0 -563
  86. package/.claude/commands/cleanup-squad.md +0 -98
  87. package/.claude/commands/config-squad.md +0 -106
  88. package/.claude/commands/crud-squad.md +0 -87
  89. package/.claude/commands/data-squad.md +0 -97
  90. package/.claude/commands/debug-squad.md +0 -303
  91. package/.claude/commands/doc-squad.md +0 -65
  92. package/.claude/commands/handoff.md +0 -137
  93. package/.claude/commands/health.md +0 -49
  94. package/.claude/commands/help.md +0 -29
  95. package/.claude/commands/help:agents.md +0 -151
  96. package/.claude/commands/help:commands.md +0 -78
  97. package/.claude/commands/help:faq.md +0 -79
  98. package/.claude/commands/help:plugins.md +0 -50
  99. package/.claude/commands/help:skills.md +0 -93
  100. package/.claude/commands/help:tools.md +0 -75
  101. package/.claude/commands/hotfix-squad.md +0 -112
  102. package/.claude/commands/integration-squad.md +0 -82
  103. package/.claude/commands/janitor-squad.md +0 -167
  104. package/.claude/commands/learn-auto.md +0 -120
  105. package/.claude/commands/learn.md +0 -120
  106. package/.claude/commands/mcp-list.md +0 -27
  107. package/.claude/commands/onboard-squad.md +0 -140
  108. package/.claude/commands/plan-workspace.md +0 -732
  109. package/.claude/commands/prd.md +0 -130
  110. package/.claude/commands/project-status.md +0 -82
  111. package/.claude/commands/publish.md +0 -138
  112. package/.claude/commands/recap.md +0 -69
  113. package/.claude/commands/restore.md +0 -64
  114. package/.claude/commands/review-squad.md +0 -152
  115. package/.claude/commands/save.md +0 -24
  116. package/.claude/commands/stats.md +0 -19
  117. package/.claude/commands/swarm.md +0 -210
  118. package/.claude/commands/tool-builder.md +0 -39
  119. package/.claude/commands/ws-pull.md +0 -44
  120. package/.claude/hooks/_shared-memory.cjs +0 -305
  121. package/.claude/hooks/_utils.cjs +0 -108
  122. package/.claude/hooks/agent-failure-detector.cjs +0 -383
  123. package/.claude/hooks/agent-usage-logger.cjs +0 -204
  124. package/.claude/hooks/app-edit-guard.cjs +0 -494
  125. package/.claude/hooks/auto-learn.cjs +0 -304
  126. package/.claude/hooks/bash-guard.cjs +0 -272
  127. package/.claude/hooks/builder-mode-manager.cjs +0 -354
  128. package/.claude/hooks/bulk-activity-guard.cjs +0 -271
  129. package/.claude/hooks/context-watchdog.cjs +0 -230
  130. package/.claude/hooks/delegation-reminder.cjs +0 -465
  131. package/.claude/hooks/design-system-lint.cjs +0 -271
  132. package/.claude/hooks/post-scaffold-hook.cjs +0 -181
  133. package/.claude/hooks/prompt-guard.cjs +0 -354
  134. package/.claude/hooks/publish-template-guard.cjs +0 -147
  135. package/.claude/hooks/session-start.cjs +0 -35
  136. package/.claude/hooks/shared-memory-writer.cjs +0 -147
  137. package/.claude/hooks/skill-injector.cjs +0 -140
  138. package/.claude/hooks/skill-usage-logger.cjs +0 -258
  139. package/.claude/hooks/src-edit-guard.cjs +0 -240
  140. package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
  141. package/.claude/settings.json +0 -257
  142. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  143. package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
  144. package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
  145. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  146. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  147. package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
  148. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
  149. package/.claude/skills/agent-structure/SKILL.md +0 -98
  150. package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
  151. package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
  152. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  153. package/.claude/skills/frontend-design/SKILL.md +0 -254
  154. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  155. package/.claude/skills/hailer-api-client/SKILL.md +0 -518
  156. package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
  157. package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
  158. package/.claude/skills/hailer-design-system/SKILL.md +0 -235
  159. package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
  160. package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
  161. package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
  162. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  163. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  164. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  165. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  166. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  167. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  168. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  169. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  170. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  171. package/.claude/skills/integration-patterns/SKILL.md +0 -421
  172. package/.claude/skills/json-only-output/SKILL.md +0 -72
  173. package/.claude/skills/lsp-setup/SKILL.md +0 -160
  174. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  175. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  176. package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
  177. package/.claude/skills/testing-patterns/SKILL.md +0 -630
  178. package/.claude/skills/tool-builder/SKILL.md +0 -250
  179. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  180. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  181. package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
  182. package/.hailer-mcp-port +0 -1
  183. package/.mcp.json +0 -13
  184. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  185. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  186. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  187. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  188. package/.opencode/agent/agent-code-simplifier.md +0 -31
  189. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  190. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  191. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  192. package/.opencode/agent/agent-helga-workflow-config.md +0 -204
  193. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  194. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  195. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  196. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  197. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  198. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  199. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  200. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  201. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  202. package/.opencode/agent/agent-permissions-handler.md +0 -50
  203. package/.opencode/agent/agent-simple-writer.md +0 -45
  204. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  205. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  206. package/.opencode/agent/agent-ui-designer.md +0 -56
  207. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  208. package/.opencode/agent/agent-web-search.md +0 -42
  209. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  210. package/.opencode/agent/agent-zara-zapier.md +0 -53
  211. package/.opencode/commands/app-squad.md +0 -135
  212. package/.opencode/commands/audit-squad.md +0 -158
  213. package/.opencode/commands/autoplan.md +0 -563
  214. package/.opencode/commands/cleanup-squad.md +0 -98
  215. package/.opencode/commands/config-squad.md +0 -106
  216. package/.opencode/commands/crud-squad.md +0 -87
  217. package/.opencode/commands/data-squad.md +0 -97
  218. package/.opencode/commands/debug-squad.md +0 -303
  219. package/.opencode/commands/doc-squad.md +0 -65
  220. package/.opencode/commands/handoff.md +0 -137
  221. package/.opencode/commands/health.md +0 -49
  222. package/.opencode/commands/help-agents.md +0 -151
  223. package/.opencode/commands/help-commands.md +0 -32
  224. package/.opencode/commands/help-faq.md +0 -29
  225. package/.opencode/commands/help-plugins.md +0 -28
  226. package/.opencode/commands/help-skills.md +0 -7
  227. package/.opencode/commands/help-tools.md +0 -40
  228. package/.opencode/commands/help.md +0 -28
  229. package/.opencode/commands/hotfix-squad.md +0 -112
  230. package/.opencode/commands/integration-squad.md +0 -82
  231. package/.opencode/commands/janitor-squad.md +0 -167
  232. package/.opencode/commands/learn-auto.md +0 -120
  233. package/.opencode/commands/learn.md +0 -120
  234. package/.opencode/commands/mcp-list.md +0 -27
  235. package/.opencode/commands/onboard-squad.md +0 -140
  236. package/.opencode/commands/plan-workspace.md +0 -732
  237. package/.opencode/commands/prd.md +0 -131
  238. package/.opencode/commands/project-status.md +0 -82
  239. package/.opencode/commands/publish.md +0 -138
  240. package/.opencode/commands/recap.md +0 -69
  241. package/.opencode/commands/restore.md +0 -64
  242. package/.opencode/commands/review-squad.md +0 -152
  243. package/.opencode/commands/save.md +0 -24
  244. package/.opencode/commands/stats.md +0 -19
  245. package/.opencode/commands/swarm.md +0 -210
  246. package/.opencode/commands/tool-builder.md +0 -39
  247. package/.opencode/commands/ws-pull.md +0 -44
  248. package/.opencode/opencode.json +0 -21
  249. package/inbox/failures.log +0 -1
  250. package/inbox/usage.jsonl +0 -4
  251. package/scripts/postinstall.cjs +0 -64
  252. package/scripts/test-hal-tools.ts +0 -154
@@ -1,1139 +0,0 @@
1
- ---
2
- name: SDK-ws-config-skill
3
- description: Comprehensive workspace configuration - workflows, fields, phases
4
- version: 1.7.1
5
- triggers: Create workflow, add field, configure phase, field visibility, phase transitions
6
- ---
7
-
8
- # Workspace Configuration
9
-
10
- ## File Structure
11
-
12
- ```
13
- workspace/
14
- ├── workflows.ts ← Workflow registry
15
- ├── enums.ts ← AUTO-GENERATED (never edit)
16
- ├── teams.ts, groups.ts ← Access control
17
- ├── insights.ts ← SQL-like reports
18
- └── [Workflow]_[id]/
19
- ├── main.ts ← Workflow metadata
20
- ├── fields.ts ← Field definitions
21
- ├── phases.ts ← Phase configuration
22
- ├── templates.ts ← Document templates registry
23
- └── functions/*.ts ← Calculated field code
24
- ```
25
-
26
- ---
27
-
28
- ## Workflows
29
-
30
- ### workflows.ts
31
-
32
- ```typescript
33
- export const workflows: WorkflowEntry[] = [
34
- // NEW workflow - omit _id and folder
35
- {
36
- name: "Tasks",
37
- enableUnlinkedMode: false
38
- },
39
- // EXISTING workflow - has _id and folder
40
- {
41
- _id: "682ac815fba468d857d498f7",
42
- name: "Tasks",
43
- enableUnlinkedMode: false,
44
- folder: "tasks_682ac815fba468d857d498f7"
45
- }
46
- ];
47
- ```
48
-
49
- | Property | Description |
50
- |----------|-------------|
51
- | `name` | Display name |
52
- | `enableUnlinkedMode` | `true` = standalone items, `false` = must link to other activities |
53
- | `_id` | Server-generated (omit for new) |
54
- | `folder` | Auto-generated on pull (omit for new) |
55
-
56
- <critical-rules>
57
- ## CRITICAL: Workflows Require a Default Team
58
-
59
- **This is the #1 cause of "can't create activities" errors.**
60
-
61
- When you create a new workflow, it has NO default team. Without a default team:
62
- - `mcp__hailer__create_activity` fails
63
- - Apps using `hailer.activity.create()` fail
64
- - You get confusing permission/validation errors
65
-
66
- **Solution:** Always set a default team immediately after creating a workflow:
67
-
68
- 1. Create the workflow
69
- 2. In Hailer UI: Workflow Settings → Default Team → Select any team
70
- 3. Or via SDK: Add `defaultTeam: TeamIds.your_team` to workflow config
71
-
72
- **For development/testing:** Any team works. Just pick one so activity creation functions properly.
73
- </critical-rules>
74
-
75
- ---
76
-
77
- ### Workflow Creation Flow
78
-
79
- **Order matters: Workflow → Phases → Fields → Phase Links → Workflow Settings**
80
-
81
- All items get server-generated IDs. You must push each step and pull to get the IDs before referring to them.
82
-
83
- ```
84
- 1. npm run pull
85
- 2. Edit workflows.ts (add new entry without _id/folder)
86
- 3. Return ["npm run workflows-sync:force"]
87
- 4. npm run pull (generates folder + enums with workflow ID)
88
-
89
- 5. Edit phases.ts (add phases without _id, empty fields array)
90
- 6. Return ["npm run phases-push:force"]
91
- 7. npm run pull (generates phase IDs in enums)
92
-
93
- 8. Edit fields.ts (add fields without _id)
94
- 9. Return ["npm run fields-push:force"]
95
- 10. npm run pull (generates field IDs in enums)
96
-
97
- 11. Edit phases.ts:
98
- - Add field IDs to phase.fields arrays
99
- - Add possibleNextPhase arrays (phase transition links)
100
- 12. Return ["npm run phases-push:force"]
101
-
102
- 13. Edit main.ts: Set primaryDateField and primaryNumberField
103
- 14. Return ["npm run push:force"]
104
- ```
105
-
106
- ### Workflow Permissions (main.ts)
107
-
108
- Control who can access the workflow and what they can do.
109
-
110
- ```typescript
111
- // In main.ts
112
- export const workflowConfig = {
113
- _id: WorkflowIds.tasks_abc,
114
- name: "Tasks",
115
-
116
- // WHO CAN ACCESS THIS WORKFLOW
117
- members: [
118
- {
119
- id: HailerMembers.timo_ahonen_94d, // User ID
120
- permissions: ["admin"] // Full control
121
- },
122
- {
123
- id: WorkspaceTeams.sales_team_fc0, // Team ID
124
- permissions: ["any"] // Standard access
125
- }
126
- ],
127
-
128
- // DEFAULT TEAM for new activities
129
- preselectedTeam: {
130
- account: "workspace_account_id",
131
- team: WorkspaceTeams.default_team_abc
132
- },
133
- enablePreselectedTeam: true,
134
-
135
- // GUEST ACCESS
136
- allowGuests: false, // Allow external guests
137
- enableGuestEditing: false, // Can guests edit?
138
-
139
- // ... other config
140
- };
141
- ```
142
-
143
- **Permission levels:**
144
- | Level | Meaning |
145
- |-------|---------|
146
- | `"admin"` | Full control - can edit workflow settings, delete activities |
147
- | `"any"` | Standard access - can view, create, edit based on phase settings |
148
-
149
- **Member types:**
150
- - Users: `HailerMembers.user_name_id`
151
- - Teams: `WorkspaceTeams.team_name_id`
152
-
153
- ### Phase Permissions (phases.ts)
154
-
155
- Control visibility and behavior per phase.
156
-
157
- ```typescript
158
- // In phases.ts
159
- export const phases = [
160
- {
161
- _id: PhaseIds.in_progress_def,
162
- name: "In Progress",
163
-
164
- // FIELD VISIBILITY - only these fields visible in this phase
165
- fields: [
166
- FieldIds.title_abc,
167
- FieldIds.assignee_def,
168
- FieldIds.due_date_ghi
169
- ],
170
-
171
- // AUTO-FOLLOWERS - notified when activity enters this phase
172
- followers: [
173
- WorkspaceTeams.managers_team_abc, // Team
174
- "user_id_123" // Or specific user
175
- ],
176
-
177
- // PHASE TRANSITIONS - where activities can move TO from here
178
- possibleNextPhase: [
179
- PhaseIds.review_ghi,
180
- PhaseIds.done_jkl
181
- ],
182
-
183
- // TRANSITION SETTINGS (optional)
184
- possibleNextPhaseSettings: {
185
- [PhaseIds.done_jkl]: {
186
- requireComment: true // Must add comment when moving to Done
187
- }
188
- },
189
-
190
- // WEBHOOKS - trigger external systems
191
- webhooksEnabled: true,
192
- webhookUrl: "https://hooks.example.com/phase-entered"
193
- }
194
- ];
195
- ```
196
-
197
- **Key phase permissions:**
198
- | Setting | Purpose |
199
- |---------|---------|
200
- | `fields[]` | Which fields are visible/editable in this phase |
201
- | `followers[]` | Users/teams auto-notified for activities in this phase |
202
- | `possibleNextPhase[]` | Allowed phase transitions (empty = cannot move out) |
203
- | `isInitial` | New activities start here |
204
- | `isEndpoint` | Activities here are "complete" |
205
-
206
- ### Teams & Groups (workspace root)
207
-
208
- Teams and groups are defined at workspace root level (not per-workflow).
209
-
210
- **Location:** `workspace/teams.ts` and `workspace/groups.ts`
211
-
212
- ```typescript
213
- // workspace/teams.ts
214
- import { WorkspaceMembers, WorkspaceTeams } from "./enums";
215
-
216
- export const teams: HailerTeamUpdatePayload[] = [
217
- {
218
- _id: WorkspaceTeams.sales_team_abc,
219
- name: "Sales Team",
220
- description: "Sales department members",
221
- members: [
222
- WorkspaceMembers.john_doe_123,
223
- WorkspaceMembers.jane_smith_456
224
- ],
225
- public: false, // Only members can see team activities
226
- defaultView: {
227
- type: "app", // "app" | "workflow" | "phase"
228
- value: "app_id_here" // ID of default view
229
- }
230
- }
231
- ];
232
- ```
233
-
234
- **Team properties:**
235
- | Property | Purpose |
236
- |----------|---------|
237
- | `_id` | Team ID (from enums after first push) |
238
- | `name` | Display name |
239
- | `description` | Team description |
240
- | `members[]` | Array of user IDs (WorkspaceMembers enum) |
241
- | `public` | If true, visible to all workspace users |
242
- | `defaultView` | What opens when team is selected |
243
-
244
- **Groups** (less common) are collections of teams:
245
- ```typescript
246
- // workspace/groups.ts
247
- export const groups: HailerGroupUpdatePayload[] = [
248
- {
249
- _id: GroupIds.all_managers_abc,
250
- name: "All Managers",
251
- teams: [TeamIds.sales_managers, TeamIds.tech_managers],
252
- users: [WorkspaceMembers.ceo_123] // Direct user members
253
- }
254
- ];
255
- ```
256
-
257
- **Push commands:**
258
- ```bash
259
- npm run teams-push:force # Push team changes
260
- npm run groups-push:force # Push group changes
261
- ```
262
-
263
- **Where teams are used:**
264
- - Workflow `members[]` - who can access workflow
265
- - Workflow `preselectedTeam` - default team for new activities
266
- - Phase `followers[]` - auto-notify teams
267
- - App permissions - grant team access to apps
268
-
269
- ---
270
-
271
- <critical-rules>
272
- ### CRITICAL: Phase Links (possibleNextPhase)
273
-
274
- **Problem:** Without phase links, users cannot move activities between phases.
275
-
276
- Every phase needs `possibleNextPhase` array defining allowed transitions:
277
-
278
- ```typescript
279
- {
280
- _id: Tasks_PhaseIds.lead_abc,
281
- name: "Lead",
282
- isInitial: true,
283
- possibleNextPhase: [
284
- Tasks_PhaseIds.qualified_def,
285
- Tasks_PhaseIds.lost_ghi
286
- ]
287
- }
288
- ```
289
-
290
- **Without this:** Activities are stuck in their initial phase forever.
291
- </critical-rules>
292
-
293
- <critical-rules>
294
- ### CRITICAL: Primary Date and Number Fields
295
-
296
- **Set in main.ts** to enable calendar view and number aggregation:
297
-
298
- ```typescript
299
- // workspace/[Workflow]_[id]/main.ts
300
- export const workflowConfig = {
301
- // ... other config
302
- primaryDateField: Tasks_FieldIds.due_date_abc, // For calendar view
303
- primaryNumberField: Tasks_FieldIds.amount_def, // For aggregations
304
- };
305
- ```
306
-
307
- **Without primaryDateField:** Activities won't appear on the calendar.
308
- **Without primaryNumberField:** Number aggregations won't work in views.
309
- </critical-rules>
310
-
311
- ---
312
-
313
- ## Fields
314
-
315
- ### Basic Field Structure
316
-
317
- ```typescript
318
- // In fields.ts
319
- import { Tasks_FieldIds, WorkflowIds } from "../enums";
320
-
321
- export const fields: HailerFieldGeneric[] = [
322
- // NEW field - omit _id
323
- {
324
- label: "Due Date",
325
- type: "date",
326
- required: false
327
- },
328
- // EXISTING field - use enum for _id
329
- {
330
- _id: Tasks_FieldIds.due_date_abc,
331
- label: "Due Date",
332
- type: "date",
333
- required: false
334
- }
335
- ];
336
- ```
337
-
338
- ### Common Field Properties
339
-
340
- | Property | Type | Description |
341
- |----------|------|-------------|
342
- | `_id` | string | Field ID (omit for new, use enum for existing) |
343
- | `label` | string | Display name shown in UI |
344
- | `type` | string | Field type (see below) |
345
- | `key` | string | URL-safe identifier (see Key Naming below) |
346
- | `description` | string | Help text shown below field in forms |
347
- | `required` | boolean | Is field required |
348
- | `defaultTo` | boolean | Use default value |
349
- | `defaultValue` | string | Default value |
350
- | `inviteToDiscussionOnChange` | boolean | Notify discussion on change |
351
-
352
- ### Field Key Naming
353
-
354
- The `key` property is an optional URL-safe identifier for the field. If omitted, Hailer auto-generates one from the label.
355
-
356
- **Conventions:**
357
- - Use `snake_case` (lowercase with underscores)
358
- - Keep it short but descriptive
359
- - Use consistent prefixes for related fields
360
- - Avoid reserved words
361
-
362
- **Examples:**
363
- ```typescript
364
- // Good keys
365
- { label: "Customer Name", key: "customer_name" }
366
- { label: "Invoice #", key: "invoice_number" }
367
- { label: "Due Date", key: "due_date" }
368
- { label: "Total (€)", key: "total_eur" }
369
-
370
- // Prefixed for grouping
371
- { label: "Billing Address", key: "billing_address" }
372
- { label: "Billing City", key: "billing_city" }
373
- { label: "Shipping Address", key: "shipping_address" }
374
- { label: "Shipping City", key: "shipping_city" }
375
- ```
376
-
377
- **When to specify `key`:**
378
- - Always for fields used in integrations (APIs, Zapier, webhooks)
379
- - Always for fields referenced in insights or functions
380
- - Optional for internal-only fields (auto-generated is fine)
381
-
382
- ### Field Descriptions
383
-
384
- The `description` property adds help text below the field input in Hailer forms.
385
-
386
- **When to use:**
387
- - Fields with non-obvious formats ("Enter date as DD.MM.YYYY")
388
- - Fields requiring specific values ("Must be 8-digit code")
389
- - Fields with business rules ("Leave empty to use default pricing")
390
- - Fields that differ from similar-named fields in other workflows
391
-
392
- **Examples:**
393
- ```typescript
394
- {
395
- label: "Project Code",
396
- type: "text",
397
- key: "project_code",
398
- description: "8-character code from the ERP system (e.g., PRJ-12345)"
399
- }
400
-
401
- {
402
- label: "Discount %",
403
- type: "numeric",
404
- key: "discount_pct",
405
- description: "Enter 0-100. Applied to subtotal before VAT."
406
- }
407
- ```
408
-
409
- ### Field Types Reference
410
-
411
- Complete reference of all Hailer field types. Source: `hailer.d.ts` HailerFieldType.
412
-
413
- #### Quick Reference Table
414
-
415
- | Type | Use For | Value Format (CRUD) | Notes |
416
- |------|---------|---------------------|-------|
417
- | `text` | Short text (single line) | `"string"` | |
418
- | `textarea` | Long text (multi-line) | `"string"` | Plain text |
419
- | `textunit` | Text with unit suffix | `"string"` | Display unit |
420
- | `numeric` | Numbers | `123` or `45.67` | |
421
- | `numericunit` | Numbers with unit | `123` | Unit in display |
422
- | `date` | Single date | `1730937600000` (ms) | Unix timestamp |
423
- | `datetime` | Date + time | `1730937600000` (ms) | Unix timestamp |
424
- | `daterange` | Date span | `{start, end}` | Both timestamps |
425
- | `datetimerange` | Date+time span | `{start, end}` | Both timestamps |
426
- | `time` | Time only | `1765863000000` (ms) | Timestamp, but only time shown (e.g., "17:00") |
427
- | `timerange` | Time span | `{start, end}` | Timestamps, shown as "17:00 - 18:00" |
428
- | `textpredefinedoptions` | Dropdown select | `"Option"` | **STRING not array!** See section below. |
429
- | `users` | Single user | `"userId"` | STRING not array! |
430
- | `teams` | Team | `"teamId"` | Team selector |
431
- | `activitylink` | Link to activity | `"activityId"` | STRING not array! |
432
- | `linkedfrom` | Backlink (read-only) | N/A | Auto-populated |
433
- | `country` | Country picker | `"FI"` | ISO country code |
434
- | `subheader` | Section divider | N/A | UI only, no data |
435
- | `numeric` + `modifier.checkbox` | Checkbox/boolean | `1` or `0` | See Modified Fields |
436
- | `text` + `modifier.file` | File/picture upload | Object | See Modified Fields |
437
-
438
- **Note:** No multi-select types exist. For multiple values, use multiple fields or comma-separated text.
439
-
440
- ---
441
-
442
- #### Text Fields
443
-
444
- ```typescript
445
- // Short text (single line)
446
- { type: "text", label: "Title" }
447
-
448
- // Long text (multi-line, plain)
449
- { type: "textarea", label: "Description" }
450
-
451
- // Text with unit suffix (e.g., "100 pcs")
452
- { type: "textunit", label: "Quantity Text", unit: "pcs" }
453
- ```
454
-
455
- **When to use:**
456
- - `text` - Names, titles, short answers
457
- - `textarea` - Descriptions, comments, notes
458
- - `textunit` - Text that needs a unit suffix displayed
459
-
460
- ---
461
-
462
- #### Number Fields
463
-
464
- ```typescript
465
- // Plain number
466
- { type: "numeric", label: "Quantity" }
467
-
468
- // Number with display unit
469
- { type: "numericunit", label: "Price", unit: "€" }
470
- { type: "numericunit", label: "Weight", unit: "kg" }
471
- ```
472
-
473
- **CRITICAL:** Type is `numeric`, NOT `number`!
474
-
475
- **When to use:**
476
- - `numeric` - Quantities, counts, raw numbers
477
- - `numericunit` - Prices, measurements, amounts with units
478
-
479
- ---
480
-
481
- #### Date/Time Fields
482
-
483
- ```typescript
484
- // Single date (no time)
485
- { type: "date", label: "Due Date" }
486
-
487
- // Date with time
488
- { type: "datetime", label: "Meeting Start" }
489
-
490
- // Date range (start + end dates)
491
- { type: "daterange", label: "Project Period" }
492
-
493
- // Date+time range
494
- { type: "datetimerange", label: "Event" }
495
-
496
- // Time only (no date)
497
- { type: "time", label: "Start Time" }
498
-
499
- // Time range
500
- { type: "timerange", label: "Working Hours" }
501
- ```
502
-
503
- **Value format (CRUD):**
504
- - `date`, `datetime`: Unix timestamp in milliseconds → `1730937600000`
505
- - `daterange`, `datetimerange`: `{ start: 1730937600000, end: 1731024000000 }`
506
- - `time`: Unix timestamp (ms) → `1765863000000` (date arbitrary, only time displayed as "09:30")
507
- - `timerange`: `{ start: 1765863000000, end: 1765892400000 }` (shown as "09:30 - 17:30")
508
-
509
- **Time field note:** Stored as full timestamp but UI only shows time. Extract time portion when displaying:
510
- ```javascript
511
- const date = new Date(timeValue);
512
- const hours = date.getUTCHours();
513
- const minutes = date.getUTCMinutes();
514
- ```
515
-
516
- **When to use:**
517
- - `date` - Due dates, deadlines, birthdays
518
- - `datetime` - Meetings, appointments with specific time
519
- - `daterange` - Projects, events, bookings with duration
520
- - `datetimerange` - Events with specific start/end times
521
- - `time` - Daily schedules, opening hours
522
- - `timerange` - Shifts, time slots
523
-
524
- ---
525
-
526
- #### Selection Fields
527
-
528
- ```typescript
529
- // Dropdown - MUST use "textpredefinedoptions"
530
- {
531
- type: "textpredefinedoptions",
532
- label: "Priority",
533
- data: ["High", "Medium", "Low"] // String array only!
534
- }
535
- ```
536
-
537
- **CRITICAL FORMAT RULES:**
538
- - Type: `textpredefinedoptions` (NOT `dropdown`, `predefinedoptions`, `select`)
539
- - Property: `data` (NOT `options`)
540
- - Format: `["A", "B"]` (NOT `[{label: "A", value: "a"}]`)
541
- - **No multi-select exists** - use multiple fields if needed
542
-
543
- **Value format (CRUD):** `"High"` (STRING, not array!)
544
-
545
- ```typescript
546
- // ✅ CORRECT
547
- { type: "textpredefinedoptions", data: ["High", "Medium", "Low"] }
548
-
549
- // ❌ WRONG
550
- { type: "dropdown", ... } // Wrong type name
551
- { type: "predefinedoptions", ... } // Missing "text" prefix
552
- { options: ["A", "B"] } // Use data, not options
553
- { data: [{label: "A", value: "a"}] } // Use strings only
554
- ```
555
-
556
- ---
557
-
558
- #### User & Team Fields
559
-
560
- ```typescript
561
- // Single user
562
- {
563
- type: "users",
564
- label: "Assignee",
565
- inviteToDiscussionOnChange: true // Auto-invite when assigned
566
- }
567
-
568
- // Team
569
- {
570
- type: "teams",
571
- label: "Responsible Team"
572
- }
573
- ```
574
-
575
- **Value format (CRUD):**
576
- - `users`: `"5f8a1b2c3d4e5f6a7b8c9d0e"` (STRING user ID)
577
- - `teams`: `"teamId"` (STRING team ID)
578
-
579
- **Note:** No multi-select for users/teams. Use multiple fields if needed.
580
-
581
- ---
582
-
583
- #### Link Fields
584
-
585
- ```typescript
586
- // Activity link (THIS → other activity)
587
- {
588
- type: "activitylink",
589
- label: "Customer",
590
- data: [WorkflowIds.customers_abc] // Plain string array!
591
- }
592
-
593
- // Multiple workflow link (can link to different workflow types)
594
- {
595
- type: "activitylink",
596
- label: "Related Item",
597
- data: [WorkflowIds.customers, WorkflowIds.projects]
598
- }
599
-
600
- // Linked from (backlink - others → THIS) - READ ONLY
601
- {
602
- type: "linkedfrom",
603
- label: "Orders",
604
- data: [WorkflowIds.orders_def],
605
- modifier: {
606
- quickAdd: {
607
- fieldIds: [], // Fields in quick-add form
608
- targetFieldId: Orders_FieldIds.customer_link
609
- }
610
- }
611
- }
612
- ```
613
-
614
- **CRITICAL FORMAT RULES:**
615
- ```typescript
616
- // ✅ CORRECT - plain string array
617
- data: ["697b9b54477b7e412ee08b9d"]
618
- data: [WorkflowIds.customers_abc]
619
-
620
- // ❌ WRONG - objects (causes API error)
621
- data: [{ workflowId: "697b9b54477b7e412ee08b9d" }]
622
- ```
623
-
624
- **Value format (CRUD):**
625
- - `activitylink`: `"692abc123def456"` (STRING activity ID, not array!)
626
-
627
- **When to use:**
628
- - `activitylink` - Customer on order, project on task, parent-child relations
629
- - `linkedfrom` - Show related items (read-only, auto-populated from links)
630
-
631
- ---
632
-
633
- #### Modified Fields (Checkbox & File Upload)
634
-
635
- Fields can have a `modifier` object that changes their behavior:
636
-
637
- ```typescript
638
- // Checkbox field = numeric + modifier.checkbox: true
639
- {
640
- label: "Is Active",
641
- type: "numeric",
642
- modifier: {
643
- checkbox: true,
644
- file: false
645
- }
646
- }
647
-
648
- // File/Picture upload = text + modifier.file: true
649
- {
650
- label: "Attachments",
651
- type: "text",
652
- modifier: {
653
- checkbox: false,
654
- file: true
655
- }
656
- }
657
- ```
658
-
659
- **Value format (CRUD):**
660
- - Checkbox: `1` (true) or `0` (false) - stored as number
661
- - File: File reference object (handled by Hailer UI)
662
-
663
- **When to use:**
664
- - `modifier.checkbox: true` - Boolean yes/no, toggles
665
- - `modifier.file: true` - File uploads, images, attachments
666
-
667
- ---
668
-
669
- #### Other Fields
670
-
671
- ```typescript
672
- // Country picker
673
- { type: "country", label: "Country" }
674
-
675
- // UI organization (section divider)
676
- { type: "subheader", label: "Financial Details", collapsedByDefault: true }
677
- ```
678
-
679
- **Value format (CRUD):**
680
- - `country`: ISO country code → `"FI"`, `"SE"`, `"US"`
681
- - `subheader`: No data (UI only)
682
-
683
- **When to use:**
684
- - `country` - Address country, nationality
685
- - `subheader` - Group related fields visually
686
-
687
- **Note:** For contact info (email, phone, URL), use `text` fields.
688
-
689
- ---
690
-
691
- #### Calculated Function Fields
692
-
693
- ```typescript
694
- {
695
- _id: Tasks_FieldIds.total_abc,
696
- label: "Total",
697
- type: "numericunit", // Output type
698
- unit: "€",
699
- functionEnabled: true,
700
- function: "@function:total_abc", // Function reference
701
- functionVariables: { // Input dependencies
702
- quantity: {
703
- type: "=",
704
- data: [Tasks_FieldIds.quantity_def]
705
- },
706
- price: {
707
- type: "=",
708
- data: [Tasks_FieldIds.unit_price_ghi]
709
- }
710
- }
711
- }
712
- ```
713
-
714
- **See `SDK-function-fields` skill for complete function field guide.**
715
-
716
- ---
717
-
718
- #### Field Type Limitations
719
-
720
- | Limitation | Details |
721
- |------------|---------|
722
- | **Cannot change type** | Once created, field type cannot be changed via API. Must delete and recreate (loses data) or change in Hailer UI. |
723
- | **linkedfrom is read-only** | Cannot set values - auto-populated from links |
724
- | **richtext size** | Large HTML can slow down activity loading |
725
- | **attachment storage** | Files stored in Hailer, count toward workspace storage |
726
-
727
- ### Calculated Function Fields
728
-
729
- ```typescript
730
- {
731
- _id: Tasks_FieldIds.total_abc,
732
- label: "Total",
733
- type: "numericunit",
734
- unit: "€",
735
- functionEnabled: true,
736
- function: "@function:total_abc",
737
- functionVariables: {
738
- quantity: {
739
- type: "=",
740
- data: [Tasks_FieldIds.quantity_def]
741
- },
742
- price: {
743
- type: "=",
744
- data: [Tasks_FieldIds.unit_price_ghi]
745
- }
746
- }
747
- }
748
- ```
749
-
750
- See `SDK-function-field-variables` skill for variable types (=, >, <, ?).
751
-
752
- ---
753
-
754
- ## Phases
755
-
756
- ### Basic Phase Structure
757
-
758
- ```typescript
759
- // In phases.ts
760
- import { Tasks_FieldIds, Tasks_PhaseIds } from "../enums";
761
-
762
- export const phases: HailerPhaseUpdatePayload[] = [
763
- // NEW phase - omit _id
764
- {
765
- name: "Todo",
766
- color: "#57636E",
767
- fields: [],
768
- possibleNextPhase: []
769
- },
770
- // EXISTING phase - use enum for _id
771
- {
772
- _id: Tasks_PhaseIds.todo_abc,
773
- name: "Todo",
774
- color: "#57636E",
775
- fields: [
776
- Tasks_FieldIds.title_def,
777
- Tasks_FieldIds.assignee_ghi
778
- ],
779
- possibleNextPhase: [
780
- Tasks_PhaseIds.in_progress_jkl,
781
- Tasks_PhaseIds.done_mno
782
- ]
783
- }
784
- ];
785
- ```
786
-
787
- ### Phase Properties Reference
788
-
789
- | Property | Type | Description |
790
- |----------|------|-------------|
791
- | `_id` | string | Phase ID (omit for new) |
792
- | `name` | string | Display name |
793
- | `color` | string | Hex color (e.g., "#57636E") |
794
- | `description` | string | Phase description |
795
-
796
- ### Phases Can Represent Different Things
797
-
798
- **Not all phases are lifecycle stages.** Check semantics before assuming flow:
799
-
800
- - **Lifecycle phases:** Draft → Review → Active → Archived
801
- - **Category phases:** Products workflow might use phases as categories (Doors, Windows, etc.)
802
- - **Status phases:** Support tickets with Open, Waiting, Resolved
803
-
804
- Always ask the user about phase semantics when creating workflows.
805
-
806
- #### Field Visibility (IMPORTANT)
807
-
808
- **Fields are NOT automatically visible in all phases.**
809
-
810
- Each phase has a `fields` array that controls which fields are visible when an activity is in that phase. A field can be:
811
- - Visible in ALL phases (add to every phase's `fields` array)
812
- - Visible in SOME phases (add only to specific phases)
813
- - Hidden in certain phases (omit from those phases)
814
-
815
- ```typescript
816
- // Phase 1: Only basic fields visible
817
- {
818
- _id: Tasks_PhaseIds.draft_abc,
819
- name: "Draft",
820
- fields: [
821
- Tasks_FieldIds.title_def,
822
- Tasks_FieldIds.description_ghi
823
- // assignee and due_date NOT visible in draft
824
- ]
825
- }
826
-
827
- // Phase 2: More fields become visible
828
- {
829
- _id: Tasks_PhaseIds.active_jkl,
830
- name: "Active",
831
- fields: [
832
- Tasks_FieldIds.title_def,
833
- Tasks_FieldIds.description_ghi,
834
- Tasks_FieldIds.assignee_mno, // NOW visible
835
- Tasks_FieldIds.due_date_pqr // NOW visible
836
- ]
837
- }
838
- ```
839
-
840
- **When adding a new field:**
841
- 1. Push the field first (`fields-push:force`)
842
- 2. Pull to get the field ID in enums
843
- 3. Decide which phases should show this field
844
- 4. Add the field ID to those phases' `fields` arrays
845
- 5. Push phases (`phases-push:force`)
846
-
847
- #### Phase Flow Control
848
- ```typescript
849
- {
850
- isInitial: true, // Starting phase (activities created here)
851
- isEndpoint: true, // Final phase (workflow complete)
852
- possibleNextPhase: [ // Allowed transitions
853
- Tasks_PhaseIds.review_abc,
854
- Tasks_PhaseIds.done_def
855
- ],
856
- possibleNextPhaseSettings: {
857
- // Phase transition settings (optional)
858
- }
859
- }
860
- ```
861
-
862
- #### Calendar Integration
863
- ```typescript
864
- {
865
- primaryDateField: Tasks_FieldIds.due_date_abc // Show on calendar
866
- // OR
867
- primaryDateField: "updated" // Use last updated timestamp
868
- }
869
- ```
870
-
871
- #### Auto-Follow
872
- ```typescript
873
- {
874
- followers: [
875
- "user_id_abc", // User ID
876
- "team_id_def" // Team ID
877
- ]
878
- // These users/teams auto-follow activities in this phase
879
- }
880
- ```
881
-
882
- #### Webhooks
883
- ```typescript
884
- {
885
- webhooksEnabled: true,
886
- webhookUrl: "https://hooks.zapier.com/..."
887
- // Triggers when activity enters this phase
888
- }
889
- ```
890
-
891
- #### Announcements
892
- ```typescript
893
- {
894
- announcementFields: [
895
- Tasks_FieldIds.title_abc,
896
- Tasks_FieldIds.due_date_def
897
- ],
898
- announcementFieldsOrder: [
899
- Tasks_FieldIds.title_abc,
900
- Tasks_FieldIds.due_date_def
901
- ],
902
- announcementRecipients: [
903
- "team_id_abc"
904
- ]
905
- // Send notification when activity enters phase
906
- }
907
- ```
908
-
909
- ---
910
-
911
- ## Push Commands
912
-
913
- | Command | What It Does |
914
- |---------|--------------|
915
- | `npm run workflows-sync:force` | Create/update/delete workflows |
916
- | `npm run fields-push:force` | Create/update/delete fields |
917
- | `npm run phases-push:force` | Create/update/delete phases |
918
- | `npm run push:force` | Push all changes |
919
-
920
- **:force variants** may delete resources not in local files.
921
- **Non-force variants** only update, never delete.
922
-
923
- ### CRITICAL: Push/Pull Order
924
-
925
- **Push FIRST, then pull.** Running pull before push overwrites local changes.
926
-
927
- ```
928
- # CORRECT order when adding new fields locally:
929
- 1. Edit fields.ts (add new field)
930
- 2. npm run fields-push:force
931
- 3. npm run pull ← Now safe, gets generated IDs
932
-
933
- # WRONG order (loses your work):
934
- 1. Edit fields.ts
935
- 2. npm run pull ← Overwrites your changes!
936
- ```
937
-
938
- **Why?** Pull fetches server state and overwrites local files. Your unpushed edits are lost.
939
-
940
- ---
941
-
942
- ## Common Patterns
943
-
944
- ### Organizing Large Workflows with Subheaders
945
-
946
- For workflows with 15+ fields, use `subheader` fields to group related fields into collapsible sections.
947
-
948
- ```typescript
949
- // In fields.ts - organize fields into logical groups
950
- export const fields: HailerFieldGeneric[] = [
951
- // === BASIC INFO (always visible) ===
952
- { label: "Customer Name", type: "text", required: true },
953
- { label: "Contact Email", type: "text" },
954
-
955
- // === FINANCIAL SECTION (collapsible) ===
956
- {
957
- type: "subheader",
958
- label: "Financial Details",
959
- collapsedByDefault: true // Starts collapsed
960
- },
961
- { label: "Unit Price", type: "numericunit", unit: "€" },
962
- { label: "Quantity", type: "numeric" },
963
- { label: "Discount %", type: "numeric" },
964
- { label: "Total", type: "numericunit", unit: "€", functionEnabled: true, ... },
965
-
966
- // === DELIVERY SECTION (collapsible) ===
967
- {
968
- type: "subheader",
969
- label: "Delivery Information",
970
- collapsedByDefault: true
971
- },
972
- { label: "Delivery Address", type: "textarea" },
973
- { label: "Delivery Date", type: "date" },
974
- { label: "Delivery Notes", type: "textarea" },
975
-
976
- // === INTERNAL/HELPER FIELDS (hidden by default) ===
977
- {
978
- type: "subheader",
979
- label: "Internal Fields",
980
- collapsedByDefault: true
981
- },
982
- { label: "Integration ID", type: "text" },
983
- { label: "Last Sync", type: "datetime" }
984
- ];
985
- ```
986
-
987
- **When to use subheaders:**
988
- - Workflows with 15+ fields
989
- - Logical groupings exist (financial, delivery, contact, internal)
990
- - Some fields are rarely edited after initial entry
991
- - Helper/integration fields that clutter the UI
992
-
993
- **Subheader properties:**
994
- | Property | Description |
995
- |----------|-------------|
996
- | `type: "subheader"` | Required - marks as section divider |
997
- | `label` | Section title shown in UI |
998
- | `collapsedByDefault` | `true` = starts collapsed, `false` = starts expanded |
999
-
1000
- **Common section patterns:**
1001
- - "Basic Information" - core fields (often expanded)
1002
- - "Financial Details" - prices, totals, discounts
1003
- - "Delivery/Shipping" - addresses, dates
1004
- - "Contact Information" - emails, phones
1005
- - "Internal/System" - IDs, sync fields, helper fields (collapsed)
1006
-
1007
- **Note:** Subheaders have no data - they're UI-only for organization.
1008
-
1009
- ---
1010
-
1011
- ### Add Field to Existing Workflow
1012
-
1013
- ```
1014
- 1. npm run pull
1015
- 2. Edit workspace/[Workflow]_[id]/fields.ts
1016
- - Add new field (omit _id)
1017
- 3. Return ["npm run fields-push:force"]
1018
- 4. npm run pull (to get generated field ID in enums)
1019
- 5. Edit phases.ts - add new field ID to phase.fields arrays using enum
1020
- 6. Return ["npm run phases-push:force"]
1021
- ```
1022
-
1023
- ### Progressive Field Visibility
1024
-
1025
- Common pattern: reveal more fields as activity progresses through phases.
1026
-
1027
- ```typescript
1028
- // Draft: minimal fields
1029
- { name: "Draft", fields: [title, description] }
1030
-
1031
- // Review: add reviewer
1032
- { name: "Review", fields: [title, description, reviewer] }
1033
-
1034
- // Active: full visibility
1035
- { name: "Active", fields: [title, description, reviewer, assignee, due_date, priority] }
1036
-
1037
- // Done: keep all visible for reference
1038
- { name: "Done", fields: [title, description, reviewer, assignee, due_date, priority] }
1039
- ```
1040
-
1041
- ### Linear Phase Flow
1042
-
1043
- ```typescript
1044
- {
1045
- _id: Tasks_PhaseIds.todo_abc,
1046
- name: "Todo",
1047
- isInitial: true,
1048
- possibleNextPhase: [Tasks_PhaseIds.in_progress_def]
1049
- },
1050
- {
1051
- _id: Tasks_PhaseIds.in_progress_def,
1052
- name: "In Progress",
1053
- possibleNextPhase: [Tasks_PhaseIds.done_ghi]
1054
- },
1055
- {
1056
- _id: Tasks_PhaseIds.done_ghi,
1057
- name: "Done",
1058
- isEndpoint: true,
1059
- possibleNextPhase: []
1060
- }
1061
- ```
1062
-
1063
- ### Kanban-Style (Any to Any)
1064
-
1065
- ```typescript
1066
- const allPhases = [
1067
- Tasks_PhaseIds.backlog_abc,
1068
- Tasks_PhaseIds.todo_def,
1069
- Tasks_PhaseIds.doing_ghi,
1070
- Tasks_PhaseIds.done_jkl
1071
- ];
1072
-
1073
- // Each phase can move to any other
1074
- {
1075
- _id: Tasks_PhaseIds.todo_def,
1076
- name: "Todo",
1077
- possibleNextPhase: allPhases.filter(p => p !== Tasks_PhaseIds.todo_def)
1078
- }
1079
- ```
1080
-
1081
- ---
1082
-
1083
- ## Common Mistakes
1084
-
1085
- | Wrong | Right |
1086
- |-------|-------|
1087
- | Creating fields before phases | Order: Workflow → Phases → Fields |
1088
- | Adding `_id` to new items | Omit `_id` for new (server generates) |
1089
- | Referencing IDs before pull | Push → Pull → Then use new IDs from enums |
1090
- | Hardcoding IDs | Use enums from `enums.ts` |
1091
- | Editing `enums.ts` | Never edit - auto-generated |
1092
- | Running push commands directly | Return to orchestrator (hooks) |
1093
- | Pulling after local edits | Push first, then pull |
1094
- | Assuming fields auto-visible | Fields only visible if in `phase.fields` array |
1095
- | Adding field to all phases | Ask which phases need this field visible |
1096
- | Forgetting to add field to phases | New fields need to be in `phase.fields` |
1097
- | Changing field type via API | Field types CANNOT be changed - see below |
1098
- | Including `key` on existing phases | `key` only for NEW phases - push fails on existing |
1099
- | Using `predefinedoptions` or `dropdown` | Use `textpredefinedoptions` (with "text" prefix) |
1100
- | Using `options: [...]` for dropdowns | Use `data: [...]` (not options) |
1101
- | `data: [{workflowId: "..."}]` for links | Use `data: ["workflowId"]` (plain string array) |
1102
- | Forgetting `possibleNextPhase` | Activities stuck without phase transition links |
1103
- | Missing `primaryDateField` | Activities won't show on calendar |
1104
-
1105
- ---
1106
-
1107
- ## CRITICAL: Field Types Cannot Be Changed via API
1108
-
1109
- **Problem:** Once a field is created, you cannot change its `type` via the SDK push commands.
1110
-
1111
- **Example:** Cannot change `textarea` → `activitylink` via `npm run fields-push`
1112
-
1113
- **Workarounds:**
1114
- 1. Create a **new field** with the correct type (deprecate old one)
1115
- 2. Change field type manually in **Hailer UI** (Settings → Workflow → Edit field)
1116
- 3. Delete and recreate the field (loses existing data)
1117
-
1118
- **What CAN be changed via API:**
1119
- - `label`, `description`, `required`
1120
- - `data` (options for predefinedoptions, linked workflows for activitylink)
1121
- - Field order in workflow
1122
-
1123
- ---
1124
-
1125
- ## Checklist
1126
-
1127
- Before pushing workflow changes:
1128
-
1129
- - [ ] Used enums for all existing IDs
1130
- - [ ] Omitted `_id` for new items
1131
- - [ ] **Asked user which phases should show new fields**
1132
- - [ ] New fields added ONLY to relevant `phase.fields` arrays
1133
- - [ ] Phase transitions make sense (`possibleNextPhase`)
1134
- - [ ] Required fields have `required: true`
1135
- - [ ] Link fields have correct workflow IDs in `data`
1136
- - [ ] Using `:force` variant for commands that need it
1137
-
1138
- When adding a new field, ALWAYS ask:
1139
- > "Which phases should this field be visible in? All phases or specific ones?"