@hailer/mcp 1.1.17-beta.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +94 -135
- package/.claude/skills/create-and-publish-app/SKILL.md +127 -0
- package/.claude/skills/hailer-app-builder/SKILL.md +47 -0
- package/.claude/skills/publish-hailer-app/SKILL.md +35 -4
- package/.claude/skills/sdk-function-fields/SKILL.md +431 -287
- package/dist/bot/bot-manager.d.ts.map +1 -1
- package/dist/bot/bot-manager.js +2 -0
- package/dist/bot/bot-manager.js.map +1 -1
- package/dist/bot/bot.d.ts +2 -1
- package/dist/bot/bot.d.ts.map +1 -1
- package/dist/bot/bot.js +109 -41
- package/dist/bot/bot.js.map +1 -1
- package/dist/bot/services/message-classifier.d.ts.map +1 -1
- package/dist/bot/services/message-classifier.js +6 -0
- package/dist/bot/services/message-classifier.js.map +1 -1
- package/dist/bot/services/signal-router.d.ts.map +1 -1
- package/dist/bot/services/signal-router.js +1 -0
- package/dist/bot/services/signal-router.js.map +1 -1
- package/dist/bot/services/system-prompt.d.ts +4 -0
- package/dist/bot/services/system-prompt.d.ts.map +1 -1
- package/dist/bot/services/system-prompt.js +41 -12
- package/dist/bot/services/system-prompt.js.map +1 -1
- package/dist/bot/services/types.d.ts +7 -31
- package/dist/bot/services/types.d.ts.map +1 -1
- package/dist/bot/services/workspace-refresh.js.map +1 -1
- package/dist/bot/workspace-overview.d.ts.map +1 -1
- package/dist/bot/workspace-overview.js +4 -1
- package/dist/bot/workspace-overview.js.map +1 -1
- package/dist/bot-config/context.js.map +1 -1
- package/dist/bot-config/loader.d.ts.map +1 -1
- package/dist/bot-config/loader.js +1 -0
- package/dist/bot-config/loader.js.map +1 -1
- package/dist/bot-config/types.d.ts +2 -0
- package/dist/bot-config/types.d.ts.map +1 -1
- package/dist/mcp/UserContextCache.d.ts.map +1 -1
- package/dist/mcp/UserContextCache.js +8 -16
- package/dist/mcp/UserContextCache.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts +3 -2
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +14 -9
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/activity.d.ts.map +1 -1
- package/dist/mcp/tools/activity.js +39 -94
- package/dist/mcp/tools/activity.js.map +1 -1
- package/dist/mcp/tools/app-scaffold.d.ts.map +1 -1
- package/dist/mcp/tools/app-scaffold.js +300 -575
- package/dist/mcp/tools/app-scaffold.js.map +1 -1
- package/dist/mcp/tools/date.d.ts +5 -0
- package/dist/mcp/tools/date.d.ts.map +1 -0
- package/dist/mcp/tools/date.js +23 -0
- package/dist/mcp/tools/date.js.map +1 -0
- package/dist/mcp/tools/discussion.d.ts.map +1 -1
- package/dist/mcp/tools/discussion.js +17 -9
- package/dist/mcp/tools/discussion.js.map +1 -1
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +2 -0
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/insight.d.ts.map +1 -1
- package/dist/mcp/tools/insight.js +13 -19
- package/dist/mcp/tools/insight.js.map +1 -1
- package/dist/mcp/tools/workflow.d.ts +1 -0
- package/dist/mcp/tools/workflow.d.ts.map +1 -1
- package/dist/mcp/tools/workflow.js +293 -46
- package/dist/mcp/tools/workflow.js.map +1 -1
- package/dist/mcp/utils/data-transformers.d.ts +47 -10
- package/dist/mcp/utils/data-transformers.d.ts.map +1 -1
- package/dist/mcp/utils/data-transformers.js +12 -9
- package/dist/mcp/utils/data-transformers.js.map +1 -1
- package/dist/mcp/utils/types.d.ts +2 -0
- package/dist/mcp/utils/types.d.ts.map +1 -1
- package/dist/mcp/utils/types.js.map +1 -1
- package/dist/mcp/webhook-handler.d.ts.map +1 -1
- package/dist/mcp/webhook-handler.js +4 -1
- package/dist/mcp/webhook-handler.js.map +1 -1
- package/dist/mcp/workspace-cache.d.ts +8 -2
- package/dist/mcp/workspace-cache.d.ts.map +1 -1
- package/dist/mcp/workspace-cache.js +12 -8
- package/dist/mcp/workspace-cache.js.map +1 -1
- package/dist/plugins/vipunen/tools.d.ts +1 -0
- package/dist/plugins/vipunen/tools.d.ts.map +1 -1
- package/dist/plugins/vipunen/tools.js.map +1 -1
- package/package.json +1 -1
package/.claude/CLAUDE.md
CHANGED
|
@@ -1,167 +1,126 @@
|
|
|
1
|
-
# Hailer MCP
|
|
1
|
+
# Hailer SDK + MCP Project
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## The One Rule
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
2. **Skill loads → sub-agent only.** Never load skills (Skill tool) in main context. Tell the sub-agent which skills to load.
|
|
7
|
-
3. **Workspace edits → spawn sonnet sub-agent.** Fields, functions, phases — always in a sub-agent with skill names + IDs front-loaded.
|
|
8
|
-
4. **MCP tools are fine in main context.** Tool results are small. Use them for discovery (IDs, schemas, data).
|
|
9
|
-
5. **Load skills before editing.** `sdk-function-fields` + `sdk-ws-config-skill` for function fields. Skills have critical steps (omit `_id` for new fields, push → pull → phases).
|
|
10
|
-
6. **New fields: omit `_id`.** The server assigns it. Push → pull → add to phases → push phases.
|
|
11
|
-
7. **Function fields: `fields-push:force`** not `fields-push`. Non-force skips `functionVariables` diffs.
|
|
12
|
-
8. **After pull: verify enum imports.** Identical hex suffixes across workflows can resolve to wrong enum. Fix manually.
|
|
13
|
-
9. **Pattern:** MCP discovery (main) → spawn sub-agent with IDs + skill names + task → sub-agent does all file work → returns summary.
|
|
5
|
+
**If it can be done locally, do it locally. MCP tools are ONLY for things that require a server call.**
|
|
14
6
|
|
|
15
|
-
|
|
7
|
+
This project has `workspace/` files managed by `@hailer/sdk`. These files ARE the source of truth for all workflow configuration. The MCP server provides tools for runtime operations that require talking to Hailer's API.
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
## What Goes Where
|
|
18
10
|
|
|
19
|
-
|
|
11
|
+
| Need | Do this | NEVER this |
|
|
12
|
+
|------|---------|------------|
|
|
13
|
+
| **Find workflow/field/phase IDs** | Read `workspace/enums.ts` | ~~`list_workflows_minimal`~~, ~~`get_workflow_schema`~~, ~~`list_workflow_phases`~~ |
|
|
14
|
+
| **See field types, labels, options** | Read `workspace/<Name>_<id>/fields.ts` | ~~`get_workflow_schema`~~ |
|
|
15
|
+
| **See phases** | Read `workspace/<Name>_<id>/phases.ts` | ~~`list_workflow_phases`~~ |
|
|
16
|
+
| **See all workflows** | Read `workspace/workflows.ts` | ~~`list_workflows`~~ |
|
|
17
|
+
| **Create/modify fields** | Edit `fields.ts` → `npm run fields-push:force` | ~~`update_workflow_field`~~ |
|
|
18
|
+
| **Create/modify phases** | Edit `phases.ts` → `npm run phases-push:force` | ~~`update_workflow_phase`~~ |
|
|
19
|
+
| **Create/modify workflows** | Edit `workflows.ts` → `npm run workflows-sync:force` | ~~`install_workflow`~~ |
|
|
20
|
+
| **Create/modify teams** | Edit `teams.ts` → `npm run teams-push:force` | — |
|
|
21
|
+
| **Create/modify groups** | Edit `groups.ts` → `npm run groups-push:force` | — |
|
|
22
|
+
| **Create activities** | MCP `create_activity` | — |
|
|
23
|
+
| **List/read activities** | MCP `list_activities`, `show_activity_by_id` | — |
|
|
24
|
+
| **Update activities** | MCP `update_activity` | — |
|
|
25
|
+
| **Query data** | MCP `preview_insight`, `create_insight` | — |
|
|
26
|
+
| **Discussions** | MCP discussion tools | — |
|
|
27
|
+
| **Activity counts** | MCP `core_init` (once per session) | — |
|
|
28
|
+
| **Scaffold app** | MCP `scaffold_hailer_app` | — |
|
|
29
|
+
| **Publish app** | MCP `publish_hailer_app` | — |
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
npm init @hailer/sdk # Scaffold project with workspace/ config
|
|
23
|
-
npm run pull # Pull latest workflow schemas from Hailer
|
|
24
|
-
npm run generate # Generate TypeScript types
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## How to Work
|
|
31
|
+
**If you're about to call an MCP tool, ask yourself: "Is this data in workspace/ files?" If yes, read the file instead.**
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
## How to Read workspace/ Files
|
|
30
34
|
|
|
31
|
-
**
|
|
32
|
-
- **You (Opus):** Orchestrate, synthesize results, make decisions. Do NOT write large code blocks yourself.
|
|
33
|
-
- **Sub-agents (Sonnet):** Write code, build features, complex edits. Use `model: "sonnet"`.
|
|
34
|
-
- **Sub-agents (Haiku):** Read files, search code, data lookups, reviews. Use `model: "haiku"`.
|
|
35
|
-
- **Rule:** If a task takes more than ~20 lines of code, delegate to a sonnet sub-agent.
|
|
35
|
+
**Never read workspace/ files in main context** — they're large and fill context permanently.
|
|
36
36
|
|
|
37
|
-
**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- Background long tasks with `run_in_background: true`
|
|
37
|
+
1. Spawn a **haiku sub-agent** to read the files
|
|
38
|
+
2. Have it extract what you need (IDs, field types, phase names)
|
|
39
|
+
3. It returns a short summary
|
|
40
|
+
4. Use that summary for MCP runtime calls
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
```
|
|
43
|
+
Pattern: haiku reads workspace/ → you get IDs → MCP create_activity/list_activities
|
|
44
|
+
```
|
|
44
45
|
|
|
45
|
-
##
|
|
46
|
+
## Sub-Agent Rules
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
- **Haiku:** Read files, search code, data lookups, reviews
|
|
49
|
+
- **Sonnet:** Write code, build features, complex edits
|
|
50
|
+
- **You (Opus):** Orchestrate, synthesize results, make decisions
|
|
51
|
+
- **Skills:** Load in sub-agents only, never in main context
|
|
52
|
+
- If a task takes more than ~20 lines of code, delegate to sonnet
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
| Skill | Use when |
|
|
51
|
-
|-------|----------|
|
|
52
|
-
| `sdk-ws-config-skill` | Workflows, fields, phases, teams, groups, new project setup |
|
|
53
|
-
| `sdk-function-fields` | Calculated fields, nameFunction |
|
|
54
|
-
| `sdk-activity-patterns` | Creating/updating activities |
|
|
55
|
-
| `sdk-insight-queries` | SQL-like insight queries, cross-workflow JOINs |
|
|
56
|
-
| `sdk-document-templates` | PDF/CSV document templates |
|
|
57
|
-
| `hailer-permissions-system` | Workflow permissions |
|
|
58
|
-
|
|
59
|
-
### App Development
|
|
60
|
-
| Skill | Use when |
|
|
61
|
-
|-------|----------|
|
|
62
|
-
| `hailer-app-builder` | Building Hailer apps (React/Chakra) |
|
|
63
|
-
| `hailer-design-system` | Theme, colors, icons, layout, spacing, responsive design |
|
|
64
|
-
| `hailer-apps-pictures` | Images/photos in apps |
|
|
65
|
-
| `publish-hailer-app` | Publishing to production |
|
|
66
|
-
|
|
67
|
-
### Integrations
|
|
68
|
-
| Skill | Use when |
|
|
69
|
-
|-------|----------|
|
|
70
|
-
| `hailer-monolith-automations` | Webhook handlers, scheduled jobs, phase cascade bots |
|
|
71
|
-
| `zapier-hailer-patterns` | Zapier integrations |
|
|
72
|
-
| `integration-patterns` | General integration patterns |
|
|
73
|
-
| `hailer-api-client` | HailerApiClient for backend |
|
|
74
|
-
|
|
75
|
-
### Code Quality
|
|
76
|
-
| Skill | Use when |
|
|
77
|
-
|-------|----------|
|
|
78
|
-
| `testing-patterns` | Vitest/playwright tests |
|
|
79
|
-
| `api-documentation-patterns` | API endpoint docs |
|
|
80
|
-
| `lsp-setup` | LSP code inspection |
|
|
81
|
-
| `tool-builder` | Building new MCP tools |
|
|
82
|
-
|
|
83
|
-
## Local-First Data
|
|
84
|
-
|
|
85
|
-
Check workspace/ BEFORE making API calls.
|
|
54
|
+
## workspace/ Structure
|
|
86
55
|
|
|
87
56
|
```
|
|
88
57
|
workspace/
|
|
89
|
-
├──
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
58
|
+
├── enums.ts # ALL IDs — WorkflowIds, FieldIds, PhaseIds, etc.
|
|
59
|
+
├── workflows.ts # Workflow registry
|
|
60
|
+
├── teams.ts # Team definitions
|
|
61
|
+
├── groups.ts # Group definitions
|
|
62
|
+
├── insights.ts # Insight definitions
|
|
63
|
+
└── <WorkflowName>_<id>/
|
|
64
|
+
├── fields.ts # Field definitions (type, label, key, options, required)
|
|
65
|
+
├── phases.ts # Phase definitions (name, key, isInitial, isEndpoint)
|
|
66
|
+
├── main.ts # Workflow config
|
|
67
|
+
└── functions/ # Function field code (if any)
|
|
93
68
|
```
|
|
94
69
|
|
|
95
|
-
|
|
96
|
-
API: Activity data, counts, discussion messages
|
|
97
|
-
REFRESH: `npm run pull`
|
|
70
|
+
**Refresh:** `npm run pull` syncs server → local files
|
|
98
71
|
|
|
99
|
-
##
|
|
72
|
+
## SDK Push Commands (all use `:force` to avoid interactive prompts)
|
|
100
73
|
|
|
101
|
-
|
|
74
|
+
| Command | What it does |
|
|
75
|
+
|---------|-------------|
|
|
76
|
+
| `npm run push:force` | Push everything |
|
|
77
|
+
| `npm run fields-push:force` | Push field changes only |
|
|
78
|
+
| `npm run phases-push:force` | Push phase changes only |
|
|
79
|
+
| `npm run workflows-sync:force` | Sync workflow registry (create/delete) |
|
|
80
|
+
| `npm run teams-push:force` | Push team changes |
|
|
81
|
+
| `npm run groups-push:force` | Push group changes |
|
|
82
|
+
| `npm run pull` | Pull latest from Hailer → local files |
|
|
102
83
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
84
|
+
## SDK Gotchas
|
|
85
|
+
|
|
86
|
+
| Gotcha | Correct | Wrong |
|
|
87
|
+
|--------|---------|-------|
|
|
88
|
+
| New fields | Omit `_id` — server assigns it | Adding `_id` manually |
|
|
89
|
+
| After push | Always `npm run pull` to get server-assigned IDs | Assuming local IDs are final |
|
|
90
|
+
| Function fields | `npm run fields-push:force` (non-force skips functionVariables) | `npm run fields-push` |
|
|
91
|
+
| Enum imports | Verify after pull — identical hex suffixes can collide | Trusting auto-generated imports |
|
|
92
|
+
| `linkedfrom` fields | Don't work in isolated-vm — use `<` backlink dependency | Using in function fields |
|
|
93
|
+
| Function field code | Plain JavaScript only | TypeScript syntax |
|
|
94
|
+
| Phase transitions | Exact string match on phase name | Guessed names |
|
|
95
|
+
| Field values (MCP) | Date: Unix ms (`1730937600000`), Dropdown: exact string, ActivityLink: string ID | ISO dates, arrays, objects |
|
|
108
96
|
|
|
109
97
|
## App Development
|
|
110
98
|
|
|
111
|
-
|
|
99
|
+
| Step | How |
|
|
100
|
+
|------|-----|
|
|
101
|
+
| Scaffold | MCP `scaffold_hailer_app` — never copy apps |
|
|
102
|
+
| Publish | MCP `publish_hailer_app` — auto icon, name, description, sharing |
|
|
103
|
+
| Local dev | `npm run dev` from app directory |
|
|
112
104
|
|
|
113
|
-
|
|
105
|
+
## Skills
|
|
114
106
|
|
|
115
|
-
|
|
107
|
+
Load in sub-agents via Skill tool. Never in main context.
|
|
108
|
+
|
|
109
|
+
| Skill | When |
|
|
110
|
+
|-------|------|
|
|
111
|
+
| `sdk-ws-config-skill` | Workflows, fields, phases, teams, groups |
|
|
112
|
+
| `sdk-function-fields` | Calculated fields, nameFunction |
|
|
113
|
+
| `sdk-activity-patterns` | Creating/updating activities via MCP |
|
|
114
|
+
| `sdk-insight-queries` | SQL insight queries |
|
|
115
|
+
| `hailer-app-builder` | Building Hailer apps (React/Chakra) |
|
|
116
|
+
| `hailer-design-system` | Theme, colors, icons, layout |
|
|
117
|
+
| `publish-hailer-app` | Publishing apps to production |
|
|
118
|
+
| `testing-patterns` | Vitest/playwright tests |
|
|
116
119
|
|
|
117
120
|
## Commands
|
|
118
121
|
|
|
119
|
-
`/command <param>`
|
|
122
|
+
`/command <param>` — angle brackets = required
|
|
120
123
|
|
|
121
124
|
**Essential:** `/save`, `/handoff`, `/prd`, `/autoplan`, `/ws-pull`
|
|
122
125
|
|
|
123
|
-
**Squads:**
|
|
124
|
-
| Squad | Use for |
|
|
125
|
-
|-------|---------|
|
|
126
|
-
| `/app-squad` | Build apps end-to-end |
|
|
127
|
-
| `/review-squad` | Code review + tests |
|
|
128
|
-
| `/config-squad` | Workflow + fields + insights |
|
|
129
|
-
| `/hotfix-squad` | Quick bug fixes |
|
|
130
|
-
| `/debug-squad` | Investigation |
|
|
131
|
-
| `/swarm <desc>` | Large-scale parallel work |
|
|
132
|
-
|
|
133
|
-
## Project Structure
|
|
134
|
-
|
|
135
|
-
```
|
|
136
|
-
src/ # MCP server source
|
|
137
|
-
workspace/ # Hailer config - check FIRST for IDs
|
|
138
|
-
apps/ # Frontend apps
|
|
139
|
-
integrations/ # Backend services
|
|
140
|
-
.claude/ # Skills, hooks, commands
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## When to Use SDK Files vs MCP Tools
|
|
144
|
-
|
|
145
|
-
| Task | Use | NOT |
|
|
146
|
-
|------|-----|-----|
|
|
147
|
-
| Create/modify fields, phases, workflows | Edit `workspace/` files → `npm run push` | MCP `update_workflow_field` |
|
|
148
|
-
| Create function fields | Edit `fields.ts` + `functions/` → `vitest` → `npm run fields-push` | MCP tools |
|
|
149
|
-
| Read/write activity data | MCP tools (`list_activities`, `create_activity`, etc.) | Editing files |
|
|
150
|
-
| Query/report on data | MCP `preview_insight`, `create_insight` | — |
|
|
151
|
-
| Test existing function field code | MCP `test_function_field` (with `functionVariables`) | — |
|
|
152
|
-
|
|
153
|
-
**Function field workflow:** See Rules #5-8 at top of file.
|
|
154
|
-
|
|
155
|
-
## Hailer SDK Gotchas
|
|
156
|
-
|
|
157
|
-
| Gotcha | Correct | Wrong |
|
|
158
|
-
|--------|---------|-------|
|
|
159
|
-
| Activity field updates | `{type: "string", value: "x"}` | Raw value `"x"` |
|
|
160
|
-
| `linkedfrom` field type | Does NOT work in isolated-vm | Use `<` backlink dependency in functionVariables instead |
|
|
161
|
-
| Code in isolated-vm | Plain JavaScript only | TypeScript syntax |
|
|
162
|
-
| Phase transitions | Exact string match | Guessed names |
|
|
163
|
-
| Field IDs | Read from workspace/ | Guessing from labels |
|
|
164
|
-
| Dropdown values | `{data: [{value, label}]}` | `{options: [...]}` |
|
|
165
|
-
| ActivityLink format | Plain string array | Nested objects |
|
|
166
|
-
|
|
167
|
-
**Rule:** Always read workspace/ first. Never guess IDs or formats.
|
|
126
|
+
**Squads:** `/app-squad`, `/review-squad`, `/config-squad`, `/hotfix-squad`, `/debug-squad`, `/swarm <desc>`
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-and-publish-app
|
|
3
|
+
description: How to scaffold, create and publish Hailer apps using @hailer/create-app npm package (CLI-based alternative to scaffold_hailer_app MCP tool)
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
triggers:
|
|
6
|
+
- create-app
|
|
7
|
+
- npx create-app
|
|
8
|
+
- hailer create-app
|
|
9
|
+
- scaffold app cli
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Create and Publish Hailer App
|
|
13
|
+
|
|
14
|
+
Scaffold, create and publish Hailer apps using `@hailer/create-app` npm package.
|
|
15
|
+
|
|
16
|
+
**npm package docs:** https://www.npmjs.com/package/@hailer/create-app
|
|
17
|
+
**Registry README (machine-readable):** https://registry.npmjs.org/@hailer/create-app (check `readme` field)
|
|
18
|
+
|
|
19
|
+
<when-to-use>
|
|
20
|
+
## When to Use This vs scaffold_hailer_app MCP Tool
|
|
21
|
+
|
|
22
|
+
| Approach | When |
|
|
23
|
+
|----------|------|
|
|
24
|
+
| `npx @hailer/create-app` (this skill) | CLI-based scaffolding, `npm run publish-production` for publishing |
|
|
25
|
+
| `scaffold_hailer_app` MCP tool | MCP-based scaffolding, `publish_hailer_app` MCP tool for publishing |
|
|
26
|
+
|
|
27
|
+
Both create valid Hailer apps. This skill covers the npm CLI path.
|
|
28
|
+
</when-to-use>
|
|
29
|
+
|
|
30
|
+
<step-1>
|
|
31
|
+
## Step 1 — Scaffold the Project
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @hailer/create-app <project-name> --template react-ts
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- Run from the `apps/` directory (create it first if it doesn't exist: `mkdir -p apps`)
|
|
38
|
+
- `react-ts` is the recommended template
|
|
39
|
+
- **CRITICAL:** The CLI is interactive-only when called via `npm create` — always use `npx @hailer/create-app` with the name and template as arguments to avoid prompts
|
|
40
|
+
</step-1>
|
|
41
|
+
|
|
42
|
+
<step-2>
|
|
43
|
+
## Step 2 — Install Dependencies
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cd apps/<project-name>
|
|
47
|
+
npm install
|
|
48
|
+
```
|
|
49
|
+
</step-2>
|
|
50
|
+
|
|
51
|
+
<step-3>
|
|
52
|
+
## Step 3 — Build the App UI
|
|
53
|
+
|
|
54
|
+
Replace `src/App.tsx` and add components. Key patterns:
|
|
55
|
+
|
|
56
|
+
- Use `useApp` from `src/hailer/use-app.ts` (the new template uses zustand-based state)
|
|
57
|
+
- Call `api.init()` in a `useEffect` in `App.tsx`
|
|
58
|
+
- Use `hailer.activity.list(workflowId, phaseId, options)` to fetch data — call once per phase in parallel with `Promise.all`
|
|
59
|
+
- Use `hailer.ui.activity.open(id)` to open an activity sidebar
|
|
60
|
+
- Use `hailer.ui.activity.create(workflowId)` to open the create form
|
|
61
|
+
</step-3>
|
|
62
|
+
|
|
63
|
+
<step-4>
|
|
64
|
+
## Step 4 — Create and Publish (First Time)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm run publish-production -- --create --app-name "<App Name>" --workspace <workspaceId> --force
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Flag | Purpose |
|
|
71
|
+
|------|---------|
|
|
72
|
+
| `--create` | Creates a brand new app entry in Hailer |
|
|
73
|
+
| `--app-name` | Name shown in Hailer |
|
|
74
|
+
| `--workspace` | Workspace ID from `config.json` at project root |
|
|
75
|
+
| `--force` | Skips confirmation prompt |
|
|
76
|
+
|
|
77
|
+
**No `--user-api-key` needed** — the publish script automatically picks up credentials from the `~/.env` file injected by Hailer Studio. Credential resolution order:
|
|
78
|
+
1. `--user-api-key` or `--email` flags
|
|
79
|
+
2. `USER_API_KEY` or `HAILER_USER_API_KEY` environment variables
|
|
80
|
+
3. `HAILER_USER_API_KEY` from `~/.env` ← this is what Hailer Studio provides automatically
|
|
81
|
+
|
|
82
|
+
After running, `public/manifest.json` is auto-updated with the new `appId`.
|
|
83
|
+
</step-4>
|
|
84
|
+
|
|
85
|
+
<step-5>
|
|
86
|
+
## Step 5 — Subsequent Publishes
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm run publish-production -- --force
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The `appId` in `manifest.json` determines which app gets updated. No API key needed — `~/.env` is picked up automatically.
|
|
93
|
+
</step-5>
|
|
94
|
+
|
|
95
|
+
<dev-vs-prod>
|
|
96
|
+
## Dev vs Production Strategy
|
|
97
|
+
|
|
98
|
+
Maintain two separate published apps:
|
|
99
|
+
|
|
100
|
+
| App | Purpose |
|
|
101
|
+
|-----|---------|
|
|
102
|
+
| My App Dev | Publish here during iteration |
|
|
103
|
+
| My App | Publish here only when ready for users |
|
|
104
|
+
|
|
105
|
+
Switch between them by changing `appId` in `public/manifest.json` before publishing.
|
|
106
|
+
</dev-vs-prod>
|
|
107
|
+
|
|
108
|
+
<environments>
|
|
109
|
+
## Environments
|
|
110
|
+
|
|
111
|
+
| Command | Target |
|
|
112
|
+
|---------|--------|
|
|
113
|
+
| `npm run publish-production` | Production (https://api.hailer.com) |
|
|
114
|
+
| `npm run publish-development` | Development (https://testapi.hailer.biz) |
|
|
115
|
+
| `npm run publish-staging` | Staging (https://api.hailer.biz) |
|
|
116
|
+
</environments>
|
|
117
|
+
|
|
118
|
+
<checklist>
|
|
119
|
+
## Checklist Before Publishing
|
|
120
|
+
|
|
121
|
+
- [ ] Read `apps/<project-name>/README.md` — it always has the latest commands for that version
|
|
122
|
+
- [ ] Verify `public/manifest.json` has the correct `appId` for the target app
|
|
123
|
+
- [ ] `version` and `versionDescription` in manifest are only required for marketplace publishes
|
|
124
|
+
- [ ] Build runs automatically as part of the publish script — no separate build step needed
|
|
125
|
+
- [ ] Workspace ID is in `config.json` at the project root
|
|
126
|
+
- [ ] No API key needed — `~/.env` is picked up automatically by the publish script
|
|
127
|
+
</checklist>
|
|
@@ -483,6 +483,53 @@ const workspaces = await hailer.workspace.list();
|
|
|
483
483
|
```
|
|
484
484
|
</sdk-api>
|
|
485
485
|
|
|
486
|
+
<field-resolver>
|
|
487
|
+
## Field Resolver Pattern
|
|
488
|
+
|
|
489
|
+
Every scaffolded app includes `src/hailer/field-resolver.ts`. It resolves human-readable field keys to hex IDs at runtime.
|
|
490
|
+
|
|
491
|
+
### Functions
|
|
492
|
+
|
|
493
|
+
**`createFieldResolver(workflowFields)`** — low-level. Takes a workflow's `fields` map, returns a resolver function.
|
|
494
|
+
|
|
495
|
+
**`useFieldResolver(workflows, workflowId)`** — hook-friendly wrapper. Takes `useApp().app.workflows` and a workflow ID.
|
|
496
|
+
|
|
497
|
+
### How It Works
|
|
498
|
+
|
|
499
|
+
- Pass a field **key** (e.g., `'matchDate'`) → resolves to hex ID at runtime
|
|
500
|
+
- Pass a field **hex ID** (e.g., `'691ffdf84217e9e8434e5697'`) → returns as-is
|
|
501
|
+
- Workflows without keys → passthrough, hex IDs still work
|
|
502
|
+
|
|
503
|
+
### Usage
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
import { useFieldResolver } from './hailer/field-resolver';
|
|
507
|
+
import { useApp } from './hailer/use-app';
|
|
508
|
+
|
|
509
|
+
const WORKFLOW_ID = '691ffdf84217e9e8434e56a5';
|
|
510
|
+
const FIELD_KEYS = {
|
|
511
|
+
MATCH_DATE: 'matchDate',
|
|
512
|
+
HOME_TEAM: 'homeTeam',
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
function MyComponent() {
|
|
516
|
+
const { app } = useApp();
|
|
517
|
+
const f = useFieldResolver(app.workflows, WORKFLOW_ID);
|
|
518
|
+
|
|
519
|
+
// f() resolves keys to IDs — works with either
|
|
520
|
+
const date = activity.fields?.[f(FIELD_KEYS.MATCH_DATE)];
|
|
521
|
+
const team = activity.fields?.[f(FIELD_KEYS.HOME_TEAM)];
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### Key Points
|
|
526
|
+
|
|
527
|
+
- Define field keys as constants (human-readable, portable across workspaces)
|
|
528
|
+
- The resolver handles both keys and hex IDs — safe to pass either
|
|
529
|
+
- Wait for workflow data before fetching activities — add the workflow to `useEffect` deps
|
|
530
|
+
- `useApp().app.workflows` is loaded on init by the scaffold's `onReady` handler
|
|
531
|
+
</field-resolver>
|
|
532
|
+
|
|
486
533
|
<field-patterns>
|
|
487
534
|
## Extracting Field Values
|
|
488
535
|
|
|
@@ -86,11 +86,17 @@ publish_hailer_app({
|
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
This does everything in one call:
|
|
89
|
+
- **Auto-derives app name** from project directory (e.g., `upcoming-matches` → "Upcoming Matches")
|
|
90
|
+
- **Auto-sets description** from `versionDescription` in manifest.json
|
|
91
|
+
- **Auto-generates and uploads a colored icon** with initials (e.g., green "UM" circle)
|
|
92
|
+
- **Auto-shares** with the entire workspace
|
|
89
93
|
- Copies manifest.json into dist/
|
|
90
94
|
- Creates .tgz with `package/` prefix (matches npm pack format)
|
|
91
95
|
- Uploads to S3 via POST /app/publish
|
|
92
96
|
- **Auto-updates app URL** to `https://apps.hailer.com/{workspaceId}/{appId}/`
|
|
93
97
|
|
|
98
|
+
No manual `update_app` calls needed after publish — name, description, icon, and sharing are all automatic.
|
|
99
|
+
|
|
94
100
|
### Step 3: Verify
|
|
95
101
|
|
|
96
102
|
```javascript
|
|
@@ -124,9 +130,14 @@ If missing/empty, the tool returns "Success" but files are NOT uploaded.
|
|
|
124
130
|
**Flow:**
|
|
125
131
|
1. `scaffold_hailer_app` checks for existing dev app at localhost:3000 — reuses it instead of creating duplicates
|
|
126
132
|
2. Dev app stays at localhost forever — it's your development slot
|
|
127
|
-
3. When user says "publish": `publish_hailer_app` detects the dev app URL, auto-creates a NEW production app
|
|
128
|
-
|
|
129
|
-
|
|
133
|
+
3. When user says "publish": `publish_hailer_app` detects the dev app URL, auto-creates a NEW production app with:
|
|
134
|
+
- Name derived from project directory (e.g., `upcoming-matches` → "Upcoming Matches")
|
|
135
|
+
- Description from `versionDescription` in manifest.json
|
|
136
|
+
- Colored icon with initials (auto-generated, uploaded as public)
|
|
137
|
+
- Shared with entire workspace
|
|
138
|
+
- URL pointing to production CDN
|
|
139
|
+
|
|
140
|
+
**No manual `update_app` or `create_app` needed.** The publish tool handles name, description, icon, sharing, and URL automatically.
|
|
130
141
|
</dev-vs-prod>
|
|
131
142
|
|
|
132
143
|
<updating>
|
|
@@ -181,6 +192,8 @@ Use `publish_app` with `productId` (the marketplace listing ID, NOT the targetId
|
|
|
181
192
|
<sharing>
|
|
182
193
|
## Sharing Apps
|
|
183
194
|
|
|
195
|
+
Workspace sharing is automatic on first publish. For manual sharing:
|
|
196
|
+
|
|
184
197
|
```javascript
|
|
185
198
|
// Entire workspace
|
|
186
199
|
add_app_member({ appId: "...", member: "network_{workspaceId}" })
|
|
@@ -193,6 +206,22 @@ add_app_member({ appId: "...", member: "user_{userId}" })
|
|
|
193
206
|
```
|
|
194
207
|
</sharing>
|
|
195
208
|
|
|
209
|
+
<gotchas>
|
|
210
|
+
## Gotchas
|
|
211
|
+
|
|
212
|
+
**App icons MUST be uploaded with `isPublic: true`.**
|
|
213
|
+
Files uploaded without this flag are private — the Hailer frontend can't load them and shows a broken/transparent image. The publish tool handles this automatically, but if you manually upload an icon via `upload_files`, always include `isPublic: true`:
|
|
214
|
+
```javascript
|
|
215
|
+
upload_files({ files: [{ path: "/tmp/icon.png", isPublic: true }] })
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**SVG images don't work as app icons.**
|
|
219
|
+
Hailer's backend image pipeline uses sharp for resizing and doesn't serve SVGs correctly. Always use PNG or JPEG.
|
|
220
|
+
|
|
221
|
+
**Don't use SVG gradients in icon generation.**
|
|
222
|
+
Sharp's `flatten()` with SVG `linearGradient` produces transparency. Use `sharp.create()` with solid RGB background + composite for text.
|
|
223
|
+
</gotchas>
|
|
224
|
+
|
|
196
225
|
<vite-config>
|
|
197
226
|
## CRITICAL: Vite Base Path
|
|
198
227
|
|
|
@@ -241,9 +270,11 @@ Hailer apps are served from `apps.hailer.com` static hosting - we can't control
|
|
|
241
270
|
|
|
242
271
|
- [ ] manifest.json `appId` is 24 chars (dev app ID is fine — publish auto-creates prod app)
|
|
243
272
|
- [ ] manifest.json `version` is set (e.g., "1.0.0")
|
|
244
|
-
- [ ] manifest.json `versionDescription` is set (not empty)
|
|
273
|
+
- [ ] manifest.json `versionDescription` is set (not empty — also used as app description)
|
|
245
274
|
- [ ] vite.config.ts has `base: './'`
|
|
246
275
|
- [ ] index.html has no-cache meta tags (see cache-busting section)
|
|
247
276
|
- [ ] node_modules exists (dependencies installed)
|
|
248
277
|
- [ ] After publish: verify URL auto-updated to production format (check with `list_apps`)
|
|
278
|
+
|
|
279
|
+
**Automatic on first publish** (no action needed): app name, description, colored icon, workspace sharing.
|
|
249
280
|
</checklist>
|