@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
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code PreToolUse Hook - Source Code Edit Guard
|
|
4
|
+
*
|
|
5
|
+
* Blocks direct edits to src/ directory files.
|
|
6
|
+
* Forces the main agent to spawn subagents for code changes.
|
|
7
|
+
* This saves context in the main agent for orchestration.
|
|
8
|
+
*
|
|
9
|
+
* Edits are ONLY allowed when:
|
|
10
|
+
* - Running inside a subagent (builder mode active)
|
|
11
|
+
* - File is outside src/ directory
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
// UNIFIED: Use same builder mode file as app-edit-guard.cjs
|
|
18
|
+
const BUILDER_MODE_FILE = '/tmp/.claude-builder-agent-active';
|
|
19
|
+
|
|
20
|
+
// Read hook input from stdin
|
|
21
|
+
let input = '';
|
|
22
|
+
process.stdin.setEncoding('utf8');
|
|
23
|
+
process.stdin.on('data', chunk => input += chunk);
|
|
24
|
+
process.stdin.on('end', () => {
|
|
25
|
+
try {
|
|
26
|
+
const data = JSON.parse(input);
|
|
27
|
+
processHook(data);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
// Invalid JSON - allow to avoid blocking legitimate operations
|
|
30
|
+
outputAllow();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function outputAllow() {
|
|
35
|
+
console.log(JSON.stringify({ decision: 'allow' }));
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function outputBlock(message) {
|
|
40
|
+
console.log(JSON.stringify({
|
|
41
|
+
decision: 'block',
|
|
42
|
+
reason: message
|
|
43
|
+
}));
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if builder mode is active (subagent editing)
|
|
49
|
+
*/
|
|
50
|
+
function isBuilderModeActive() {
|
|
51
|
+
try {
|
|
52
|
+
return fs.existsSync(BUILDER_MODE_FILE);
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Enable builder mode
|
|
60
|
+
*/
|
|
61
|
+
function enableBuilderMode() {
|
|
62
|
+
fs.writeFileSync(BUILDER_MODE_FILE, JSON.stringify({
|
|
63
|
+
enabledAt: new Date().toISOString(),
|
|
64
|
+
pid: process.pid
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Disable builder mode
|
|
70
|
+
*/
|
|
71
|
+
function disableBuilderMode() {
|
|
72
|
+
if (fs.existsSync(BUILDER_MODE_FILE)) {
|
|
73
|
+
fs.unlinkSync(BUILDER_MODE_FILE);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function processHook(data) {
|
|
80
|
+
const { tool_name, tool_input } = data;
|
|
81
|
+
|
|
82
|
+
// Only guard Write and Edit tools
|
|
83
|
+
if (tool_name !== 'Write' && tool_name !== 'Edit') {
|
|
84
|
+
outputAllow();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const filePath = tool_input?.file_path;
|
|
89
|
+
if (!filePath) {
|
|
90
|
+
outputAllow();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Normalize and get relative path
|
|
95
|
+
const normalizedPath = path.resolve(filePath);
|
|
96
|
+
const projectRoot = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
97
|
+
const relativePath = path.relative(projectRoot, normalizedPath);
|
|
98
|
+
|
|
99
|
+
// Check if file is in src/ directory
|
|
100
|
+
const isInSrc = relativePath.startsWith('src/') || relativePath.startsWith('src\\');
|
|
101
|
+
|
|
102
|
+
if (!isInSrc) {
|
|
103
|
+
// Not in src/ directory - allow
|
|
104
|
+
outputAllow();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check if builder mode is active - ALLOW
|
|
109
|
+
if (isBuilderModeActive()) {
|
|
110
|
+
outputAllow();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// BLOCK with helpful message
|
|
115
|
+
outputBlock(`
|
|
116
|
+
🚫 BLOCKED: Direct edit to source file
|
|
117
|
+
|
|
118
|
+
File: ${relativePath}
|
|
119
|
+
|
|
120
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
121
|
+
WHY: Use a subagent to save your context for orchestration
|
|
122
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
123
|
+
|
|
124
|
+
TO PROCEED: Spawn a general-purpose agent with detailed instructions:
|
|
125
|
+
|
|
126
|
+
Task({
|
|
127
|
+
subagent_type: "general-purpose",
|
|
128
|
+
description: "Fix issue #XX",
|
|
129
|
+
prompt: \`
|
|
130
|
+
[Detailed instructions for the change]
|
|
131
|
+
|
|
132
|
+
File to modify: ${relativePath}
|
|
133
|
+
|
|
134
|
+
[Explain what to change and why]
|
|
135
|
+
\`
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
The agent will:
|
|
139
|
+
1. Make the code changes
|
|
140
|
+
2. Verify the build passes
|
|
141
|
+
3. Report back results
|
|
142
|
+
|
|
143
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
144
|
+
OR: Enable builder mode temporarily (if you need to edit directly)
|
|
145
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
146
|
+
|
|
147
|
+
Bash: node .claude/hooks/src-edit-guard.cjs --on
|
|
148
|
+
[Make your edits]
|
|
149
|
+
Bash: node .claude/hooks/src-edit-guard.cjs --off
|
|
150
|
+
`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// CLI: Enable builder mode
|
|
154
|
+
if (process.argv[2] === '--on') {
|
|
155
|
+
enableBuilderMode();
|
|
156
|
+
console.log('🔧 Builder mode ENABLED - src/ edits now allowed');
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// CLI: Disable builder mode
|
|
161
|
+
if (process.argv[2] === '--off') {
|
|
162
|
+
if (disableBuilderMode()) {
|
|
163
|
+
console.log('🔒 Builder mode DISABLED - src/ edits blocked again');
|
|
164
|
+
} else {
|
|
165
|
+
console.log('ℹ️ Builder mode was not active');
|
|
166
|
+
}
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// CLI: Check status
|
|
171
|
+
if (process.argv[2] === '--status') {
|
|
172
|
+
if (isBuilderModeActive()) {
|
|
173
|
+
const data = JSON.parse(fs.readFileSync(BUILDER_MODE_FILE, 'utf8'));
|
|
174
|
+
console.log(`🔧 Builder mode is ACTIVE (enabled at ${data.enabledAt})`);
|
|
175
|
+
} else {
|
|
176
|
+
console.log('🔒 Builder mode is OFF - src/ edits are blocked');
|
|
177
|
+
}
|
|
178
|
+
process.exit(0);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// CLI: Help
|
|
182
|
+
if (process.argv[2] === '--help' || process.argv[2] === '-h') {
|
|
183
|
+
console.log(`
|
|
184
|
+
Source Code Edit Guard - Blocks direct edits to src/ directory
|
|
185
|
+
|
|
186
|
+
Usage:
|
|
187
|
+
node src-edit-guard.cjs --on Enable builder mode (allow edits)
|
|
188
|
+
node src-edit-guard.cjs --off Disable builder mode (block edits)
|
|
189
|
+
node src-edit-guard.cjs --status Check current mode
|
|
190
|
+
node src-edit-guard.cjs --help Show this help
|
|
191
|
+
|
|
192
|
+
UNIFIED SYSTEM: This hook uses the same builder mode file as app-edit-guard.cjs.
|
|
193
|
+
Enabling builder mode here also enables it for Hailer app edits, and vice versa.
|
|
194
|
+
|
|
195
|
+
Preferred commands (via app-edit-guard.cjs):
|
|
196
|
+
node app-edit-guard.cjs --agent-on Enable global builder mode
|
|
197
|
+
node app-edit-guard.cjs --agent-off Disable global builder mode
|
|
198
|
+
|
|
199
|
+
As a hook:
|
|
200
|
+
Reads JSON from stdin with tool_name and tool_input
|
|
201
|
+
Outputs JSON with decision: "allow" or "block"
|
|
202
|
+
|
|
203
|
+
Purpose:
|
|
204
|
+
Forces the main Claude agent to spawn subagents for code changes.
|
|
205
|
+
This saves context in the main agent for orchestration tasks.
|
|
206
|
+
`);
|
|
207
|
+
process.exit(0);
|
|
208
|
+
}
|
package/.claude/settings.json
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"hooks": [
|
|
15
15
|
{
|
|
16
16
|
"type": "command",
|
|
17
|
-
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/
|
|
18
|
-
"timeout":
|
|
17
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/interactive-mode.cjs\"",
|
|
18
|
+
"timeout": 5
|
|
19
19
|
}
|
|
20
20
|
]
|
|
21
21
|
}
|
|
@@ -28,6 +28,11 @@
|
|
|
28
28
|
"type": "command",
|
|
29
29
|
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/sdk-delete-guard.cjs\"",
|
|
30
30
|
"timeout": 5
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/mcp-server-guard.cjs\"",
|
|
35
|
+
"timeout": 5
|
|
31
36
|
}
|
|
32
37
|
]
|
|
33
38
|
},
|
|
@@ -40,6 +45,36 @@
|
|
|
40
45
|
"timeout": 5
|
|
41
46
|
}
|
|
42
47
|
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"matcher": "Write",
|
|
51
|
+
"hooks": [
|
|
52
|
+
{
|
|
53
|
+
"type": "command",
|
|
54
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/app-edit-guard.cjs\"",
|
|
55
|
+
"timeout": 5
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "command",
|
|
59
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/src-edit-guard.cjs\"",
|
|
60
|
+
"timeout": 5
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"matcher": "Edit",
|
|
66
|
+
"hooks": [
|
|
67
|
+
{
|
|
68
|
+
"type": "command",
|
|
69
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/app-edit-guard.cjs\"",
|
|
70
|
+
"timeout": 5
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"type": "command",
|
|
74
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/src-edit-guard.cjs\"",
|
|
75
|
+
"timeout": 5
|
|
76
|
+
}
|
|
77
|
+
]
|
|
43
78
|
}
|
|
44
79
|
],
|
|
45
80
|
"PostToolUse": [
|
|
@@ -52,6 +87,16 @@
|
|
|
52
87
|
"timeout": 5
|
|
53
88
|
}
|
|
54
89
|
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"matcher": "Task",
|
|
93
|
+
"hooks": [
|
|
94
|
+
{
|
|
95
|
+
"type": "command",
|
|
96
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/agent-failure-detector.cjs\"",
|
|
97
|
+
"timeout": 5
|
|
98
|
+
}
|
|
99
|
+
]
|
|
55
100
|
}
|
|
56
101
|
]
|
|
57
102
|
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Insight JOIN Patterns
|
|
2
|
+
|
|
3
|
+
## Pattern
|
|
4
|
+
When joining workflows with ActivityLink fields in Hailer insights, you must:
|
|
5
|
+
1. Include `_id` meta field in BOTH source definitions
|
|
6
|
+
2. Join ON the activitylink field value equals target _id
|
|
7
|
+
3. Use the activitylink fieldId (NOT the key) for the JOIN condition
|
|
8
|
+
|
|
9
|
+
## Critical Rules
|
|
10
|
+
|
|
11
|
+
**Always Required:**
|
|
12
|
+
- Both workflows need `{ name: 'id', meta: '_id' }` in their fields array
|
|
13
|
+
- JOIN condition: `source1.activityLinkFieldName = source2.id`
|
|
14
|
+
- Use LEFT JOIN for optional relationships (activitylink can be null)
|
|
15
|
+
- Use INNER JOIN only when relationship must exist
|
|
16
|
+
|
|
17
|
+
## Correct Examples
|
|
18
|
+
|
|
19
|
+
### Basic ActivityLink JOIN
|
|
20
|
+
```javascript
|
|
21
|
+
// Players workflow has "club" field (activitylink to Clubs workflow)
|
|
22
|
+
{
|
|
23
|
+
sources: [
|
|
24
|
+
{
|
|
25
|
+
name: 'p',
|
|
26
|
+
workflowId: '68446dc05b30685f67c6fcd4',
|
|
27
|
+
fields: [
|
|
28
|
+
{ name: 'player_name', meta: 'name' },
|
|
29
|
+
{ name: 'id', meta: '_id' }, // Required!
|
|
30
|
+
{ name: 'club', fieldId: '684d5e45...' } // ActivityLink field
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'c',
|
|
35
|
+
workflowId: '691ea936ccb6bdeebc0cbf77',
|
|
36
|
+
fields: [
|
|
37
|
+
{ name: 'club_name', meta: 'name' },
|
|
38
|
+
{ name: 'id', meta: '_id' } // Required!
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
query: 'SELECT p.player_name, c.club_name FROM p LEFT JOIN c ON p.club = c.id'
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Three-Way JOIN (Tasks -> Topics -> Projects)
|
|
47
|
+
```javascript
|
|
48
|
+
{
|
|
49
|
+
sources: [
|
|
50
|
+
{
|
|
51
|
+
name: 't',
|
|
52
|
+
workflowId: 'tasks-workflow-id',
|
|
53
|
+
fields: [
|
|
54
|
+
{ name: 'task_name', meta: 'name' },
|
|
55
|
+
{ name: 'id', meta: '_id' },
|
|
56
|
+
{ name: 'topic', fieldId: 'topic-field-id' } // Links to Topics
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'top',
|
|
61
|
+
workflowId: 'topics-workflow-id',
|
|
62
|
+
fields: [
|
|
63
|
+
{ name: 'topic_name', meta: 'name' },
|
|
64
|
+
{ name: 'id', meta: '_id' },
|
|
65
|
+
{ name: 'project', fieldId: 'project-field-id' } // Links to Projects
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'p',
|
|
70
|
+
workflowId: 'projects-workflow-id',
|
|
71
|
+
fields: [
|
|
72
|
+
{ name: 'project_name', meta: 'name' },
|
|
73
|
+
{ name: 'id', meta: '_id' }
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
query: `
|
|
78
|
+
SELECT
|
|
79
|
+
t.task_name,
|
|
80
|
+
top.topic_name,
|
|
81
|
+
p.project_name
|
|
82
|
+
FROM t
|
|
83
|
+
LEFT JOIN top ON t.topic = top.id
|
|
84
|
+
LEFT JOIN p ON top.project = p.id
|
|
85
|
+
`
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Aggregation with JOIN
|
|
90
|
+
```javascript
|
|
91
|
+
{
|
|
92
|
+
sources: [
|
|
93
|
+
{
|
|
94
|
+
name: 'matches',
|
|
95
|
+
workflowId: 'matches-workflow-id',
|
|
96
|
+
fields: [
|
|
97
|
+
{ name: 'match_date', fieldId: 'date-field-id' },
|
|
98
|
+
{ name: 'id', meta: '_id' },
|
|
99
|
+
{ name: 'home_team', fieldId: 'home-team-field-id' }
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'teams',
|
|
104
|
+
workflowId: 'teams-workflow-id',
|
|
105
|
+
fields: [
|
|
106
|
+
{ name: 'team_name', meta: 'name' },
|
|
107
|
+
{ name: 'id', meta: '_id' }
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
query: `
|
|
112
|
+
SELECT
|
|
113
|
+
teams.team_name,
|
|
114
|
+
COUNT(*) as match_count
|
|
115
|
+
FROM matches
|
|
116
|
+
LEFT JOIN teams ON matches.home_team = teams.id
|
|
117
|
+
GROUP BY teams.team_name
|
|
118
|
+
`
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Wrong Examples
|
|
123
|
+
|
|
124
|
+
### Missing _id Field
|
|
125
|
+
```javascript
|
|
126
|
+
// ❌ WRONG - Missing _id in clubs source
|
|
127
|
+
{
|
|
128
|
+
sources: [
|
|
129
|
+
{
|
|
130
|
+
name: 'p',
|
|
131
|
+
workflowId: 'players-id',
|
|
132
|
+
fields: [
|
|
133
|
+
{ name: 'player_name', meta: 'name' },
|
|
134
|
+
{ name: 'id', meta: '_id' },
|
|
135
|
+
{ name: 'club', fieldId: 'club-field-id' }
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'c',
|
|
140
|
+
workflowId: 'clubs-id',
|
|
141
|
+
fields: [
|
|
142
|
+
{ name: 'club_name', meta: 'name' }
|
|
143
|
+
// Missing: { name: 'id', meta: '_id' }
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
query: 'SELECT p.player_name, c.club_name FROM p LEFT JOIN c ON p.club = c.id'
|
|
148
|
+
}
|
|
149
|
+
// Error: "no such column: c.id"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Using Key Instead of FieldId
|
|
153
|
+
```javascript
|
|
154
|
+
// ❌ WRONG - Using field key instead of fieldId
|
|
155
|
+
{
|
|
156
|
+
sources: [
|
|
157
|
+
{
|
|
158
|
+
name: 'p',
|
|
159
|
+
workflowId: 'players-id',
|
|
160
|
+
fields: [
|
|
161
|
+
{ name: 'player_name', meta: 'name' },
|
|
162
|
+
{ name: 'id', meta: '_id' },
|
|
163
|
+
{ name: 'club', key: 'club' } // Wrong! Use fieldId
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Wrong JOIN Syntax
|
|
171
|
+
```javascript
|
|
172
|
+
// ❌ WRONG - Trying to join on name instead of id
|
|
173
|
+
query: 'SELECT p.player_name, c.club_name FROM p LEFT JOIN c ON p.club = c.club_name'
|
|
174
|
+
|
|
175
|
+
// ❌ WRONG - Using field key in JOIN instead of column name
|
|
176
|
+
query: 'SELECT p.player_name, c.club_name FROM p LEFT JOIN c ON p.clubId = c.id'
|
|
177
|
+
// (Should use column name from sources definition: p.club = c.id)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Troubleshooting
|
|
181
|
+
|
|
182
|
+
**Error: "no such column: c.id"**
|
|
183
|
+
- Missing `{ name: 'id', meta: '_id' }` in target workflow source
|
|
184
|
+
|
|
185
|
+
**Error: "no such column: p.club"**
|
|
186
|
+
- ActivityLink field not included in source fields array
|
|
187
|
+
- Check you used correct fieldId from `get_workflow_schema`
|
|
188
|
+
|
|
189
|
+
**NULL results for joined data**
|
|
190
|
+
- ActivityLink field is empty/null for some activities (expected with LEFT JOIN)
|
|
191
|
+
- Use INNER JOIN if you only want activities with relationships
|
|
192
|
+
|
|
193
|
+
## Workflow
|
|
194
|
+
|
|
195
|
+
1. Get schema: `get_workflow_schema({ workflowId, phaseId })`
|
|
196
|
+
2. Find ActivityLink field ID and target workflow ID
|
|
197
|
+
3. Build sources with BOTH _id fields
|
|
198
|
+
4. Preview query: `preview_insight({ sources, query })`
|
|
199
|
+
5. Fix errors, re-preview
|
|
200
|
+
6. Create insight when preview succeeds
|
|
201
|
+
|
|
202
|
+
## Quick Checklist
|
|
203
|
+
|
|
204
|
+
Before creating an insight with JOINs:
|
|
205
|
+
- [ ] Both workflow sources include `{ name: 'id', meta: '_id' }`
|
|
206
|
+
- [ ] ActivityLink field uses `fieldId` (NOT `key`)
|
|
207
|
+
- [ ] JOIN condition uses column names from sources (e.g., `p.club = c.id`)
|
|
208
|
+
- [ ] Using LEFT JOIN (unless relationship required)
|
|
209
|
+
- [ ] Tested with `preview_insight` first
|
package/.env.example
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# Hailer MCP Server Configuration
|
|
2
2
|
# Copy this file to .env.local and update with your own credentials
|
|
3
3
|
|
|
4
|
+
# ==============================================
|
|
5
|
+
# ENVIRONMENT
|
|
6
|
+
# ==============================================
|
|
7
|
+
|
|
8
|
+
# NODE_ENV controls multiple behaviors:
|
|
9
|
+
# - 'development': TLS bypass for local URLs, console logging, file tracking
|
|
10
|
+
# - 'production': Strict TLS, OpenTelemetry logging, no file tracking
|
|
11
|
+
#
|
|
12
|
+
# Set to 'development' when using local Hailer cluster (*.local.gd)
|
|
13
|
+
# Leave unset or 'production' for api.hailer.com
|
|
14
|
+
# NODE_ENV=development
|
|
15
|
+
|
|
4
16
|
# ==============================================
|
|
5
17
|
# MCP SERVER CONFIGURATION (for external clients)
|
|
6
18
|
# ==============================================
|
|
@@ -78,4 +90,4 @@ ADAPTIVE_DOCUMENTATION_BOT_ENABLED=false
|
|
|
78
90
|
ADAPTIVE_AUTO_UPDATE=false
|
|
79
91
|
ADAPTIVE_UPDATE_INTERVAL=60000
|
|
80
92
|
ADAPTIVE_MIN_ERROR_COUNT=3
|
|
81
|
-
ADAPTIVE_SKILL_GENERATION=false
|
|
93
|
+
ADAPTIVE_SKILL_GENERATION=false
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Hailer SDK
|
|
2
|
+
|
|
3
|
+
MCP tools for Hailer workspaces: workflows, activities, insights, and apps.
|
|
4
|
+
|
|
5
|
+
**Core features:**
|
|
6
|
+
- MCP Tools: Direct Hailer API access
|
|
7
|
+
- Local Config: Synced workspace in `workspace/` directory
|
|
8
|
+
- Type Generation: TypeScript enums for IDs
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Default Agent System (Customizable)
|
|
13
|
+
|
|
14
|
+
Ships with pre-configured agents. **These are defaults - modify, replace, or remove them.**
|
|
15
|
+
|
|
16
|
+
| Action | How |
|
|
17
|
+
|--------|-----|
|
|
18
|
+
| Create custom | `agent-builder` or add to `.claude/agents/` |
|
|
19
|
+
| Modify defaults | Edit `.claude/agents/*.md` |
|
|
20
|
+
| Disable agents | Move to `docs/agents/`, update this file |
|
|
21
|
+
|
|
22
|
+
## Orchestrator Role
|
|
23
|
+
|
|
24
|
+
You route requests to agents. Do trivial things directly; delegate everything else.
|
|
25
|
+
|
|
26
|
+
**Do directly:** Answer from context, summarize results, opinions, confirmations
|
|
27
|
+
**Delegate:** Any file read, API call, creation, update, or complex reasoning
|
|
28
|
+
|
|
29
|
+
## Default Agents
|
|
30
|
+
|
|
31
|
+
> Customize by editing `.claude/agents/` files.
|
|
32
|
+
|
|
33
|
+
| Pattern | Agent | Model |
|
|
34
|
+
|---------|-------|-------|
|
|
35
|
+
| Read data/schema | `kenji` | Haiku |
|
|
36
|
+
| Activity CRUD | `dmitri` | Haiku |
|
|
37
|
+
| Discussions/chat | `yevgeni` | Haiku |
|
|
38
|
+
| Config audit | `bjorn` | Haiku |
|
|
39
|
+
| Workspace config | `helga` | Sonnet |
|
|
40
|
+
| SQL insights | `viktor` | Sonnet |
|
|
41
|
+
| Function fields | `alejandro` | Sonnet |
|
|
42
|
+
| MCP tools | `gunther` | Sonnet |
|
|
43
|
+
| Hailer apps | `giuseppe` | Sonnet |
|
|
44
|
+
| Code review | `svetlana` | Sonnet |
|
|
45
|
+
| New agents | `agent-builder` | Sonnet |
|
|
46
|
+
| Create/update skills, improve agents | `ada` | Sonnet |
|
|
47
|
+
| Document templates | `ingrid` | Sonnet |
|
|
48
|
+
|
|
49
|
+
## Delegation Protocol
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Task(subagent_type="agent-name", prompt="JSON task spec", model="haiku")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Task spec:**
|
|
56
|
+
```json
|
|
57
|
+
{ "task": "action", "context": { "workflow_id": "...", "field_ids": {} }, "requirements": {}, "output": [] }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Response (JSON only, no prose):**
|
|
61
|
+
```json
|
|
62
|
+
{ "status": "success", "result": {}, "summary": "max 50 chars" }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Critical:** Get IDs first (via kenji), then pass to execution agents.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
# Local-First Principle
|
|
70
|
+
|
|
71
|
+
**Check local files BEFORE API calls.**
|
|
72
|
+
|
|
73
|
+
After `npm run pull`:
|
|
74
|
+
```
|
|
75
|
+
workspace/
|
|
76
|
+
├── workflows.ts # Workflow IDs, names
|
|
77
|
+
├── enums.ts # Type-safe ID constants
|
|
78
|
+
├── teams.ts, groups.ts # Team/group definitions
|
|
79
|
+
└── [Workflow]_[id]/
|
|
80
|
+
├── fields.ts # Field definitions
|
|
81
|
+
└── phases.ts # Phase definitions
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Use Local | Use API |
|
|
85
|
+
|-----------|---------|
|
|
86
|
+
| Workflow/field/phase IDs | Activity data (live) |
|
|
87
|
+
| Field types, labels, options | Activity counts |
|
|
88
|
+
| Team/group definitions | Discussion messages |
|
|
89
|
+
|
|
90
|
+
**Refresh:** `npm run pull` (after changes, start of session, before building apps)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
# Safety Rules
|
|
95
|
+
|
|
96
|
+
**Protected (hooks confirm):** `npm run push`, `*-push`, `*-sync`
|
|
97
|
+
**Safe:** `npm run pull`, `npm run generate`
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# Directory Structure
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
workspace/ # Local config (check FIRST)
|
|
105
|
+
.claude/
|
|
106
|
+
agents/ # Agent definitions
|
|
107
|
+
hooks/ # Safety hooks
|
|
108
|
+
skills/ # Documentation
|
|
109
|
+
commands/ # Slash commands
|
|
110
|
+
settings.json # Permissions
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
# Customization
|
|
116
|
+
|
|
117
|
+
## Create Agent
|
|
118
|
+
```yaml
|
|
119
|
+
# .claude/agents/your-agent.md
|
|
120
|
+
---
|
|
121
|
+
name: your-agent
|
|
122
|
+
description: What it does.\n\n<example>...</example>
|
|
123
|
+
model: haiku
|
|
124
|
+
---
|
|
125
|
+
[Agent body with responsibilities]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Modify Agents
|
|
129
|
+
Edit `.claude/agents/*.md` - change personality, responsibilities, model, tools.
|
|
130
|
+
|
|
131
|
+
## Disable Agents
|
|
132
|
+
Move from `.claude/agents/` to `docs/agents/`, remove from delegation table.
|
|
133
|
+
|
|
134
|
+
## Without Agents
|
|
135
|
+
Use MCP tools directly: `list_workflows`, `create_activity`, `get_workflow_schema`, etc.
|
package/dist/app.js
CHANGED
|
@@ -9,7 +9,6 @@ const user_1 = require("./mcp/tools/user");
|
|
|
9
9
|
const workflow_1 = require("./mcp/tools/workflow");
|
|
10
10
|
const insight_1 = require("./mcp/tools/insight");
|
|
11
11
|
const app_1 = require("./mcp/tools/app");
|
|
12
|
-
const skill_1 = require("./mcp/tools/skill");
|
|
13
12
|
const core = new core_1.Core();
|
|
14
13
|
console.log('Registering tools...');
|
|
15
14
|
console.log(`Nuclear tools ${config_1.environment.ENABLE_NUCLEAR_TOOLS ? 'ENABLED' : 'DISABLED'} (set ENABLE_NUCLEAR_TOOLS=true in .env.local to enable)`);
|
|
@@ -47,6 +46,7 @@ core.addTool(workflow_1.countActivitiesTool);
|
|
|
47
46
|
core.addTool(insight_1.createInsightTool);
|
|
48
47
|
core.addTool(insight_1.previewInsightTool);
|
|
49
48
|
core.addTool(insight_1.getInsightDataTool);
|
|
49
|
+
core.addTool(insight_1.updateInsightTool);
|
|
50
50
|
if (config_1.environment.ENABLE_NUCLEAR_TOOLS) {
|
|
51
51
|
core.addTool(insight_1.removeInsightTool);
|
|
52
52
|
}
|
|
@@ -69,8 +69,9 @@ core.addTool(app_1.getTemplateTool);
|
|
|
69
69
|
core.addTool(app_1.publishTemplateTool);
|
|
70
70
|
core.addTool(app_1.getProductTool);
|
|
71
71
|
core.addTool(app_1.getProductManifestTool);
|
|
72
|
-
|
|
73
|
-
core.addTool(
|
|
72
|
+
// Marketplace app tools
|
|
73
|
+
core.addTool(app_1.publishAppTool);
|
|
74
|
+
core.addTool(app_1.installMarketplaceAppTool);
|
|
74
75
|
console.log('All tools registered successfully!');
|
|
75
76
|
// Start the application
|
|
76
77
|
core.start().catch((error) => {
|
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -15,7 +15,6 @@ import { ToolCallError, ErrorPattern, AdaptiveBotConfig } from './adaptive-docum
|
|
|
15
15
|
export declare class AdaptiveDocumentationBot {
|
|
16
16
|
private logParser;
|
|
17
17
|
private descriptionUpdater;
|
|
18
|
-
private skillGenerator;
|
|
19
18
|
private llmCaller;
|
|
20
19
|
private config;
|
|
21
20
|
private errorPatterns;
|
|
@@ -83,7 +82,6 @@ export declare class AdaptiveDocumentationBot {
|
|
|
83
82
|
monitoring: boolean;
|
|
84
83
|
errorPatterns: number;
|
|
85
84
|
improvements: any;
|
|
86
|
-
skills: any;
|
|
87
85
|
};
|
|
88
86
|
/**
|
|
89
87
|
* Get error patterns for a specific tool
|