@hailer/mcp 0.0.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/commands/tool-builder.md +37 -0
- package/.claude/commands/ws-pull.md +44 -0
- package/.claude/settings.json +8 -0
- package/.claude/settings.local.json +49 -0
- package/.claude/skills/activity-api/SKILL.md +96 -0
- package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
- package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
- package/.claude/skills/agent-building/SKILL.md +243 -0
- package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
- package/.claude/skills/agent-building/references/code-examples.md +587 -0
- package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
- package/.claude/skills/app-api/SKILL.md +219 -0
- package/.claude/skills/app-api/references/app-endpoints.md +759 -0
- package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
- package/.claude/skills/create-app-skill/SKILL.md +1101 -0
- package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
- package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
- package/.claude/skills/hailer-api/SKILL.md +283 -0
- package/.claude/skills/hailer-api/references/activities.md +620 -0
- package/.claude/skills/hailer-api/references/authentication.md +216 -0
- package/.claude/skills/hailer-api/references/datasets.md +437 -0
- package/.claude/skills/hailer-api/references/files.md +301 -0
- package/.claude/skills/hailer-api/references/insights.md +469 -0
- package/.claude/skills/hailer-api/references/workflows.md +720 -0
- package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
- package/.claude/skills/insight-api/SKILL.md +185 -0
- package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
- package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
- package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
- package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
- package/.claude/skills/local-first-skill/SKILL.md +570 -0
- package/.claude/skills/mcp-tools/SKILL.md +419 -0
- package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
- package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
- package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
- package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
- package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
- package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
- package/.claude/skills/remove-app-skill/SKILL.md +985 -0
- package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
- package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
- package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
- package/.claude/skills/skill-testing/README.md +137 -0
- package/.claude/skills/skill-testing/SKILL.md +348 -0
- package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
- package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
- package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
- package/.claude/skills/tool-builder/SKILL.md +328 -0
- package/.claude/skills/update-app-skill/SKILL.md +970 -0
- package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
- package/.env.example +81 -0
- package/.mcp.json +13 -0
- package/README.md +297 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.js +74 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +5 -0
- package/dist/client/adaptive-documentation-bot.d.ts +108 -0
- package/dist/client/adaptive-documentation-bot.js +475 -0
- package/dist/client/adaptive-documentation-types.d.ts +66 -0
- package/dist/client/adaptive-documentation-types.js +9 -0
- package/dist/client/agent-activity-bot.d.ts +51 -0
- package/dist/client/agent-activity-bot.js +166 -0
- package/dist/client/agent-tracker.d.ts +499 -0
- package/dist/client/agent-tracker.js +659 -0
- package/dist/client/description-updater.d.ts +56 -0
- package/dist/client/description-updater.js +259 -0
- package/dist/client/log-parser.d.ts +72 -0
- package/dist/client/log-parser.js +387 -0
- package/dist/client/mcp-client.d.ts +50 -0
- package/dist/client/mcp-client.js +532 -0
- package/dist/client/message-processor.d.ts +35 -0
- package/dist/client/message-processor.js +352 -0
- package/dist/client/multi-bot-manager.d.ts +24 -0
- package/dist/client/multi-bot-manager.js +74 -0
- package/dist/client/providers/anthropic-provider.d.ts +19 -0
- package/dist/client/providers/anthropic-provider.js +631 -0
- package/dist/client/providers/llm-provider.d.ts +47 -0
- package/dist/client/providers/llm-provider.js +367 -0
- package/dist/client/providers/openai-provider.d.ts +23 -0
- package/dist/client/providers/openai-provider.js +621 -0
- package/dist/client/simple-llm-caller.d.ts +19 -0
- package/dist/client/simple-llm-caller.js +100 -0
- package/dist/client/skill-generator.d.ts +81 -0
- package/dist/client/skill-generator.js +386 -0
- package/dist/client/test-adaptive-bot.d.ts +9 -0
- package/dist/client/test-adaptive-bot.js +82 -0
- package/dist/client/token-pricing.d.ts +38 -0
- package/dist/client/token-pricing.js +127 -0
- package/dist/client/token-tracker.d.ts +232 -0
- package/dist/client/token-tracker.js +457 -0
- package/dist/client/token-usage-bot.d.ts +53 -0
- package/dist/client/token-usage-bot.js +153 -0
- package/dist/client/tool-executor.d.ts +69 -0
- package/dist/client/tool-executor.js +159 -0
- package/dist/client/tool-schema-loader.d.ts +60 -0
- package/dist/client/tool-schema-loader.js +178 -0
- package/dist/client/types.d.ts +69 -0
- package/dist/client/types.js +7 -0
- package/dist/config.d.ts +162 -0
- package/dist/config.js +296 -0
- package/dist/core.d.ts +26 -0
- package/dist/core.js +147 -0
- package/dist/lib/context-manager.d.ts +111 -0
- package/dist/lib/context-manager.js +431 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +277 -0
- package/dist/lib/materialize.d.ts +3 -0
- package/dist/lib/materialize.js +101 -0
- package/dist/lib/normalizedName.d.ts +7 -0
- package/dist/lib/normalizedName.js +48 -0
- package/dist/lib/prompt-length-manager.d.ts +81 -0
- package/dist/lib/prompt-length-manager.js +457 -0
- package/dist/lib/terminal-prompt.d.ts +9 -0
- package/dist/lib/terminal-prompt.js +108 -0
- package/dist/mcp/UserContextCache.d.ts +56 -0
- package/dist/mcp/UserContextCache.js +163 -0
- package/dist/mcp/auth.d.ts +2 -0
- package/dist/mcp/auth.js +29 -0
- package/dist/mcp/hailer-clients.d.ts +42 -0
- package/dist/mcp/hailer-clients.js +246 -0
- package/dist/mcp/signal-handler.d.ts +45 -0
- package/dist/mcp/signal-handler.js +317 -0
- package/dist/mcp/tool-registry.d.ts +100 -0
- package/dist/mcp/tool-registry.js +306 -0
- package/dist/mcp/tools/activity.d.ts +15 -0
- package/dist/mcp/tools/activity.js +955 -0
- package/dist/mcp/tools/app.d.ts +20 -0
- package/dist/mcp/tools/app.js +1488 -0
- package/dist/mcp/tools/discussion.d.ts +19 -0
- package/dist/mcp/tools/discussion.js +950 -0
- package/dist/mcp/tools/file.d.ts +15 -0
- package/dist/mcp/tools/file.js +119 -0
- package/dist/mcp/tools/insight.d.ts +17 -0
- package/dist/mcp/tools/insight.js +806 -0
- package/dist/mcp/tools/skill.d.ts +10 -0
- package/dist/mcp/tools/skill.js +279 -0
- package/dist/mcp/tools/user.d.ts +10 -0
- package/dist/mcp/tools/user.js +108 -0
- package/dist/mcp/tools/workflow-template.d.ts +19 -0
- package/dist/mcp/tools/workflow-template.js +822 -0
- package/dist/mcp/tools/workflow.d.ts +18 -0
- package/dist/mcp/tools/workflow.js +1362 -0
- package/dist/mcp/utils/api-errors.d.ts +45 -0
- package/dist/mcp/utils/api-errors.js +160 -0
- package/dist/mcp/utils/data-transformers.d.ts +102 -0
- package/dist/mcp/utils/data-transformers.js +194 -0
- package/dist/mcp/utils/file-upload.d.ts +33 -0
- package/dist/mcp/utils/file-upload.js +148 -0
- package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
- package/dist/mcp/utils/hailer-api-client.js +323 -0
- package/dist/mcp/utils/index.d.ts +13 -0
- package/dist/mcp/utils/index.js +39 -0
- package/dist/mcp/utils/logger.d.ts +42 -0
- package/dist/mcp/utils/logger.js +103 -0
- package/dist/mcp/utils/types.d.ts +286 -0
- package/dist/mcp/utils/types.js +7 -0
- package/dist/mcp/workspace-cache.d.ts +42 -0
- package/dist/mcp/workspace-cache.js +97 -0
- package/dist/mcp-server.d.ts +42 -0
- package/dist/mcp-server.js +280 -0
- package/package.json +56 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: local-first-skill
|
|
3
|
+
description: Complete guide to local-first data access - check workspace configs before API calls to save tokens and reduce latency
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Local-First Data Access Skill
|
|
7
|
+
|
|
8
|
+
Complete guide to using local workspace configurations before making API calls. This optimization saves 2-3 API calls per operation and hundreds of tokens by reading cached TypeScript files.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
- [Quick Reference](#quick-reference)
|
|
12
|
+
- [Overview](#overview)
|
|
13
|
+
- [Helper Functions](#helper-functions)
|
|
14
|
+
- [Decision Tree](#decision-tree)
|
|
15
|
+
- [Common Patterns](#common-patterns)
|
|
16
|
+
- [Benefits](#benefits)
|
|
17
|
+
- [Limitations](#limitations)
|
|
18
|
+
- [Best Practices](#best-practices)
|
|
19
|
+
- [Troubleshooting](#troubleshooting)
|
|
20
|
+
|
|
21
|
+
## Quick Reference
|
|
22
|
+
|
|
23
|
+
### Get workflows from local cache
|
|
24
|
+
```typescript
|
|
25
|
+
const workflows = await getLocalWorkflows() || await list_workflows();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Get field definitions from local cache
|
|
29
|
+
```typescript
|
|
30
|
+
const fields = await getLocalFields("Players") || await get_workflow_schema({...});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Get phases from local cache
|
|
34
|
+
```typescript
|
|
35
|
+
const phases = await getLocalPhases("Players") || await list_workflow_phases({...});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Get type-safe enums
|
|
39
|
+
```typescript
|
|
40
|
+
const enums = await getEnums();
|
|
41
|
+
console.log(enums.Players_FieldIds.player_name_694);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Overview
|
|
45
|
+
|
|
46
|
+
The local-first strategy caches workspace metadata (workflows, fields, phases) as TypeScript files that can be imported directly. This eliminates unnecessary API calls for data that rarely changes.
|
|
47
|
+
|
|
48
|
+
**What gets cached:**
|
|
49
|
+
- ✅ Workflow names, IDs, structure
|
|
50
|
+
- ✅ Field definitions (types, labels, keys, options)
|
|
51
|
+
- ✅ Phase definitions (names, IDs, transitions)
|
|
52
|
+
- ✅ Type-safe enums for field/phase IDs
|
|
53
|
+
|
|
54
|
+
**What doesn't get cached:**
|
|
55
|
+
- ❌ Activity data (always from API)
|
|
56
|
+
- ❌ Activity counts (always from API)
|
|
57
|
+
- ❌ Live status information
|
|
58
|
+
|
|
59
|
+
**Performance impact:**
|
|
60
|
+
- **Before**: 4 API calls to list activities (workflows → phases → schema → activities)
|
|
61
|
+
- **After**: 1 API call (activities only)
|
|
62
|
+
- **Savings**: 75% reduction in API calls + hundreds of tokens saved
|
|
63
|
+
|
|
64
|
+
## Helper Functions
|
|
65
|
+
|
|
66
|
+
Copy these functions to use local-first access:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const WORKSPACE_PATH = process.env.WORKSPACE_CONFIG_PATH || '/home/brodolf/Desktop/footballmanager';
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get all workflows from local cache
|
|
73
|
+
* Returns: Array of workflow objects with _id, name, folder properties
|
|
74
|
+
* Fallback: list_workflows() API call
|
|
75
|
+
*/
|
|
76
|
+
async function getLocalWorkflows() {
|
|
77
|
+
try {
|
|
78
|
+
const { workflows } = await import(`${WORKSPACE_PATH}/workspace/workflows.ts`);
|
|
79
|
+
return workflows;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.log('Local workflows not found, falling back to API');
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get field definitions for a workflow from local cache
|
|
88
|
+
* @param workflowName - Human-readable workflow name (e.g., "Players")
|
|
89
|
+
* Returns: Array of field objects with _id, key, label, type, data properties
|
|
90
|
+
* Fallback: get_workflow_schema() API call
|
|
91
|
+
*/
|
|
92
|
+
async function getLocalFields(workflowName: string) {
|
|
93
|
+
try {
|
|
94
|
+
const workflows = await getLocalWorkflows();
|
|
95
|
+
const workflow = workflows?.find(w => w.name === workflowName);
|
|
96
|
+
if (!workflow) {
|
|
97
|
+
console.log(`Workflow "${workflowName}" not found in local cache`);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { fields } = await import(`${WORKSPACE_PATH}/workspace/${workflow.folder}/fields.ts`);
|
|
102
|
+
return fields;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.log(`Fields for "${workflowName}" not found, falling back to API`);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get phase definitions for a workflow from local cache
|
|
111
|
+
* @param workflowName - Human-readable workflow name (e.g., "Players")
|
|
112
|
+
* Returns: Array of phase objects with _id, name, isInitial, possibleNextPhase properties
|
|
113
|
+
* Fallback: list_workflow_phases() API call
|
|
114
|
+
*/
|
|
115
|
+
async function getLocalPhases(workflowName: string) {
|
|
116
|
+
try {
|
|
117
|
+
const workflows = await getLocalWorkflows();
|
|
118
|
+
const workflow = workflows?.find(w => w.name === workflowName);
|
|
119
|
+
if (!workflow) {
|
|
120
|
+
console.log(`Workflow "${workflowName}" not found in local cache`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const { phases } = await import(`${WORKSPACE_PATH}/workspace/${workflow.folder}/phases.ts`);
|
|
125
|
+
return phases;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.log(`Phases for "${workflowName}" not found, falling back to API`);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get type-safe enums for all workflows
|
|
134
|
+
* Returns: Object with workflow-specific enum exports (e.g., Players_FieldIds, Players_PhaseIds)
|
|
135
|
+
* Use for type-safe field/phase ID access
|
|
136
|
+
*/
|
|
137
|
+
async function getEnums() {
|
|
138
|
+
try {
|
|
139
|
+
return await import(`${WORKSPACE_PATH}/workspace/enums.ts`);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.log('Enums not found in local cache');
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get workflow main config (permissions, order, etc.)
|
|
148
|
+
* @param workflowName - Human-readable workflow name
|
|
149
|
+
* Returns: Workflow configuration object
|
|
150
|
+
*/
|
|
151
|
+
async function getLocalWorkflowConfig(workflowName: string) {
|
|
152
|
+
try {
|
|
153
|
+
const workflows = await getLocalWorkflows();
|
|
154
|
+
const workflow = workflows?.find(w => w.name === workflowName);
|
|
155
|
+
if (!workflow) return null;
|
|
156
|
+
|
|
157
|
+
const { workflowConfig } = await import(`${WORKSPACE_PATH}/workspace/${workflow.folder}/main.ts`);
|
|
158
|
+
return workflowConfig;
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.log(`Config for "${workflowName}" not found`);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Decision Tree
|
|
167
|
+
|
|
168
|
+
Use this flowchart to decide local vs API:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
┌─────────────────────────────┐
|
|
172
|
+
│ What data do you need? │
|
|
173
|
+
└──────────┬──────────────────┘
|
|
174
|
+
│
|
|
175
|
+
├─> Workflow list (names, IDs, folders)
|
|
176
|
+
│ → getLocalWorkflows() || list_workflows()
|
|
177
|
+
│
|
|
178
|
+
├─> Field definitions (types, labels, keys)
|
|
179
|
+
│ → getLocalFields("WorkflowName") || get_workflow_schema()
|
|
180
|
+
│
|
|
181
|
+
├─> Phase definitions (names, transitions)
|
|
182
|
+
│ → getLocalPhases("WorkflowName") || list_workflow_phases()
|
|
183
|
+
│
|
|
184
|
+
├─> Type-safe field/phase IDs
|
|
185
|
+
│ → getEnums()
|
|
186
|
+
│
|
|
187
|
+
└─> Activity data (records, counts, live values)
|
|
188
|
+
→ ALWAYS use API (list_activities, show_activity_by_id)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Common Patterns
|
|
192
|
+
|
|
193
|
+
### Pattern 1: List Activities in a Workflow
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// ❌ BAD - Makes 4 API calls
|
|
197
|
+
const workflows = await list_workflows();
|
|
198
|
+
const playersWorkflow = workflows.find(w => w.name === "Players");
|
|
199
|
+
const phases = await list_workflow_phases({ workflowId: playersWorkflow._id });
|
|
200
|
+
const schema = await get_workflow_schema({ workflowId: playersWorkflow._id, phaseId: phases[0]._id });
|
|
201
|
+
const activities = await list_activities({ workflowId: playersWorkflow._id, phaseId: phases[0]._id, fields: [...] });
|
|
202
|
+
|
|
203
|
+
// ✅ GOOD - Makes 1 API call
|
|
204
|
+
const workflows = await getLocalWorkflows();
|
|
205
|
+
const playersWorkflow = workflows.find(w => w.name === "Players");
|
|
206
|
+
const phases = await getLocalPhases("Players");
|
|
207
|
+
const fields = await getLocalFields("Players");
|
|
208
|
+
const activities = await list_activities({
|
|
209
|
+
workflowId: playersWorkflow._id,
|
|
210
|
+
phaseId: phases[0]._id,
|
|
211
|
+
fields: fields.slice(0, 5).map(f => f.key)
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Savings**: 3 fewer API calls, ~500-1000 tokens saved
|
|
216
|
+
|
|
217
|
+
### Pattern 2: Create Activity with Proper Field IDs
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// ❌ BAD - Hardcoded field IDs (breaks if schema changes)
|
|
221
|
+
await create_activity({
|
|
222
|
+
workflowId: "691ffdf84217e9e8434e5693",
|
|
223
|
+
fields: {
|
|
224
|
+
"691ffdf84217e9e8434e5694": "Bruno Fernandes",
|
|
225
|
+
"691ffdf84217e9e8434e5695": 8
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// ✅ GOOD - Use local cache to get field keys
|
|
230
|
+
const fields = await getLocalFields("Players");
|
|
231
|
+
const playerNameField = fields.find(f => f.label === "Player Name");
|
|
232
|
+
const jerseyField = fields.find(f => f.label === "Jersey Number");
|
|
233
|
+
|
|
234
|
+
await create_activity({
|
|
235
|
+
workflowId: "691ffdf84217e9e8434e5693",
|
|
236
|
+
fields: {
|
|
237
|
+
[playerNameField.key]: "Bruno Fernandes",
|
|
238
|
+
[jerseyField.key]: 8
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// ✅ BEST - Use key property directly (if fields have keys)
|
|
243
|
+
await create_activity({
|
|
244
|
+
workflowId: "691ffdf84217e9e8434e5693",
|
|
245
|
+
fields: {
|
|
246
|
+
playerName: "Bruno Fernandes",
|
|
247
|
+
jerseyNumber: 8
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Pattern 3: Type-Safe Field Access with Enums
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// ✅ EXCELLENT - Type-safe with enums
|
|
256
|
+
const enums = await getEnums();
|
|
257
|
+
const fields = await getLocalFields("Players");
|
|
258
|
+
|
|
259
|
+
// Access field by enum (autocomplete + compile-time safety)
|
|
260
|
+
const playerNameFieldId = enums.Players_FieldIds.player_name_694;
|
|
261
|
+
const activeSquadPhaseId = enums.Players_PhaseIds.active_squad_69f;
|
|
262
|
+
|
|
263
|
+
await list_activities({
|
|
264
|
+
workflowId: "691ffdf84217e9e8434e5693",
|
|
265
|
+
phaseId: activeSquadPhaseId,
|
|
266
|
+
fields: [
|
|
267
|
+
enums.Players_FieldIds.player_name_694,
|
|
268
|
+
enums.Players_FieldIds.jersey_number_695,
|
|
269
|
+
enums.Players_FieldIds.position_696
|
|
270
|
+
]
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Pattern 4: Bulk Operations with Field Validation
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// ✅ GOOD - Validate field types before bulk create
|
|
278
|
+
const fields = await getLocalFields("Players");
|
|
279
|
+
const positionField = fields.find(f => f.key === "position");
|
|
280
|
+
const validPositions = positionField.data; // ["Goalkeeper", "Defender", "Midfielder", "Forward"]
|
|
281
|
+
|
|
282
|
+
// Validate before creating
|
|
283
|
+
const players = [
|
|
284
|
+
{ name: "Player 1", position: "Midfielder" }, // ✅ Valid
|
|
285
|
+
{ name: "Player 2", position: "Striker" } // ❌ Invalid - will fail!
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
// Pre-validate
|
|
289
|
+
players.forEach(p => {
|
|
290
|
+
if (!validPositions.includes(p.position)) {
|
|
291
|
+
console.error(`Invalid position: ${p.position}. Valid: ${validPositions.join(", ")}`);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Then bulk create
|
|
296
|
+
await create_activity({
|
|
297
|
+
workflowId: "xxx",
|
|
298
|
+
activities: players.map(p => ({
|
|
299
|
+
name: p.name,
|
|
300
|
+
fields: { position: p.position }
|
|
301
|
+
}))
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Benefits
|
|
306
|
+
|
|
307
|
+
### 1. Performance Improvement
|
|
308
|
+
|
|
309
|
+
| Operation | API Calls (Before) | API Calls (After) | Improvement |
|
|
310
|
+
|-----------|-------------------|-------------------|-------------|
|
|
311
|
+
| List activities | 4 | 1 | 75% faster |
|
|
312
|
+
| Create activity with validation | 3 | 0 + 1 | 66% faster |
|
|
313
|
+
| Update activity field | 2 | 0 + 1 | 50% faster |
|
|
314
|
+
| Bulk operations | N × 3 | 0 + 1 | 90%+ faster |
|
|
315
|
+
|
|
316
|
+
### 2. Token Savings
|
|
317
|
+
|
|
318
|
+
- Workflow list: ~200-500 tokens saved
|
|
319
|
+
- Field schema: ~300-800 tokens saved
|
|
320
|
+
- Phase definitions: ~100-300 tokens saved
|
|
321
|
+
- **Total per operation**: 600-1600 tokens saved
|
|
322
|
+
|
|
323
|
+
### 3. Offline Capability
|
|
324
|
+
|
|
325
|
+
Work with workflow structure without network:
|
|
326
|
+
- Browse field definitions
|
|
327
|
+
- Understand phase transitions
|
|
328
|
+
- Validate data against schemas
|
|
329
|
+
- Generate code with type-safe IDs
|
|
330
|
+
|
|
331
|
+
### 4. Type Safety
|
|
332
|
+
|
|
333
|
+
Enums provide compile-time safety:
|
|
334
|
+
```typescript
|
|
335
|
+
// TypeScript knows these exist and autocompletes!
|
|
336
|
+
Players_FieldIds.player_name_694
|
|
337
|
+
Players_PhaseIds.active_squad_69f
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Limitations
|
|
341
|
+
|
|
342
|
+
### 1. Stale Data Risk
|
|
343
|
+
|
|
344
|
+
**Problem**: Local cache doesn't update automatically when workspace changes.
|
|
345
|
+
|
|
346
|
+
**Solution**: Re-run `/ws-pull` after schema changes:
|
|
347
|
+
```bash
|
|
348
|
+
/ws-pull # or: npm run ws-pull
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**When to refresh:**
|
|
352
|
+
- After adding/removing workflows
|
|
353
|
+
- After adding/removing fields
|
|
354
|
+
- After modifying field types/options
|
|
355
|
+
- After adding/removing phases
|
|
356
|
+
|
|
357
|
+
### 2. No Activity Data
|
|
358
|
+
|
|
359
|
+
**Problem**: Local cache has no activity records or counts.
|
|
360
|
+
|
|
361
|
+
**Solution**: Always use API for activity operations:
|
|
362
|
+
- `list_activities()` - Get activities
|
|
363
|
+
- `show_activity_by_id()` - Get single activity
|
|
364
|
+
- `create_activity()` - Create activities
|
|
365
|
+
- `update_activity()` - Update activities
|
|
366
|
+
|
|
367
|
+
### 3. No Live Counts
|
|
368
|
+
|
|
369
|
+
**Problem**: Workflow activity counts in local cache are outdated.
|
|
370
|
+
|
|
371
|
+
**Solution**: Call `list_workflows()` API if you need current counts.
|
|
372
|
+
|
|
373
|
+
## Best Practices
|
|
374
|
+
|
|
375
|
+
### ✅ Do This
|
|
376
|
+
|
|
377
|
+
1. **Always try local first**
|
|
378
|
+
```typescript
|
|
379
|
+
const data = await getLocalData() || await apiCall();
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
2. **Use meaningful workflow names**
|
|
383
|
+
```typescript
|
|
384
|
+
// ✅ Good - readable
|
|
385
|
+
await getLocalFields("Players")
|
|
386
|
+
|
|
387
|
+
// ❌ Bad - requires ID lookup
|
|
388
|
+
await get_workflow_schema({ workflowId: "691..." })
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
3. **Cache helper results if used multiple times**
|
|
392
|
+
```typescript
|
|
393
|
+
const workflows = await getLocalWorkflows();
|
|
394
|
+
// Use workflows multiple times without re-importing
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
4. **Run `/ws-pull` regularly**
|
|
398
|
+
- Daily for active development
|
|
399
|
+
- After schema changes
|
|
400
|
+
- When starting new features
|
|
401
|
+
|
|
402
|
+
5. **Use enums for type safety**
|
|
403
|
+
```typescript
|
|
404
|
+
const enums = await getEnums();
|
|
405
|
+
// Use enums.Players_FieldIds.* everywhere
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### ❌ Avoid This
|
|
409
|
+
|
|
410
|
+
1. **Don't skip local check**
|
|
411
|
+
```typescript
|
|
412
|
+
// ❌ BAD
|
|
413
|
+
const workflows = await list_workflows();
|
|
414
|
+
|
|
415
|
+
// ✅ GOOD
|
|
416
|
+
const workflows = await getLocalWorkflows() || await list_workflows();
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
2. **Don't use local cache for activity data**
|
|
420
|
+
```typescript
|
|
421
|
+
// ❌ WRONG - activities not in local cache!
|
|
422
|
+
const activities = await getLocalActivities("Players");
|
|
423
|
+
|
|
424
|
+
// ✅ CORRECT
|
|
425
|
+
const activities = await list_activities({...});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
3. **Don't forget to fallback to API**
|
|
429
|
+
```typescript
|
|
430
|
+
// ❌ BAD - fails if cache missing
|
|
431
|
+
const workflows = await getLocalWorkflows();
|
|
432
|
+
|
|
433
|
+
// ✅ GOOD - graceful fallback
|
|
434
|
+
const workflows = await getLocalWorkflows() || await list_workflows();
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
4. **Don't use outdated cache without warning**
|
|
438
|
+
```typescript
|
|
439
|
+
// ✅ GOOD - Check timestamp
|
|
440
|
+
const cacheAge = Date.now() - fs.statSync(`${WORKSPACE_PATH}/workspace/workflows.ts`).mtimeMs;
|
|
441
|
+
if (cacheAge > 24 * 60 * 60 * 1000) {
|
|
442
|
+
console.warn('Local cache is >24h old. Consider running /ws-pull');
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
## Troubleshooting
|
|
447
|
+
|
|
448
|
+
### Issue: "Cannot find module" error
|
|
449
|
+
|
|
450
|
+
**Symptom:**
|
|
451
|
+
```
|
|
452
|
+
Error: Cannot find module '/path/to/workspace/workflows.ts'
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Cause**: Local cache doesn't exist or path is wrong.
|
|
456
|
+
|
|
457
|
+
**Solutions:**
|
|
458
|
+
1. Run `/ws-pull` to download configs
|
|
459
|
+
2. Check `WORKSPACE_CONFIG_PATH` in `.env.local`
|
|
460
|
+
3. Verify path exists: `ls $WORKSPACE_CONFIG_PATH/workspace/`
|
|
461
|
+
|
|
462
|
+
### Issue: Workflow not found by name
|
|
463
|
+
|
|
464
|
+
**Symptom:**
|
|
465
|
+
```typescript
|
|
466
|
+
const fields = await getLocalFields("Players"); // Returns null
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**Cause**: Workflow name doesn't match exactly.
|
|
470
|
+
|
|
471
|
+
**Solutions:**
|
|
472
|
+
1. Check exact spelling/capitalization
|
|
473
|
+
2. List available workflows:
|
|
474
|
+
```typescript
|
|
475
|
+
const workflows = await getLocalWorkflows();
|
|
476
|
+
console.log(workflows.map(w => w.name));
|
|
477
|
+
```
|
|
478
|
+
3. Use workflow ID directly if name is ambiguous
|
|
479
|
+
|
|
480
|
+
### Issue: Field/phase data seems outdated
|
|
481
|
+
|
|
482
|
+
**Symptom**: Local data doesn't match what's in Hailer.
|
|
483
|
+
|
|
484
|
+
**Cause**: Cache is stale (workspace was modified).
|
|
485
|
+
|
|
486
|
+
**Solutions:**
|
|
487
|
+
1. Re-run `/ws-pull` to refresh
|
|
488
|
+
2. Compare timestamps:
|
|
489
|
+
```bash
|
|
490
|
+
ls -la $WORKSPACE_CONFIG_PATH/workspace/
|
|
491
|
+
```
|
|
492
|
+
3. For critical operations, use API directly
|
|
493
|
+
|
|
494
|
+
### Issue: Import fails in production
|
|
495
|
+
|
|
496
|
+
**Symptom**: Works locally but fails in deployed environment.
|
|
497
|
+
|
|
498
|
+
**Cause**: Workspace configs not deployed or path incorrect.
|
|
499
|
+
|
|
500
|
+
**Solutions:**
|
|
501
|
+
1. Ensure `WORKSPACE_CONFIG_PATH` is set correctly in production
|
|
502
|
+
2. Copy workspace configs to production environment
|
|
503
|
+
3. Use API fallback for production reliability
|
|
504
|
+
|
|
505
|
+
### Issue: Type errors with enums
|
|
506
|
+
|
|
507
|
+
**Symptom:**
|
|
508
|
+
```typescript
|
|
509
|
+
const enums = await getEnums();
|
|
510
|
+
enums.Players_FieldIds.player_name_694; // Type error
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**Cause**: TypeScript doesn't recognize dynamic imports.
|
|
514
|
+
|
|
515
|
+
**Solutions:**
|
|
516
|
+
1. Use type assertion:
|
|
517
|
+
```typescript
|
|
518
|
+
const enums = await getEnums() as any;
|
|
519
|
+
```
|
|
520
|
+
2. Or use direct imports (static):
|
|
521
|
+
```typescript
|
|
522
|
+
import { Players_FieldIds } from './workspace/enums';
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
## Integration with MCP Tools
|
|
526
|
+
|
|
527
|
+
### When to use local-first with each tool:
|
|
528
|
+
|
|
529
|
+
| Tool | Local First? | Notes |
|
|
530
|
+
|------|-------------|-------|
|
|
531
|
+
| `list_workflows` | ✅ Yes | Use `getLocalWorkflows()` |
|
|
532
|
+
| `list_workflow_phases` | ✅ Yes | Use `getLocalPhases()` |
|
|
533
|
+
| `get_workflow_schema` | ✅ Yes | Use `getLocalFields()` |
|
|
534
|
+
| `list_activities` | ❌ No | Always API |
|
|
535
|
+
| `show_activity_by_id` | ❌ No | Always API |
|
|
536
|
+
| `create_activity` | Validate with local | Get field types for validation |
|
|
537
|
+
| `update_activity` | Validate with local | Check field types before update |
|
|
538
|
+
| `update_workflow_field` | Check local first | Know current state before update |
|
|
539
|
+
|
|
540
|
+
## Summary
|
|
541
|
+
|
|
542
|
+
**Key Takeaway**: Always check local cache before API calls for workflow metadata.
|
|
543
|
+
|
|
544
|
+
**Pattern to remember:**
|
|
545
|
+
```typescript
|
|
546
|
+
const data = await getLocalData() || await apiCall();
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Benefits:**
|
|
550
|
+
- 75% fewer API calls
|
|
551
|
+
- 600-1600 tokens saved per operation
|
|
552
|
+
- Faster response times
|
|
553
|
+
- Offline-capable development
|
|
554
|
+
- Type-safe field/phase access
|
|
555
|
+
|
|
556
|
+
**Next steps:**
|
|
557
|
+
1. Run `/ws-pull` to set up local cache
|
|
558
|
+
2. Copy helper functions into your code
|
|
559
|
+
3. Replace direct API calls with local-first pattern
|
|
560
|
+
4. Use enums for type-safe IDs
|
|
561
|
+
5. Refresh cache regularly
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
**Related Skills:**
|
|
566
|
+
- `list-workflows-minimal-skill` - Minimal API calls for workflow listing
|
|
567
|
+
- `install-workflow-skill` - Creating workflows (uses local patterns)
|
|
568
|
+
- `update-workflow-field-skill` - Modifying fields (validate with local data)
|
|
569
|
+
|
|
570
|
+
**Last Updated**: 2025-11-24
|