@hailer/mcp 1.1.12 → 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.
- package/CHANGELOG.md +0 -7
- package/{.claude → dist}/CLAUDE.md +2 -2
- package/dist/app.js +18 -5
- package/dist/bot/bot-config.d.ts +10 -1
- package/dist/bot/bot-config.js +64 -3
- package/dist/bot/bot-manager.d.ts +2 -0
- package/dist/bot/bot-manager.js +9 -2
- package/dist/bot/bot.d.ts +33 -0
- package/dist/bot/bot.js +461 -160
- package/dist/bot/services/message-classifier.js +17 -0
- package/dist/bot/services/permission-guard.d.ts +52 -0
- package/dist/bot/services/permission-guard.js +149 -0
- package/dist/bot/services/types.d.ts +5 -0
- package/dist/bot/services/typing-indicator.d.ts +6 -1
- package/dist/bot/services/typing-indicator.js +19 -3
- package/dist/cli.js +0 -0
- package/dist/config.d.ts +6 -1
- package/dist/config.js +43 -0
- package/dist/core.js +3 -6
- package/dist/lib/discussion-lock.d.ts +42 -0
- package/dist/lib/discussion-lock.js +110 -0
- package/dist/mcp/UserContextCache.d.ts +5 -0
- package/dist/mcp/UserContextCache.js +51 -19
- package/dist/mcp/hailer-clients.d.ts +19 -1
- package/dist/mcp/hailer-clients.js +158 -24
- package/dist/mcp/session-store.d.ts +68 -0
- package/dist/mcp/session-store.js +169 -0
- package/dist/mcp/signal-handler.js +2 -0
- package/dist/mcp/tool-registry.d.ts +17 -4
- package/dist/mcp/tool-registry.js +37 -7
- package/dist/mcp/tools/activity.js +99 -7
- package/dist/mcp/tools/app-scaffold.js +304 -336
- package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
- package/dist/mcp/tools/bot-config/constants.js +94 -0
- package/dist/mcp/tools/bot-config/core.d.ts +253 -0
- package/dist/mcp/tools/bot-config/core.js +2456 -0
- package/dist/mcp/tools/bot-config/index.d.ts +10 -0
- package/dist/mcp/tools/bot-config/index.js +59 -0
- package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
- package/dist/mcp/tools/bot-config/tools.js +15 -0
- package/dist/mcp/tools/bot-config/types.d.ts +50 -0
- package/dist/mcp/tools/bot-config/types.js +6 -0
- package/dist/mcp/tools/bug-fixer-tools.d.ts +45 -0
- package/dist/mcp/tools/bug-fixer-tools.js +1096 -0
- package/dist/mcp/tools/company.d.ts +9 -0
- package/dist/mcp/tools/company.js +88 -0
- package/dist/mcp/tools/discussion.js +68 -0
- package/dist/mcp/tools/document.d.ts +11 -0
- package/dist/mcp/tools/document.js +741 -0
- package/dist/mcp/tools/investigate.d.ts +9 -0
- package/dist/mcp/tools/investigate.js +254 -0
- package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
- package/dist/mcp/tools/workflow-permissions.js +204 -0
- package/dist/mcp/tools/workflow.js +57 -18
- package/dist/mcp/utils/index.d.ts +2 -0
- package/dist/mcp/utils/index.js +12 -1
- package/dist/mcp/utils/role-utils.d.ts +74 -0
- package/dist/mcp/utils/role-utils.js +151 -0
- package/dist/mcp/utils/types.d.ts +43 -1
- package/dist/mcp/utils/types.js +14 -0
- package/dist/mcp/webhook-handler.d.ts +4 -0
- package/dist/mcp/webhook-handler.js +8 -0
- package/dist/mcp-server.d.ts +23 -2
- package/dist/mcp-server.js +639 -127
- package/dist/plugins/vipunen/client.d.ts +150 -0
- package/dist/plugins/vipunen/client.js +535 -0
- package/dist/plugins/vipunen/config/schema-config.json +19 -0
- package/dist/plugins/vipunen/config/schema-doc.json +22 -0
- package/dist/plugins/vipunen/index.d.ts +41 -0
- package/dist/plugins/vipunen/index.js +88 -0
- package/dist/plugins/vipunen/tools.d.ts +26 -0
- package/dist/plugins/vipunen/tools.js +501 -0
- package/dist/stdio-server.d.ts +14 -0
- package/dist/stdio-server.js +101 -0
- package/package.json +2 -1
- package/.claude/agents/agent-ada-skill-builder.md +0 -94
- package/.claude/agents/agent-alejandro-function-fields.md +0 -342
- package/.claude/agents/agent-bjorn-config-audit.md +0 -103
- package/.claude/agents/agent-builder-agent-creator.md +0 -130
- package/.claude/agents/agent-code-simplifier.md +0 -53
- package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
- package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
- package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
- package/.claude/agents/agent-helga-workflow-config.md +0 -204
- package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
- package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
- package/.claude/agents/agent-ivan-monolith.md +0 -154
- package/.claude/agents/agent-kenji-data-reader.md +0 -86
- package/.claude/agents/agent-lars-code-inspector.md +0 -102
- package/.claude/agents/agent-marco-mockup-builder.md +0 -110
- package/.claude/agents/agent-marcus-api-documenter.md +0 -323
- package/.claude/agents/agent-marketplace-publisher.md +0 -280
- package/.claude/agents/agent-marketplace-reviewer.md +0 -309
- package/.claude/agents/agent-permissions-handler.md +0 -208
- package/.claude/agents/agent-simple-writer.md +0 -48
- package/.claude/agents/agent-svetlana-code-review.md +0 -171
- package/.claude/agents/agent-tanya-test-runner.md +0 -333
- package/.claude/agents/agent-ui-designer.md +0 -100
- package/.claude/agents/agent-viktor-sql-insights.md +0 -212
- package/.claude/agents/agent-web-search.md +0 -55
- package/.claude/agents/agent-yevgeni-discussions.md +0 -45
- package/.claude/agents/agent-zara-zapier.md +0 -159
- package/.claude/commands/app-squad.md +0 -135
- package/.claude/commands/audit-squad.md +0 -158
- package/.claude/commands/autoplan.md +0 -563
- package/.claude/commands/cleanup-squad.md +0 -98
- package/.claude/commands/config-squad.md +0 -106
- package/.claude/commands/crud-squad.md +0 -87
- package/.claude/commands/data-squad.md +0 -97
- package/.claude/commands/debug-squad.md +0 -303
- package/.claude/commands/doc-squad.md +0 -65
- package/.claude/commands/handoff.md +0 -137
- package/.claude/commands/health.md +0 -49
- package/.claude/commands/help.md +0 -29
- package/.claude/commands/help:agents.md +0 -151
- package/.claude/commands/help:commands.md +0 -78
- package/.claude/commands/help:faq.md +0 -79
- package/.claude/commands/help:plugins.md +0 -50
- package/.claude/commands/help:skills.md +0 -93
- package/.claude/commands/help:tools.md +0 -75
- package/.claude/commands/hotfix-squad.md +0 -112
- package/.claude/commands/integration-squad.md +0 -82
- package/.claude/commands/janitor-squad.md +0 -167
- package/.claude/commands/learn-auto.md +0 -120
- package/.claude/commands/learn.md +0 -120
- package/.claude/commands/mcp-list.md +0 -27
- package/.claude/commands/onboard-squad.md +0 -140
- package/.claude/commands/plan-workspace.md +0 -732
- package/.claude/commands/prd.md +0 -130
- package/.claude/commands/project-status.md +0 -82
- package/.claude/commands/publish.md +0 -138
- package/.claude/commands/recap.md +0 -69
- package/.claude/commands/restore.md +0 -64
- package/.claude/commands/review-squad.md +0 -152
- package/.claude/commands/save.md +0 -24
- package/.claude/commands/stats.md +0 -19
- package/.claude/commands/swarm.md +0 -210
- package/.claude/commands/tool-builder.md +0 -39
- package/.claude/commands/ws-pull.md +0 -44
- package/.claude/hooks/_shared-memory.cjs +0 -305
- package/.claude/hooks/_utils.cjs +0 -108
- package/.claude/hooks/agent-failure-detector.cjs +0 -383
- package/.claude/hooks/agent-usage-logger.cjs +0 -204
- package/.claude/hooks/app-edit-guard.cjs +0 -494
- package/.claude/hooks/auto-learn.cjs +0 -304
- package/.claude/hooks/bash-guard.cjs +0 -272
- package/.claude/hooks/builder-mode-manager.cjs +0 -354
- package/.claude/hooks/bulk-activity-guard.cjs +0 -271
- package/.claude/hooks/context-watchdog.cjs +0 -230
- package/.claude/hooks/delegation-reminder.cjs +0 -465
- package/.claude/hooks/design-system-lint.cjs +0 -271
- package/.claude/hooks/post-scaffold-hook.cjs +0 -181
- package/.claude/hooks/prompt-guard.cjs +0 -354
- package/.claude/hooks/publish-template-guard.cjs +0 -147
- package/.claude/hooks/session-start.cjs +0 -35
- package/.claude/hooks/shared-memory-writer.cjs +0 -147
- package/.claude/hooks/skill-injector.cjs +0 -140
- package/.claude/hooks/skill-usage-logger.cjs +0 -258
- package/.claude/hooks/src-edit-guard.cjs +0 -240
- package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
- package/.claude/settings.json +0 -257
- package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
- package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
- package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
- package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
- package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
- package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
- package/.claude/skills/agent-structure/SKILL.md +0 -98
- package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
- package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
- package/.claude/skills/delegation-routing/SKILL.md +0 -202
- package/.claude/skills/frontend-design/SKILL.md +0 -254
- package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
- package/.claude/skills/hailer-api-client/SKILL.md +0 -518
- package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
- package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
- package/.claude/skills/hailer-design-system/SKILL.md +0 -235
- package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
- package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
- package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
- package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
- package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
- package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
- package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
- package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
- package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
- package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
- package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
- package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
- package/.claude/skills/integration-patterns/SKILL.md +0 -421
- package/.claude/skills/json-only-output/SKILL.md +0 -72
- package/.claude/skills/lsp-setup/SKILL.md +0 -160
- package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
- package/.claude/skills/optional-parameters/SKILL.md +0 -72
- package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
- package/.claude/skills/testing-patterns/SKILL.md +0 -630
- package/.claude/skills/tool-builder/SKILL.md +0 -250
- package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
- package/.claude/skills/tool-response-verification/SKILL.md +0 -92
- package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
- package/.mcp.json +0 -13
- package/.opencode/agent/agent-ada-skill-builder.md +0 -35
- package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
- package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
- package/.opencode/agent/agent-builder-agent-creator.md +0 -39
- package/.opencode/agent/agent-code-simplifier.md +0 -31
- package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
- package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
- package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
- package/.opencode/agent/agent-helga-workflow-config.md +0 -203
- package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
- package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
- package/.opencode/agent/agent-ivan-monolith.md +0 -46
- package/.opencode/agent/agent-kenji-data-reader.md +0 -53
- package/.opencode/agent/agent-lars-code-inspector.md +0 -28
- package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
- package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
- package/.opencode/agent/agent-marketplace-publisher.md +0 -44
- package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
- package/.opencode/agent/agent-permissions-handler.md +0 -50
- package/.opencode/agent/agent-simple-writer.md +0 -45
- package/.opencode/agent/agent-svetlana-code-review.md +0 -39
- package/.opencode/agent/agent-tanya-test-runner.md +0 -57
- package/.opencode/agent/agent-ui-designer.md +0 -56
- package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
- package/.opencode/agent/agent-web-search.md +0 -42
- package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
- package/.opencode/agent/agent-zara-zapier.md +0 -53
- package/.opencode/commands/app-squad.md +0 -135
- package/.opencode/commands/audit-squad.md +0 -158
- package/.opencode/commands/autoplan.md +0 -563
- package/.opencode/commands/cleanup-squad.md +0 -98
- package/.opencode/commands/config-squad.md +0 -106
- package/.opencode/commands/crud-squad.md +0 -87
- package/.opencode/commands/data-squad.md +0 -97
- package/.opencode/commands/debug-squad.md +0 -303
- package/.opencode/commands/doc-squad.md +0 -65
- package/.opencode/commands/handoff.md +0 -137
- package/.opencode/commands/health.md +0 -49
- package/.opencode/commands/help-agents.md +0 -151
- package/.opencode/commands/help-commands.md +0 -32
- package/.opencode/commands/help-faq.md +0 -29
- package/.opencode/commands/help-plugins.md +0 -28
- package/.opencode/commands/help-skills.md +0 -7
- package/.opencode/commands/help-tools.md +0 -40
- package/.opencode/commands/help.md +0 -28
- package/.opencode/commands/hotfix-squad.md +0 -112
- package/.opencode/commands/integration-squad.md +0 -82
- package/.opencode/commands/janitor-squad.md +0 -167
- package/.opencode/commands/learn-auto.md +0 -120
- package/.opencode/commands/learn.md +0 -120
- package/.opencode/commands/mcp-list.md +0 -27
- package/.opencode/commands/onboard-squad.md +0 -140
- package/.opencode/commands/plan-workspace.md +0 -732
- package/.opencode/commands/prd.md +0 -131
- package/.opencode/commands/project-status.md +0 -82
- package/.opencode/commands/publish.md +0 -138
- package/.opencode/commands/recap.md +0 -69
- package/.opencode/commands/restore.md +0 -64
- package/.opencode/commands/review-squad.md +0 -152
- package/.opencode/commands/save.md +0 -24
- package/.opencode/commands/stats.md +0 -19
- package/.opencode/commands/swarm.md +0 -210
- package/.opencode/commands/tool-builder.md +0 -39
- package/.opencode/commands/ws-pull.md +0 -44
- package/.opencode/opencode.json +0 -28
- package/SESSION-HANDOFF.md +0 -68
- package/inbox/2026-03-04-bot-config-patterns.md +0 -24
- package/scripts/postinstall.cjs +0 -64
- 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
|