@hailer/mcp 0.0.6 → 0.1.1
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/agents/ada.md +127 -0
- package/.claude/agents/agent-builder.md +151 -0
- package/.claude/agents/alejandro.md +66 -0
- package/.claude/agents/bjorn.md +305 -0
- package/.claude/agents/dmitri.md +61 -0
- package/.claude/agents/giuseppe.md +66 -0
- package/.claude/agents/gunther.md +355 -0
- package/.claude/agents/helga.md +68 -0
- package/.claude/agents/ingrid.md +108 -0
- package/.claude/agents/kenji.md +58 -0
- package/.claude/agents/svetlana.md +394 -0
- package/.claude/agents/viktor.md +63 -0
- package/.claude/agents/yevgeni.md +60 -0
- package/.claude/hooks/agent-failure-detector.cjs +286 -0
- package/.claude/hooks/app-edit-guard.cjs +462 -0
- package/.claude/hooks/interactive-mode.cjs +59 -0
- package/.claude/hooks/mcp-server-guard.cjs +92 -0
- package/.claude/hooks/post-scaffold-hook.cjs +31 -0
- package/.claude/hooks/sdk-delete-guard.cjs +2 -0
- package/.claude/hooks/src-edit-guard.cjs +208 -0
- package/.claude/settings.json +47 -2
- package/.claude/skills/insight-join-patterns/SKILL.md +209 -0
- package/.env.example +13 -1
- package/CLAUDE.md +135 -0
- package/dist/app.js +4 -3
- package/dist/cli.js +0 -0
- package/dist/client/adaptive-documentation-bot.d.ts +0 -2
- package/dist/client/adaptive-documentation-bot.js +5 -16
- package/dist/client/message-processor.js +5 -0
- package/dist/client/providers/anthropic-provider.js +21 -7
- package/dist/mcp/UserContextCache.d.ts +14 -0
- package/dist/mcp/UserContextCache.js +49 -24
- package/dist/mcp/auth.d.ts +7 -0
- package/dist/mcp/auth.js +13 -5
- package/dist/mcp/hailer-clients.d.ts +5 -2
- package/dist/mcp/signal-handler.d.ts +28 -2
- package/dist/mcp/signal-handler.js +4 -2
- package/dist/mcp/tool-registry.d.ts +55 -2
- package/dist/mcp/tool-registry.js +197 -2
- package/dist/mcp/tools/app-core.d.ts +15 -0
- package/dist/mcp/tools/app-core.js +609 -0
- package/dist/mcp/tools/app-marketplace.d.ts +21 -0
- package/dist/mcp/tools/app-marketplace.js +1284 -0
- package/dist/mcp/tools/app-member.d.ts +11 -0
- package/dist/mcp/tools/app-member.js +258 -0
- package/dist/mcp/tools/app-scaffold.d.ts +11 -0
- package/dist/mcp/tools/app-scaffold.js +743 -0
- package/dist/mcp/tools/app.d.ts +13 -22
- package/dist/mcp/tools/app.js +17 -2466
- package/dist/mcp/tools/file.js +6 -6
- package/dist/mcp/tools/insight.d.ts +1 -0
- package/dist/mcp/tools/insight.js +203 -64
- package/dist/mcp/tools/user.js +3 -9
- package/dist/mcp/tools/workflow.js +49 -38
- package/dist/mcp/utils/hailer-api-client.js +4 -13
- package/dist/mcp/utils/tool-helpers.d.ts +102 -0
- package/dist/mcp/utils/tool-helpers.js +179 -0
- package/dist/mcp/utils/types.d.ts +6 -0
- package/dist/mcp/workspace-cache.d.ts +5 -5
- package/dist/mcp/workspace-cache.js +4 -3
- package/package.json +1 -1
- package/.claude/hooks/PreToolUse.sh +0 -52
- package/.claude/hooks/prompt-skill-loader.cjs +0 -553
- package/.claude/hooks/skill-loader.cjs +0 -142
- package/.claude/settings.local.json +0 -49
- package/.claude/skills/MCP-add-app-member-skill/SKILL.md +0 -977
- package/.claude/skills/MCP-build-data-app-skill/SKILL.md +0 -372
- package/.claude/skills/MCP-create-app-skill/SKILL.md +0 -1101
- package/.claude/skills/MCP-create-insight-skill/SKILL.md +0 -1317
- package/.claude/skills/MCP-get-insight-data-skill/SKILL.md +0 -1053
- package/.claude/skills/MCP-insight-api/SKILL.md +0 -185
- package/.claude/skills/MCP-insight-api/references/insight-endpoints.md +0 -514
- package/.claude/skills/MCP-install-workflow-skill/SKILL.md +0 -1056
- package/.claude/skills/MCP-list-apps-skill/SKILL.md +0 -1010
- package/.claude/skills/MCP-list-workflows-minimal-skill/SKILL.md +0 -992
- package/.claude/skills/MCP-local-first-skill/SKILL.md +0 -570
- package/.claude/skills/MCP-populate-workflow-data-skill/SKILL.md +0 -395
- package/.claude/skills/MCP-preview-insight-skill/SKILL.md +0 -1290
- package/.claude/skills/MCP-publish-hailer-app-skill/SKILL.md +0 -453
- package/.claude/skills/MCP-publish-template-skill/SKILL.md +0 -278
- package/.claude/skills/MCP-remove-app-member-skill/SKILL.md +0 -671
- package/.claude/skills/MCP-remove-app-skill/SKILL.md +0 -985
- package/.claude/skills/MCP-remove-insight-skill/SKILL.md +0 -1011
- package/.claude/skills/MCP-remove-workflow-skill/SKILL.md +0 -920
- package/.claude/skills/MCP-scaffold-hailer-app-skill/SKILL.md +0 -1314
- package/.claude/skills/MCP-update-app-skill/SKILL.md +0 -970
- package/.claude/skills/MCP-update-workflow-field-skill/SKILL.md +0 -1098
- package/.claude/skills/SDK-create-function-field-skill/SKILL.md +0 -313
- package/.claude/skills/SDK-generate-skill/SKILL.md +0 -223
- package/.claude/skills/SDK-init-skill/SKILL.md +0 -177
- package/.claude/skills/SDK-workspace-setup-skill/SKILL.md +0 -605
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -435
- package/.claude/skills/activity-api/SKILL.md +0 -96
- package/.claude/skills/activity-api/references/activity-endpoints.md +0 -845
- package/.claude/skills/agent-building/SKILL.md +0 -243
- package/.claude/skills/agent-building/references/architecture-patterns.md +0 -446
- package/.claude/skills/agent-building/references/code-examples.md +0 -587
- package/.claude/skills/agent-building/references/implementation-guide.md +0 -619
- package/.claude/skills/app-api/SKILL.md +0 -219
- package/.claude/skills/app-api/references/app-endpoints.md +0 -759
- package/.claude/skills/building-hailer-apps-skill/SKILL.md +0 -813
- package/.claude/skills/hailer-api/SKILL.md +0 -283
- package/.claude/skills/hailer-api/references/activities.md +0 -620
- package/.claude/skills/hailer-api/references/authentication.md +0 -216
- package/.claude/skills/hailer-api/references/datasets.md +0 -437
- package/.claude/skills/hailer-api/references/files.md +0 -301
- package/.claude/skills/hailer-api/references/insights.md +0 -469
- package/.claude/skills/hailer-api/references/workflows.md +0 -720
- package/.claude/skills/hailer-api/references/workspaces-users.md +0 -445
- package/.claude/skills/hailer-app-builder/SKILL.md +0 -340
- package/.claude/skills/mcp-tools/SKILL.md +0 -419
- package/.claude/skills/mcp-tools/references/api-endpoints.md +0 -499
- package/.claude/skills/mcp-tools/references/data-structures.md +0 -554
- package/.claude/skills/mcp-tools/references/implementation-patterns.md +0 -717
- package/.claude/skills/skill-testing/README.md +0 -137
- package/.claude/skills/skill-testing/SKILL.md +0 -348
- package/.claude/skills/skill-testing/references/test-patterns.md +0 -705
- package/.claude/skills/skill-testing/references/testing-guide.md +0 -603
- package/.claude/skills/skill-testing/references/validation-checklist.md +0 -537
- package/.claude/skills/spawn-app-builder/SKILL.md +0 -366
- package/.claude/skills/tool-builder/SKILL.md +0 -328
- package/tsconfig.json +0 -23
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
# Build Data App Skill
|
|
2
|
-
|
|
3
|
-
Complete guide for building Hailer data visualization and management apps based on workspace workflows.
|
|
4
|
-
|
|
5
|
-
> **Important:** For comprehensive SDK API documentation, load `building-hailer-apps-skill` which covers all SDK patterns, field access, and common pitfalls in detail.
|
|
6
|
-
|
|
7
|
-
## When to Use This Skill
|
|
8
|
-
|
|
9
|
-
Use this skill when:
|
|
10
|
-
- Building apps to visualize workspace data
|
|
11
|
-
- Creating data management dashboards
|
|
12
|
-
- Building CRUD interfaces for workflows
|
|
13
|
-
- User says "build me an app", "visualize data", "create dashboard"
|
|
14
|
-
|
|
15
|
-
## Prerequisites
|
|
16
|
-
|
|
17
|
-
Before building, you need:
|
|
18
|
-
1. **Scaffolded app** - Use `scaffold_hailer_app` first
|
|
19
|
-
2. **Workspace info** - Run `list_workflows_minimal()` to see available data
|
|
20
|
-
3. **Requirements** - App type, features, and workflow selection
|
|
21
|
-
|
|
22
|
-
## The Build Flow
|
|
23
|
-
|
|
24
|
-
### Step 0: Discovery (Auto)
|
|
25
|
-
|
|
26
|
-
```javascript
|
|
27
|
-
// Always run this first to understand the workspace
|
|
28
|
-
list_workflows_minimal()
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Shows:
|
|
32
|
-
- All workflows (like database tables)
|
|
33
|
-
- Activity counts (row counts)
|
|
34
|
-
- Workflow IDs for API calls
|
|
35
|
-
|
|
36
|
-
### Step 1: Gather Requirements
|
|
37
|
-
|
|
38
|
-
Use AskUserQuestion to collect:
|
|
39
|
-
|
|
40
|
-
| Question | Options | Purpose |
|
|
41
|
-
|----------|---------|---------|
|
|
42
|
-
| App Type | Dashboard / Full Manager / Specific Workflows | Determines layout |
|
|
43
|
-
| Features | View / Edit / Create | Determines UI components |
|
|
44
|
-
| Workflows | All or specific selection | Determines data scope |
|
|
45
|
-
| App Name | Project folder name | Used for scaffolding |
|
|
46
|
-
|
|
47
|
-
### Step 2: Scaffold
|
|
48
|
-
|
|
49
|
-
```javascript
|
|
50
|
-
scaffold_hailer_app({
|
|
51
|
-
projectName: "<app-name>",
|
|
52
|
-
template: "react-ts",
|
|
53
|
-
description: "<generated from requirements>"
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Step 3: Build Components
|
|
58
|
-
|
|
59
|
-
Based on requirements, create appropriate React components.
|
|
60
|
-
|
|
61
|
-
## App Architecture Patterns
|
|
62
|
-
|
|
63
|
-
### Dashboard Overview
|
|
64
|
-
|
|
65
|
-
**Layout:** Grid of cards showing workflow stats
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
+------------------+------------------+------------------+
|
|
69
|
-
| Players (31) | Matches (15) | Teams (15) |
|
|
70
|
-
| View Details | View Details | View Details |
|
|
71
|
-
+------------------+------------------+------------------+
|
|
72
|
-
| Injuries (9) | Training (17) | Stats (8) |
|
|
73
|
-
| View Details | View Details | View Details |
|
|
74
|
-
+------------------+------------------+------------------+
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
**Components needed:**
|
|
78
|
-
- `WorkflowCard` - Shows workflow name, count, link
|
|
79
|
-
- `Dashboard` - Grid layout of cards
|
|
80
|
-
- `useWorkflows` - Hook to fetch workflow list
|
|
81
|
-
|
|
82
|
-
### Full Data Manager
|
|
83
|
-
|
|
84
|
-
**Layout:** Sidebar navigation + main content area
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
+----------+----------------------------------------+
|
|
88
|
-
| Players | [Search] [Filter] [+ New Activity] |
|
|
89
|
-
| Matches +----------------------------------------+
|
|
90
|
-
| Teams | Name Status Date |
|
|
91
|
-
| Training | Player 1 Active 2024-01-15 |
|
|
92
|
-
| Stats | Player 2 Injured 2024-01-10 |
|
|
93
|
-
| ... | Player 3 Active 2024-01-08 |
|
|
94
|
-
+----------+----------------------------------------+
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Components needed:**
|
|
98
|
-
- `Sidebar` - Workflow navigation
|
|
99
|
-
- `ActivityList` - Table/list of activities
|
|
100
|
-
- `ActivityRow` - Individual activity display
|
|
101
|
-
- `SearchFilter` - Search and filter controls
|
|
102
|
-
- `ActivityForm` - Create/Edit form (if features include Edit/Create)
|
|
103
|
-
|
|
104
|
-
### Specific Workflow Focus
|
|
105
|
-
|
|
106
|
-
**Layout:** Tabs or focused views for selected workflows
|
|
107
|
-
|
|
108
|
-
```
|
|
109
|
-
+--------------------------------------------------+
|
|
110
|
-
| [Players] [Contracts] [Stats] [Injuries] |
|
|
111
|
-
+--------------------------------------------------+
|
|
112
|
-
| Player Details View with Related Data |
|
|
113
|
-
| - Contract info |
|
|
114
|
-
| - Stats history |
|
|
115
|
-
| - Injury records |
|
|
116
|
-
+--------------------------------------------------+
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**Components needed:**
|
|
120
|
-
- `TabNav` - Tab navigation between workflows
|
|
121
|
-
- `WorkflowView` - Main view for each workflow
|
|
122
|
-
- `RelatedData` - Shows linked activities
|
|
123
|
-
|
|
124
|
-
## Hailer SDK API Patterns
|
|
125
|
-
|
|
126
|
-
### CRITICAL: Correct API Usage
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
// CORRECT - Use hailer.activity (singular)
|
|
130
|
-
const activities = await hailer.activity.list(
|
|
131
|
-
processId, // Workflow ID
|
|
132
|
-
phaseId, // Phase ID
|
|
133
|
-
options // { sortBy, sortOrder, limit, filters }
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
// WRONG - This will fail
|
|
137
|
-
const activities = await hailer.activities.list({...}) // undefined!
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Fetching Activities
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
import useHailer from './hailer/use-hailer';
|
|
144
|
-
|
|
145
|
-
export function useActivities(workflowId: string, phaseId: string) {
|
|
146
|
-
const { hailer, inside } = useHailer();
|
|
147
|
-
const [activities, setActivities] = useState([]);
|
|
148
|
-
const [loading, setLoading] = useState(true);
|
|
149
|
-
|
|
150
|
-
useEffect(() => {
|
|
151
|
-
if (!hailer || !inside) return;
|
|
152
|
-
|
|
153
|
-
async function fetch() {
|
|
154
|
-
try {
|
|
155
|
-
const data = await hailer.activity.list(
|
|
156
|
-
workflowId,
|
|
157
|
-
phaseId,
|
|
158
|
-
{ sortBy: 'updated', sortOrder: 'desc', limit: 50 }
|
|
159
|
-
);
|
|
160
|
-
setActivities(data || []);
|
|
161
|
-
} catch (err) {
|
|
162
|
-
console.error('Failed to fetch:', err);
|
|
163
|
-
} finally {
|
|
164
|
-
setLoading(false);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
fetch();
|
|
169
|
-
}, [hailer, inside, workflowId, phaseId]);
|
|
170
|
-
|
|
171
|
-
return { activities, loading };
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Accessing Custom Fields
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
// Fields are in activity.fields object, NOT directly on activity
|
|
179
|
-
interface Activity {
|
|
180
|
-
_id: string;
|
|
181
|
-
name: string;
|
|
182
|
-
fields?: {
|
|
183
|
-
[fieldKey: string]: any;
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// CORRECT
|
|
188
|
-
const playerName = activity.fields?.playerName;
|
|
189
|
-
const status = activity.fields?.status;
|
|
190
|
-
|
|
191
|
-
// WRONG - These are undefined
|
|
192
|
-
const playerName = activity.playerName; // undefined!
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Creating Activities
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
async function createActivity(workflowId: string, data: any) {
|
|
199
|
-
const created = await hailer.activity.create(
|
|
200
|
-
workflowId,
|
|
201
|
-
[{ name: data.name, fields: data.fields }]
|
|
202
|
-
);
|
|
203
|
-
return created[0];
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Updating Activities
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
async function updateActivity(activityId: string, updates: any) {
|
|
211
|
-
await hailer.activity.update(
|
|
212
|
-
[{ _id: activityId, ...updates }],
|
|
213
|
-
{}
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Feature Implementation
|
|
219
|
-
|
|
220
|
-
### View Only
|
|
221
|
-
|
|
222
|
-
Components:
|
|
223
|
-
- Activity list with sorting
|
|
224
|
-
- Search/filter
|
|
225
|
-
- Click to view details (read-only)
|
|
226
|
-
|
|
227
|
-
### View + Edit
|
|
228
|
-
|
|
229
|
-
Additional components:
|
|
230
|
-
- Edit button on each row
|
|
231
|
-
- Edit form/modal
|
|
232
|
-
- Save/Cancel buttons
|
|
233
|
-
- Optimistic updates
|
|
234
|
-
|
|
235
|
-
### View + Edit + Create
|
|
236
|
-
|
|
237
|
-
Additional components:
|
|
238
|
-
- "New Activity" button
|
|
239
|
-
- Create form/modal
|
|
240
|
-
- Validation
|
|
241
|
-
- Success/error feedback
|
|
242
|
-
|
|
243
|
-
## Getting Workflow Metadata
|
|
244
|
-
|
|
245
|
-
### Option 1: From SDK (in React components)
|
|
246
|
-
|
|
247
|
-
```typescript
|
|
248
|
-
// Use hailer.workflow.get() - NOT hailer.process.getFields()!
|
|
249
|
-
const workflow = await hailer.workflow.get(workflowId);
|
|
250
|
-
|
|
251
|
-
// workflow.fields = { fieldId: { label, type, key, data, required } }
|
|
252
|
-
// workflow.phases = { phaseId: { name, fields: [...] } }
|
|
253
|
-
|
|
254
|
-
// Extract field schema as array
|
|
255
|
-
const fieldIds = workflow.phases?.[phaseId]?.fields || Object.keys(workflow.fields);
|
|
256
|
-
const schema = fieldIds.map(id => ({
|
|
257
|
-
_id: id,
|
|
258
|
-
...workflow.fields[id]
|
|
259
|
-
}));
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Option 2: From MCP Tools (before building)
|
|
263
|
-
|
|
264
|
-
```javascript
|
|
265
|
-
// Get phases for a workflow
|
|
266
|
-
list_workflow_phases({ workflowId: "xxx" })
|
|
267
|
-
|
|
268
|
-
// Get field schema
|
|
269
|
-
get_workflow_schema({ workflowId: "xxx", phaseId: "yyy" })
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
This tells you:
|
|
273
|
-
- Available phases (like statuses)
|
|
274
|
-
- Field types (text, numeric, date, dropdown, etc.)
|
|
275
|
-
- Field keys for API access
|
|
276
|
-
|
|
277
|
-
### ⚠️ Common Mistake
|
|
278
|
-
|
|
279
|
-
```typescript
|
|
280
|
-
// ❌ WRONG - These methods don't exist!
|
|
281
|
-
await hailer.process.getFields(workflowId, phaseId);
|
|
282
|
-
await hailer.workflow.getFields(workflowId);
|
|
283
|
-
|
|
284
|
-
// ✅ CORRECT
|
|
285
|
-
const workflow = await hailer.workflow.get(workflowId);
|
|
286
|
-
const fields = workflow.fields;
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## Example: Complete Dashboard Component
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
import { useEffect, useState } from 'react';
|
|
293
|
-
import useHailer from './hailer/use-hailer';
|
|
294
|
-
|
|
295
|
-
interface WorkflowSummary {
|
|
296
|
-
id: string;
|
|
297
|
-
name: string;
|
|
298
|
-
count: number;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
export default function Dashboard() {
|
|
302
|
-
const { hailer, inside } = useHailer();
|
|
303
|
-
const [workflows, setWorkflows] = useState<WorkflowSummary[]>([]);
|
|
304
|
-
const [loading, setLoading] = useState(true);
|
|
305
|
-
|
|
306
|
-
useEffect(() => {
|
|
307
|
-
if (!hailer || !inside) return;
|
|
308
|
-
|
|
309
|
-
async function fetchWorkflows() {
|
|
310
|
-
try {
|
|
311
|
-
// Get workspace workflows
|
|
312
|
-
const ws = await hailer.workspace.get();
|
|
313
|
-
const summaries: WorkflowSummary[] = [];
|
|
314
|
-
|
|
315
|
-
for (const [id, workflow] of Object.entries(ws.processes || {})) {
|
|
316
|
-
summaries.push({
|
|
317
|
-
id,
|
|
318
|
-
name: workflow.name,
|
|
319
|
-
count: workflow.activityCount || 0
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
setWorkflows(summaries);
|
|
324
|
-
} catch (err) {
|
|
325
|
-
console.error('Failed to load:', err);
|
|
326
|
-
} finally {
|
|
327
|
-
setLoading(false);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
fetchWorkflows();
|
|
332
|
-
}, [hailer, inside]);
|
|
333
|
-
|
|
334
|
-
if (loading) return <div>Loading...</div>;
|
|
335
|
-
|
|
336
|
-
return (
|
|
337
|
-
<div className="dashboard">
|
|
338
|
-
<h1>Workspace Overview</h1>
|
|
339
|
-
<div className="workflow-grid">
|
|
340
|
-
{workflows.map(wf => (
|
|
341
|
-
<div key={wf.id} className="workflow-card">
|
|
342
|
-
<h3>{wf.name}</h3>
|
|
343
|
-
<p>{wf.count} activities</p>
|
|
344
|
-
<button onClick={() => navigate(`/workflow/${wf.id}`)}>
|
|
345
|
-
View Details
|
|
346
|
-
</button>
|
|
347
|
-
</div>
|
|
348
|
-
))}
|
|
349
|
-
</div>
|
|
350
|
-
</div>
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
## Related Skills
|
|
356
|
-
|
|
357
|
-
- **building-hailer-apps-skill** - Comprehensive app SDK guide
|
|
358
|
-
- **scaffold-hailer-app-skill** - One-shot app scaffolding
|
|
359
|
-
- **hailer-api** - Complete API reference
|
|
360
|
-
|
|
361
|
-
## Checklist
|
|
362
|
-
|
|
363
|
-
Before considering the app complete:
|
|
364
|
-
|
|
365
|
-
- [ ] App scaffolded and running
|
|
366
|
-
- [ ] All required workflows accessible
|
|
367
|
-
- [ ] View functionality working
|
|
368
|
-
- [ ] Edit functionality working (if required)
|
|
369
|
-
- [ ] Create functionality working (if required)
|
|
370
|
-
- [ ] Error handling in place
|
|
371
|
-
- [ ] Loading states shown
|
|
372
|
-
- [ ] Responsive layout
|