@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,542 +0,0 @@
1
- ---
2
- name: SDK-function-fields
3
- description: Complete guide to creating calculated function fields in Hailer - workflow, variable types, patterns
4
- version: 1.2.0
5
- triggers:
6
- - function field
7
- - calculated field
8
- - formula field
9
- - backlinks
10
- - phase filtering
11
- - Data metadata
12
- ---
13
-
14
- # Function Fields
15
-
16
- Complete guide for creating calculated fields that auto-update when dependencies change.
17
-
18
- ---
19
-
20
- ## Overview
21
-
22
- Function fields compute values from other fields. Examples:
23
- - Total = Quantity × Unit Price
24
- - Days Until Due = Due Date - Today
25
- - Invoice Total = Sum of line item prices (filtered by phase)
26
-
27
- ---
28
-
29
- ## Step-by-Step Workflow
30
-
31
- ### 1. Pull Latest
32
- ```bash
33
- npm run pull
34
- ```
35
-
36
- ### 2. Add Field Definition (fields.ts)
37
-
38
- ```typescript
39
- // workspace/[Workflow]_[id]/fields.ts
40
- {
41
- label: "Total Cost",
42
- type: "number",
43
- key: "total_cost",
44
- function: "@function:totalCost",
45
- functionEnabled: true,
46
- editable: false,
47
- functionVariables: {
48
- quantity: {
49
- type: "=",
50
- data: [FieldIds.quantity]
51
- },
52
- unitPrice: {
53
- type: "=",
54
- data: [FieldIds.unit_price]
55
- }
56
- }
57
- }
58
- ```
59
-
60
- ### 3. Create Function File
61
-
62
- Create `workspace/[Workflow]_[id]/functions/totalCost.ts`:
63
-
64
- ```typescript
65
- export function totalCost(dep: {
66
- quantity: number | null;
67
- unitPrice: number | null;
68
- }): number {
69
- const qty = Number(dep.quantity) || 0;
70
- const price = Number(dep.unitPrice) || 0;
71
- return qty * price;
72
- }
73
- ```
74
-
75
- ### 4. Export Function
76
-
77
- Edit `workspace/[Workflow]_[id]/functions/index.ts`:
78
-
79
- ```typescript
80
- export { totalCost } from './totalCost';
81
- ```
82
-
83
- ### 5. Test
84
-
85
- ```typescript
86
- // workspace/[Workflow]_[id]/main.test.ts
87
- import { totalCost } from './functions';
88
-
89
- describe('totalCost', () => {
90
- it('multiplies quantity by unit price', () => {
91
- expect(totalCost({ quantity: 5, unitPrice: 10 })).toBe(50);
92
- });
93
-
94
- it('handles null values', () => {
95
- expect(totalCost({ quantity: null, unitPrice: 10 })).toBe(0);
96
- });
97
- });
98
- ```
99
-
100
- Run: `npm test`
101
-
102
- ### 6. Push
103
-
104
- ```bash
105
- npm run fields-push:force
106
- ```
107
-
108
- ---
109
-
110
- ## Variable Types Reference
111
-
112
- | Type | Name | data Array | Returns |
113
- |------|------|------------|---------|
114
- | `=` | Current field | `[FieldId]` | Single value |
115
- | `>` | Forward link | `[LinkFieldId, TargetFieldId]` | Single value |
116
- | `<` | Backlink | `[WorkflowId, TargetFieldId]` | **Array** |
117
- | `?` | Static | `[WorkflowId, PhaseId]` | Phase ID string |
118
-
119
- ---
120
-
121
- ## Field Data Formats in Functions
122
-
123
- What format does each field type return when used as a dependency variable?
124
-
125
- | Field Type | Returns | Example |
126
- |------------|---------|---------|
127
- | `text`, `textarea` | `string` | `"Hello world"` |
128
- | `numeric`, `numericunit` | `number` | `42.5` |
129
- | `date`, `datetime` | `number` (ms timestamp) | `1730937600000` |
130
- | `daterange`, `datetimerange` | `{ start: number, end: number }` | `{ start: 1730937600000, end: 1731024000000 }` |
131
- | `time` | `number` (ms timestamp, includes date!) | `1765863000000` |
132
- | `timerange` | `{ start: number, end: number }` | `{ start: 1765863000000, end: 1765915200000 }` (ms timestamps, includes date!) |
133
- | `textpredefinedoptions` | `string` | `"High"` |
134
- | `users`, `teams` | `string` (ID) | `"5f8a1b2c3d4e5f6a7b8c9d0e"` |
135
- | `activitylink` | `string` (activity ID) | `"692abc123def456"` |
136
- | `country` | `string` (ISO code) | `"FI"` |
137
- | `numeric` + `modifier.checkbox` | `number` | `1` (true) or `0` (false) |
138
-
139
- **Examples:**
140
-
141
- ```javascript
142
- // Date field (milliseconds timestamp)
143
- const dueDate = dep.dueDate; // 1730937600000
144
- const isOverdue = dueDate < Date.now();
145
-
146
- // Daterange field (object with start/end)
147
- const period = dep.eventPeriod; // { start: 1730937600000, end: 1731024000000 }
148
- const startDate = period ? period.start : null;
149
- const endDate = period ? period.end : null;
150
- const durationMs = (endDate && startDate) ? (endDate - startDate) : 0;
151
- const durationDays = Math.ceil(durationMs / 86400000);
152
-
153
- // Time field (ms timestamp - includes date!)
154
- const startTime = dep.startTime; // 1765863000000
155
- // To extract just the time, use Date methods:
156
- const date = new Date(startTime);
157
- const hours = date.getUTCHours();
158
- const minutes = date.getUTCMinutes();
159
-
160
- // Timerange field (object with start/end as ms timestamps - includes date!)
161
- const workHours = dep.workingHours; // { start: 1765863000000, end: 1765915200000 }
162
- const durationMs = workHours ? (workHours.end - workHours.start) : 0;
163
- const durationMinutes = durationMs / 60000;
164
-
165
- // IMPORTANT: When to convert vs keep raw:
166
- // - Display only (text output) → use Date methods to extract time
167
- // - Write to another date/time field → keep as Unix milliseconds (no conversion!)
168
-
169
- // Checkbox field (1 or 0)
170
- const isActive = dep.isActive; // 1 or 0
171
- if (isActive === 1) { /* checked */ }
172
- ```
173
-
174
- ---
175
-
176
- ## Backlink Arrays (`<`)
177
-
178
- Backlinks return **arrays** because multiple activities can link to this one.
179
-
180
- ```javascript
181
- // functionVariables config
182
- {
183
- prices: {
184
- type: "<",
185
- data: [WorkflowIds.invoice_rows, InvoiceRows_FieldIds.total_price]
186
- }
187
- }
188
-
189
- // In function - ALWAYS default to empty array
190
- const prices = dep.prices || [];
191
- let total = 0;
192
- for (let i = 0; i < prices.length; i++) {
193
- total += Number(prices[i]) || 0;
194
- }
195
- return total;
196
- ```
197
-
198
- ---
199
-
200
- ## Activity Metadata (`"meta"`)
201
-
202
- The special `"meta"` value returns activity metadata. It works with **all variable types**:
203
-
204
- ### Current Activity Metadata (`=`)
205
-
206
- ```javascript
207
- // Get metadata of THIS activity
208
- {
209
- myMeta: {
210
- type: "=",
211
- data: ["meta"]
212
- }
213
- }
214
-
215
- // In function
216
- const myPhase = dep.myMeta ? dep.myMeta.phase : null;
217
- const myCreated = dep.myMeta ? dep.myMeta.created : 0;
218
- ```
219
-
220
- ### Forward Link Metadata (`>`)
221
-
222
- ```javascript
223
- // Get metadata of LINKED activity (this → other)
224
- {
225
- customerMeta: {
226
- type: ">",
227
- data: [FieldIds.customer_link, "meta"]
228
- }
229
- }
230
-
231
- // In function
232
- const customerPhase = dep.customerMeta ? dep.customerMeta.phaseName : 'Unknown';
233
- ```
234
-
235
- ### Backlink Metadata (`<`)
236
-
237
- ```javascript
238
- // Get metadata of activities linking TO this (others → this)
239
- {
240
- rowsMeta: {
241
- type: "<",
242
- data: [WorkflowIds.invoice_rows, "meta"]
243
- }
244
- }
245
-
246
- // In function - returns ARRAY
247
- const rows = dep.rowsMeta || [];
248
- for (let i = 0; i < rows.length; i++) {
249
- const phaseName = rows[i] ? rows[i].phaseName : 'Unknown';
250
- }
251
- ```
252
-
253
- ### Metadata Structure
254
-
255
- ```javascript
256
- {
257
- "_id": "694c9536acfa30f6df13201b", // Activity ID
258
- "name": "Invoice row name", // Activity name
259
- "process": "67dc1b7d3d2c9f6cf9a5468d", // Workflow ID
260
- "phase": "67dc1b7d3d2c9f6cf9a546c4", // Phase ID
261
- "processName": "Invoice Rows", // Workflow name
262
- "phaseName": "Active", // Phase name
263
- "created": 1766626614031, // Created timestamp (ms)
264
- "updated": 1766626614031, // Updated timestamp (ms)
265
- "completed": null, // Completed timestamp or null
266
- "sequence": 1649, // Activity sequence number
267
- "active": true // Is activity active
268
- }
269
- ```
270
-
271
- ---
272
-
273
- ## Parallel Array Guarantee
274
-
275
- **CRITICAL INSIGHT:** When you have multiple `<` (backlink) variables from the **SAME source workflow**, they are guaranteed to be:
276
- - Same length
277
- - Same order (index 0 in all arrays = same activity)
278
-
279
- **This is a core Hailer feature that enables safe parallel iteration.**
280
-
281
- ```javascript
282
- const prices = dep['Total price'] || []; // [41.76, 26.1, 153.47]
283
- const data = dep['Data'] || []; // [{...}, {...}, {...}]
284
-
285
- // Index 0 in both = same Invoice Row activity
286
- for (let i = 0; i < prices.length; i++) {
287
- const price = Number(prices[i]) || 0;
288
- const phaseName = data[i] ? data[i].phaseName : 'Unknown';
289
- // price and phaseName are from the SAME activity
290
- }
291
- ```
292
-
293
- **Arrays from DIFFERENT workflows** are independent.
294
-
295
- ---
296
-
297
- ## Static Variables (`?`)
298
-
299
- Static variables provide phase IDs for comparison in your function logic.
300
-
301
- ```javascript
302
- // Get specific phase IDs to compare against
303
- {
304
- donePhase: {
305
- type: "?",
306
- data: [WorkflowIds.sales_activities, PhaseIds.done]
307
- },
308
- archivePhase: {
309
- type: "?",
310
- data: [WorkflowIds.sales_activities, PhaseIds.archive]
311
- }
312
- }
313
-
314
- // In function - compare against metadata phase
315
- const donePhase = dep.donePhase; // "627d14339381d6077ab90ce9"
316
- const archivePhase = dep.archivePhase; // "639b49617a4413c20f15ac12"
317
-
318
- if (item.phase === donePhase || item.phase === archivePhase) {
319
- // Activity is in done or archive phase
320
- }
321
- ```
322
-
323
- **Note:** To get `process` and `phase` IDs from activities, use `"meta"` (not `?`). Static `?` is only for providing known phase IDs for comparison.
324
-
325
- ---
326
-
327
- ## Common Patterns
328
-
329
- ### Sum from Backlinks
330
-
331
- ```javascript
332
- function total(dep) {
333
- const prices = dep.prices || [];
334
- let sum = 0;
335
- for (let i = 0; i < prices.length; i++) {
336
- sum += Number(prices[i]) || 0;
337
- }
338
- return sum;
339
- }
340
- ```
341
-
342
- ### Filter by Phase (Complete Example)
343
-
344
- **functionVariables config:**
345
- ```javascript
346
- {
347
- Data: {
348
- type: "<",
349
- data: [WorkflowIds.sales_activities, "meta"]
350
- },
351
- dl: {
352
- type: "<",
353
- data: [WorkflowIds.sales_activities, FieldIds.deadline]
354
- },
355
- done: {
356
- type: "?",
357
- data: [WorkflowIds.sales_activities, PhaseIds.done]
358
- },
359
- archive: {
360
- type: "?",
361
- data: [WorkflowIds.sales_activities, PhaseIds.archive]
362
- }
363
- }
364
- ```
365
-
366
- **Function (find latest deadline from done/archived activities):**
367
- ```javascript
368
- function latestCompletedDeadline(dep) {
369
- const data = dep.Data || [];
370
- const deadlines = dep.dl || [];
371
- const donePhase = dep.done;
372
- const archivePhase = dep.archive;
373
-
374
- const arr = [];
375
- for (let i = 0; i < data.length; i++) {
376
- const item = data[i];
377
- if ((item.phase === donePhase || item.phase === archivePhase) && deadlines[i]) {
378
- arr.push(deadlines[i]);
379
- }
380
- }
381
-
382
- if (arr.length === 0) return null;
383
- return Math.max(...arr);
384
- }
385
- ```
386
-
387
- ### Sum Active Only
388
-
389
- ```javascript
390
- function sumActiveOnly(dep) {
391
- const prices = dep['Total price'] || [];
392
- const data = dep['Data'] || [];
393
- const activePhase = dep['Active'];
394
-
395
- let total = 0;
396
- for (let i = 0; i < prices.length; i++) {
397
- if (data[i] && data[i].phase === activePhase) {
398
- total += Number(prices[i]) || 0;
399
- }
400
- }
401
- return total;
402
- }
403
- ```
404
-
405
- ### Group by Phase
406
-
407
- ```javascript
408
- function groupByPhase(dep) {
409
- const prices = dep['Total price'] || [];
410
- const data = dep['Data'] || [];
411
-
412
- const result = {};
413
- for (let i = 0; i < prices.length; i++) {
414
- const phaseName = data[i] ? data[i].phaseName : 'Unknown';
415
- const price = Number(prices[i]) || 0;
416
- result[phaseName] = (result[phaseName] || 0) + price;
417
- }
418
- return JSON.stringify(result);
419
- }
420
- ```
421
-
422
- ### Exclude Multiple Phases
423
-
424
- ```javascript
425
- function sumExcludingCancelled(dep) {
426
- const prices = dep['Total price'] || [];
427
- const data = dep['Data'] || [];
428
- const cancelledPhase = dep['Cancelled'];
429
- const deletedPhase = dep['Deleted'];
430
-
431
- let total = 0;
432
- for (let i = 0; i < prices.length; i++) {
433
- const phase = data[i] ? data[i].phase : null;
434
- if (phase === cancelledPhase || phase === deletedPhase) continue;
435
- total += Number(prices[i]) || 0;
436
- }
437
- return total;
438
- }
439
- ```
440
-
441
- ### Conditional Text
442
-
443
- ```javascript
444
- function status(dep) {
445
- if (!dep.dueDate) return "No due date";
446
- if (dep.dueDate < Date.now()) return "Overdue";
447
- return "On track";
448
- }
449
- ```
450
-
451
- ### Forward Link Value
452
-
453
- ```javascript
454
- // Get value from linked activity
455
- functionVariables: {
456
- customerName: {
457
- type: ">",
458
- data: [FieldIds.customer_link, Customers_FieldIds.name]
459
- }
460
- }
461
- ```
462
-
463
- ### Emoji Based on Own Phase
464
-
465
- ```javascript
466
- // In name function: use activity's own phase, not parent workflow phase
467
- functionVariables: {
468
- myMeta: {
469
- type: "=",
470
- data: ["meta"] // Returns this activity's metadata
471
- },
472
- donePhase: {
473
- type: "?",
474
- data: [WorkflowIds.this_workflow, PhaseIds.done]
475
- }
476
- }
477
-
478
- // In name function
479
- function nameWithEmoji(dep) {
480
- const myPhase = dep.myMeta ? dep.myMeta.phase : null;
481
- const donePhase = dep.donePhase;
482
-
483
- const prefix = (myPhase === donePhase) ? "✅ " : "🔄 ";
484
- return prefix + dep.activityName;
485
- }
486
- ```
487
-
488
- **Key:** Compare against the activity's OWN phase (from `"data"` metadata), not the parent workflow's phase.
489
-
490
- ---
491
-
492
- ## Code Style
493
-
494
- **Use `const` and `let`** - NOT `var`:
495
- ```javascript
496
- // Correct
497
- const prices = dep.prices || [];
498
- let total = 0;
499
-
500
- // Wrong
501
- var prices = dep.prices || [];
502
- ```
503
-
504
- ---
505
-
506
- ## Critical Rules
507
-
508
- 1. **ES6 JavaScript only** - No TypeScript syntax in function body
509
- 2. **Never return null/undefined** - Always return valid typed value
510
- 3. **Handle null inputs** - Use `|| 0` or `|| ""` defaults
511
- 4. **Same inputs = same outputs** - No randomness, deterministic
512
- 5. **Helpers inside function** - Define helper functions in function body
513
- 6. **Use enums** - Never hardcode field/workflow IDs
514
- 7. **updateMany single-workflow rule** - `v3.activity.updateMany` targets one workflow per call. For cascading updates across multiple workflows, create separate function fields per target workflow. Don't mix activities from different workflows in one payload
515
- 8. **Double-wrapped array for generic CRUD** - When outputting a payload for the monolith `POST /api/update-activities` handler, use `[[{_id, phaseId}, ...]]` (double-wrapped). The handler spreads parsed JSON as `updateMany(...args)`, so the first arg must be the array. Single-wrapped `[{_id, phaseId}]` causes "must be an array" validation error
516
- 9. **Empty string validation** - Hailer rejects empty string `''` with "value is not allowed to be empty". Always return `'[]'` or a valid non-empty string as default from function fields
517
- 10. **Data metadata shorthand** - `type: "="` with `data: ["data"]` returns this activity's metadata object (same as `data: ["meta"]`). Similarly, `type: "<"` with `data: [workflowId, "data"]` returns array of metadata objects for linked activities
518
-
519
- ---
520
-
521
- ## Common Mistakes
522
-
523
- | Wrong | Right |
524
- |-------|-------|
525
- | `var arr = dep.arr` | `const arr = dep.arr \|\| []` |
526
- | `arr[i] * 2` | `(Number(arr[i]) \|\| 0) * 2` |
527
- | `data[i].phase` | `data[i] ? data[i].phase : null` |
528
- | Assuming arrays match across workflows | Only same-workflow arrays are parallel |
529
- | Hardcoding phase IDs | Use `?` static variables with enums |
530
-
531
- ---
532
-
533
- ## Checklist
534
-
535
- Before creating a function with backlinks:
536
-
537
- - [ ] All `<` arrays have `|| []` default
538
- - [ ] Individual array values use `Number(x) || 0`
539
- - [ ] Data metadata access has null check
540
- - [ ] Phase comparisons use `?` static variables
541
- - [ ] Using enums from workspace for all IDs
542
- - [ ] Tested with Vitest before push
@@ -1,92 +0,0 @@
1
- ---
2
- name: SDK-generate-skill
3
- description: TypeScript type generation from Hailer workspace
4
- version: 1.0.0
5
- triggers: Generate types, TypeScript generation, update types, enums
6
- ---
7
-
8
- # SDK Type Generation
9
-
10
- Generate TypeScript types from your Hailer workspace configuration.
11
-
12
- ## Overview
13
-
14
- The SDK generates TypeScript types and enums from your workspace configuration, providing type-safe access to:
15
- - Workflow IDs
16
- - Field IDs
17
- - Phase IDs
18
- - Team IDs
19
- - Group IDs
20
- - Member IDs
21
-
22
- ---
23
-
24
- ## Generated Files
25
-
26
- After `npm run pull`, these files are auto-generated:
27
-
28
- ```
29
- workspace/
30
- ├── enums.ts # Type-safe ID constants (DO NOT EDIT)
31
- ├── hailer.d.ts # TypeScript definitions (DO NOT EDIT)
32
- ```
33
-
34
- ---
35
-
36
- ## Using Enums
37
-
38
- ```typescript
39
- import {
40
- WorkflowIds,
41
- Tasks_FieldIds,
42
- Tasks_PhaseIds,
43
- TeamIds,
44
- WorkspaceMembers
45
- } from './workspace/enums';
46
-
47
- // Reference workflow
48
- const workflowId = WorkflowIds.tasks;
49
-
50
- // Reference field
51
- const fieldId = Tasks_FieldIds.due_date;
52
-
53
- // Reference phase
54
- const phaseId = Tasks_PhaseIds.in_progress;
55
- ```
56
-
57
- ---
58
-
59
- ## Regenerating Types
60
-
61
- Types are regenerated automatically when you run:
62
-
63
- ```bash
64
- npm run pull
65
- ```
66
-
67
- **When to regenerate:**
68
- - After pushing new fields/phases/workflows
69
- - After team/group changes
70
- - When enums seem out of date
71
-
72
- ---
73
-
74
- ## Important Notes
75
-
76
- 1. **Never edit enums.ts manually** - It's auto-generated
77
- 2. **Pull after push** - Get new IDs into enums after adding items
78
- 3. **Use enums everywhere** - Never hardcode IDs as strings
79
- 4. **Type safety** - TypeScript will catch invalid ID references
80
-
81
- ---
82
-
83
- ## Troubleshooting
84
-
85
- **Enum not found after adding field:**
86
- 1. Ensure you ran `npm run fields-push:force`
87
- 2. Run `npm run pull` to regenerate enums
88
- 3. Check that the field was actually created in Hailer
89
-
90
- **Type errors after changes:**
91
- 1. Run `npm run pull` to sync
92
- 2. Restart TypeScript server in your IDE