@hailer/mcp 1.1.12 → 1.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +0 -7
- package/{.claude → dist}/CLAUDE.md +2 -2
- package/dist/app.js +18 -5
- package/dist/bot/bot-config.d.ts +10 -1
- package/dist/bot/bot-config.js +64 -3
- package/dist/bot/bot-manager.d.ts +2 -0
- package/dist/bot/bot-manager.js +9 -2
- package/dist/bot/bot.d.ts +33 -0
- package/dist/bot/bot.js +461 -160
- package/dist/bot/services/message-classifier.js +17 -0
- package/dist/bot/services/permission-guard.d.ts +52 -0
- package/dist/bot/services/permission-guard.js +149 -0
- package/dist/bot/services/types.d.ts +5 -0
- package/dist/bot/services/typing-indicator.d.ts +6 -1
- package/dist/bot/services/typing-indicator.js +19 -3
- package/dist/cli.js +0 -0
- package/dist/config.d.ts +6 -1
- package/dist/config.js +43 -0
- package/dist/core.js +3 -6
- package/dist/lib/discussion-lock.d.ts +42 -0
- package/dist/lib/discussion-lock.js +110 -0
- package/dist/mcp/UserContextCache.d.ts +5 -0
- package/dist/mcp/UserContextCache.js +51 -19
- package/dist/mcp/hailer-clients.d.ts +19 -1
- package/dist/mcp/hailer-clients.js +158 -24
- package/dist/mcp/session-store.d.ts +68 -0
- package/dist/mcp/session-store.js +169 -0
- package/dist/mcp/signal-handler.js +2 -0
- package/dist/mcp/tool-registry.d.ts +17 -4
- package/dist/mcp/tool-registry.js +37 -7
- package/dist/mcp/tools/activity.js +99 -7
- package/dist/mcp/tools/app-scaffold.js +304 -336
- package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
- package/dist/mcp/tools/bot-config/constants.js +94 -0
- package/dist/mcp/tools/bot-config/core.d.ts +253 -0
- package/dist/mcp/tools/bot-config/core.js +2456 -0
- package/dist/mcp/tools/bot-config/index.d.ts +10 -0
- package/dist/mcp/tools/bot-config/index.js +59 -0
- package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
- package/dist/mcp/tools/bot-config/tools.js +15 -0
- package/dist/mcp/tools/bot-config/types.d.ts +50 -0
- package/dist/mcp/tools/bot-config/types.js +6 -0
- package/dist/mcp/tools/bug-fixer-tools.d.ts +45 -0
- package/dist/mcp/tools/bug-fixer-tools.js +1096 -0
- package/dist/mcp/tools/company.d.ts +9 -0
- package/dist/mcp/tools/company.js +88 -0
- package/dist/mcp/tools/discussion.js +68 -0
- package/dist/mcp/tools/document.d.ts +11 -0
- package/dist/mcp/tools/document.js +741 -0
- package/dist/mcp/tools/investigate.d.ts +9 -0
- package/dist/mcp/tools/investigate.js +254 -0
- package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
- package/dist/mcp/tools/workflow-permissions.js +204 -0
- package/dist/mcp/tools/workflow.js +57 -18
- package/dist/mcp/utils/index.d.ts +2 -0
- package/dist/mcp/utils/index.js +12 -1
- package/dist/mcp/utils/role-utils.d.ts +74 -0
- package/dist/mcp/utils/role-utils.js +151 -0
- package/dist/mcp/utils/types.d.ts +43 -1
- package/dist/mcp/utils/types.js +14 -0
- package/dist/mcp/webhook-handler.d.ts +4 -0
- package/dist/mcp/webhook-handler.js +8 -0
- package/dist/mcp-server.d.ts +23 -2
- package/dist/mcp-server.js +639 -127
- package/dist/plugins/vipunen/client.d.ts +150 -0
- package/dist/plugins/vipunen/client.js +535 -0
- package/dist/plugins/vipunen/config/schema-config.json +19 -0
- package/dist/plugins/vipunen/config/schema-doc.json +22 -0
- package/dist/plugins/vipunen/index.d.ts +41 -0
- package/dist/plugins/vipunen/index.js +88 -0
- package/dist/plugins/vipunen/tools.d.ts +26 -0
- package/dist/plugins/vipunen/tools.js +501 -0
- package/dist/stdio-server.d.ts +14 -0
- package/dist/stdio-server.js +101 -0
- package/package.json +2 -1
- package/.claude/agents/agent-ada-skill-builder.md +0 -94
- package/.claude/agents/agent-alejandro-function-fields.md +0 -342
- package/.claude/agents/agent-bjorn-config-audit.md +0 -103
- package/.claude/agents/agent-builder-agent-creator.md +0 -130
- package/.claude/agents/agent-code-simplifier.md +0 -53
- package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
- package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
- package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
- package/.claude/agents/agent-helga-workflow-config.md +0 -204
- package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
- package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
- package/.claude/agents/agent-ivan-monolith.md +0 -154
- package/.claude/agents/agent-kenji-data-reader.md +0 -86
- package/.claude/agents/agent-lars-code-inspector.md +0 -102
- package/.claude/agents/agent-marco-mockup-builder.md +0 -110
- package/.claude/agents/agent-marcus-api-documenter.md +0 -323
- package/.claude/agents/agent-marketplace-publisher.md +0 -280
- package/.claude/agents/agent-marketplace-reviewer.md +0 -309
- package/.claude/agents/agent-permissions-handler.md +0 -208
- package/.claude/agents/agent-simple-writer.md +0 -48
- package/.claude/agents/agent-svetlana-code-review.md +0 -171
- package/.claude/agents/agent-tanya-test-runner.md +0 -333
- package/.claude/agents/agent-ui-designer.md +0 -100
- package/.claude/agents/agent-viktor-sql-insights.md +0 -212
- package/.claude/agents/agent-web-search.md +0 -55
- package/.claude/agents/agent-yevgeni-discussions.md +0 -45
- package/.claude/agents/agent-zara-zapier.md +0 -159
- package/.claude/commands/app-squad.md +0 -135
- package/.claude/commands/audit-squad.md +0 -158
- package/.claude/commands/autoplan.md +0 -563
- package/.claude/commands/cleanup-squad.md +0 -98
- package/.claude/commands/config-squad.md +0 -106
- package/.claude/commands/crud-squad.md +0 -87
- package/.claude/commands/data-squad.md +0 -97
- package/.claude/commands/debug-squad.md +0 -303
- package/.claude/commands/doc-squad.md +0 -65
- package/.claude/commands/handoff.md +0 -137
- package/.claude/commands/health.md +0 -49
- package/.claude/commands/help.md +0 -29
- package/.claude/commands/help:agents.md +0 -151
- package/.claude/commands/help:commands.md +0 -78
- package/.claude/commands/help:faq.md +0 -79
- package/.claude/commands/help:plugins.md +0 -50
- package/.claude/commands/help:skills.md +0 -93
- package/.claude/commands/help:tools.md +0 -75
- package/.claude/commands/hotfix-squad.md +0 -112
- package/.claude/commands/integration-squad.md +0 -82
- package/.claude/commands/janitor-squad.md +0 -167
- package/.claude/commands/learn-auto.md +0 -120
- package/.claude/commands/learn.md +0 -120
- package/.claude/commands/mcp-list.md +0 -27
- package/.claude/commands/onboard-squad.md +0 -140
- package/.claude/commands/plan-workspace.md +0 -732
- package/.claude/commands/prd.md +0 -130
- package/.claude/commands/project-status.md +0 -82
- package/.claude/commands/publish.md +0 -138
- package/.claude/commands/recap.md +0 -69
- package/.claude/commands/restore.md +0 -64
- package/.claude/commands/review-squad.md +0 -152
- package/.claude/commands/save.md +0 -24
- package/.claude/commands/stats.md +0 -19
- package/.claude/commands/swarm.md +0 -210
- package/.claude/commands/tool-builder.md +0 -39
- package/.claude/commands/ws-pull.md +0 -44
- package/.claude/hooks/_shared-memory.cjs +0 -305
- package/.claude/hooks/_utils.cjs +0 -108
- package/.claude/hooks/agent-failure-detector.cjs +0 -383
- package/.claude/hooks/agent-usage-logger.cjs +0 -204
- package/.claude/hooks/app-edit-guard.cjs +0 -494
- package/.claude/hooks/auto-learn.cjs +0 -304
- package/.claude/hooks/bash-guard.cjs +0 -272
- package/.claude/hooks/builder-mode-manager.cjs +0 -354
- package/.claude/hooks/bulk-activity-guard.cjs +0 -271
- package/.claude/hooks/context-watchdog.cjs +0 -230
- package/.claude/hooks/delegation-reminder.cjs +0 -465
- package/.claude/hooks/design-system-lint.cjs +0 -271
- package/.claude/hooks/post-scaffold-hook.cjs +0 -181
- package/.claude/hooks/prompt-guard.cjs +0 -354
- package/.claude/hooks/publish-template-guard.cjs +0 -147
- package/.claude/hooks/session-start.cjs +0 -35
- package/.claude/hooks/shared-memory-writer.cjs +0 -147
- package/.claude/hooks/skill-injector.cjs +0 -140
- package/.claude/hooks/skill-usage-logger.cjs +0 -258
- package/.claude/hooks/src-edit-guard.cjs +0 -240
- package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
- package/.claude/settings.json +0 -257
- package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
- package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
- package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
- package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
- package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
- package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
- package/.claude/skills/agent-structure/SKILL.md +0 -98
- package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
- package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
- package/.claude/skills/delegation-routing/SKILL.md +0 -202
- package/.claude/skills/frontend-design/SKILL.md +0 -254
- package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
- package/.claude/skills/hailer-api-client/SKILL.md +0 -518
- package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
- package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
- package/.claude/skills/hailer-design-system/SKILL.md +0 -235
- package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
- package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
- package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
- package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
- package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
- package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
- package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
- package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
- package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
- package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
- package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
- package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
- package/.claude/skills/integration-patterns/SKILL.md +0 -421
- package/.claude/skills/json-only-output/SKILL.md +0 -72
- package/.claude/skills/lsp-setup/SKILL.md +0 -160
- package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
- package/.claude/skills/optional-parameters/SKILL.md +0 -72
- package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
- package/.claude/skills/testing-patterns/SKILL.md +0 -630
- package/.claude/skills/tool-builder/SKILL.md +0 -250
- package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
- package/.claude/skills/tool-response-verification/SKILL.md +0 -92
- package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
- package/.mcp.json +0 -13
- package/.opencode/agent/agent-ada-skill-builder.md +0 -35
- package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
- package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
- package/.opencode/agent/agent-builder-agent-creator.md +0 -39
- package/.opencode/agent/agent-code-simplifier.md +0 -31
- package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
- package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
- package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
- package/.opencode/agent/agent-helga-workflow-config.md +0 -203
- package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
- package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
- package/.opencode/agent/agent-ivan-monolith.md +0 -46
- package/.opencode/agent/agent-kenji-data-reader.md +0 -53
- package/.opencode/agent/agent-lars-code-inspector.md +0 -28
- package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
- package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
- package/.opencode/agent/agent-marketplace-publisher.md +0 -44
- package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
- package/.opencode/agent/agent-permissions-handler.md +0 -50
- package/.opencode/agent/agent-simple-writer.md +0 -45
- package/.opencode/agent/agent-svetlana-code-review.md +0 -39
- package/.opencode/agent/agent-tanya-test-runner.md +0 -57
- package/.opencode/agent/agent-ui-designer.md +0 -56
- package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
- package/.opencode/agent/agent-web-search.md +0 -42
- package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
- package/.opencode/agent/agent-zara-zapier.md +0 -53
- package/.opencode/commands/app-squad.md +0 -135
- package/.opencode/commands/audit-squad.md +0 -158
- package/.opencode/commands/autoplan.md +0 -563
- package/.opencode/commands/cleanup-squad.md +0 -98
- package/.opencode/commands/config-squad.md +0 -106
- package/.opencode/commands/crud-squad.md +0 -87
- package/.opencode/commands/data-squad.md +0 -97
- package/.opencode/commands/debug-squad.md +0 -303
- package/.opencode/commands/doc-squad.md +0 -65
- package/.opencode/commands/handoff.md +0 -137
- package/.opencode/commands/health.md +0 -49
- package/.opencode/commands/help-agents.md +0 -151
- package/.opencode/commands/help-commands.md +0 -32
- package/.opencode/commands/help-faq.md +0 -29
- package/.opencode/commands/help-plugins.md +0 -28
- package/.opencode/commands/help-skills.md +0 -7
- package/.opencode/commands/help-tools.md +0 -40
- package/.opencode/commands/help.md +0 -28
- package/.opencode/commands/hotfix-squad.md +0 -112
- package/.opencode/commands/integration-squad.md +0 -82
- package/.opencode/commands/janitor-squad.md +0 -167
- package/.opencode/commands/learn-auto.md +0 -120
- package/.opencode/commands/learn.md +0 -120
- package/.opencode/commands/mcp-list.md +0 -27
- package/.opencode/commands/onboard-squad.md +0 -140
- package/.opencode/commands/plan-workspace.md +0 -732
- package/.opencode/commands/prd.md +0 -131
- package/.opencode/commands/project-status.md +0 -82
- package/.opencode/commands/publish.md +0 -138
- package/.opencode/commands/recap.md +0 -69
- package/.opencode/commands/restore.md +0 -64
- package/.opencode/commands/review-squad.md +0 -152
- package/.opencode/commands/save.md +0 -24
- package/.opencode/commands/stats.md +0 -19
- package/.opencode/commands/swarm.md +0 -210
- package/.opencode/commands/tool-builder.md +0 -39
- package/.opencode/commands/ws-pull.md +0 -44
- package/.opencode/opencode.json +0 -28
- package/SESSION-HANDOFF.md +0 -68
- package/inbox/2026-03-04-bot-config-patterns.md +0 -24
- package/scripts/postinstall.cjs +0 -64
- package/scripts/test-hal-tools.ts +0 -154
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* <hook-name>agent-failure-detector</hook-name>
|
|
4
|
-
*
|
|
5
|
-
* <purpose>
|
|
6
|
-
* Detects repeated agent failures, categorizes error types, and suggests fixes.
|
|
7
|
-
* Tracks failures per agent and prompts for improvement after threshold.
|
|
8
|
-
* </purpose>
|
|
9
|
-
*
|
|
10
|
-
* <triggers>
|
|
11
|
-
* - PostToolUse on Task tool
|
|
12
|
-
* - Only when agent response contains error indicators
|
|
13
|
-
* </triggers>
|
|
14
|
-
*
|
|
15
|
-
* <error-categories>
|
|
16
|
-
* - skill: API/schema errors → Create skill documenting correct pattern
|
|
17
|
-
* - agent: Behavioral errors → Update agent definition
|
|
18
|
-
* - user_issue: Permission errors → Ignore (user problem)
|
|
19
|
-
* - transient: Connection/timeout → Ignore (retry may work)
|
|
20
|
-
* </error-categories>
|
|
21
|
-
*
|
|
22
|
-
* <behavior>
|
|
23
|
-
* 1. Detects failure patterns in agent response
|
|
24
|
-
* 2. Categorizes error type
|
|
25
|
-
* 3. Logs to global failures.log
|
|
26
|
-
* 4. Auto-spawns Ada on first actionable failure to create skill or update agent
|
|
27
|
-
* </behavior>
|
|
28
|
-
*
|
|
29
|
-
* <tracker-file>/tmp/.claude-agent-failures.json</tracker-file>
|
|
30
|
-
* <log-file>$CLAUDE_PROJECT_DIR/inbox/failures.log</log-file>
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
const fs = require('fs');
|
|
34
|
-
const path = require('path');
|
|
35
|
-
const os = require('os');
|
|
36
|
-
|
|
37
|
-
const TEMP_DIR = os.tmpdir();
|
|
38
|
-
const TRACKER_FILE = path.join(TEMP_DIR, '.claude-agent-failures.json');
|
|
39
|
-
const GLOBAL_LOG_FILE = path.join(
|
|
40
|
-
process.env.HAILER_INBOX_DIR || path.join(process.env.CLAUDE_PROJECT_DIR || process.cwd(), 'inbox'),
|
|
41
|
-
'failures.log'
|
|
42
|
-
);
|
|
43
|
-
const FAILURE_THRESHOLD = 1; // Auto-spawn Ada on first failure
|
|
44
|
-
|
|
45
|
-
// Skip if stdin is TTY (no piped input)
|
|
46
|
-
if (process.stdin.isTTY) {
|
|
47
|
-
process.exit(0);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let input = '';
|
|
51
|
-
process.stdin.setEncoding('utf8');
|
|
52
|
-
process.stdin.on('data', chunk => input += chunk);
|
|
53
|
-
process.stdin.on('end', () => {
|
|
54
|
-
try {
|
|
55
|
-
const data = JSON.parse(input);
|
|
56
|
-
processHook(data);
|
|
57
|
-
} catch (e) {
|
|
58
|
-
console.error(`[agent-failure-detector] Failed to parse input: ${e.message}`);
|
|
59
|
-
process.exit(0);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
function loadTracker() {
|
|
64
|
-
try {
|
|
65
|
-
if (fs.existsSync(TRACKER_FILE)) {
|
|
66
|
-
return JSON.parse(fs.readFileSync(TRACKER_FILE, 'utf8'));
|
|
67
|
-
}
|
|
68
|
-
} catch (e) {
|
|
69
|
-
console.error(`[agent-failure-detector] Warning: ${e.message}`);
|
|
70
|
-
}
|
|
71
|
-
return { failures: {}, prompted: {}, errorTypes: {} };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function saveTracker(tracker) {
|
|
75
|
-
fs.writeFileSync(TRACKER_FILE, JSON.stringify(tracker, null, 2));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Log failure to global file for persistent tracking
|
|
80
|
-
*/
|
|
81
|
-
function logFailureToGlobal(agentName, errorInfo, errorMessage, projectDir) {
|
|
82
|
-
try {
|
|
83
|
-
const timestamp = new Date().toISOString();
|
|
84
|
-
const project = projectDir ? path.basename(projectDir) : 'unknown';
|
|
85
|
-
const logEntry = `[${timestamp}] ${agentName} | ${errorInfo.category} | ${project} | ${errorMessage}\n`;
|
|
86
|
-
|
|
87
|
-
// Ensure ~/.claude directory exists
|
|
88
|
-
const claudeDir = path.dirname(GLOBAL_LOG_FILE);
|
|
89
|
-
if (!fs.existsSync(claudeDir)) {
|
|
90
|
-
fs.mkdirSync(claudeDir, { recursive: true });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
fs.appendFileSync(GLOBAL_LOG_FILE, logEntry);
|
|
94
|
-
} catch (err) {
|
|
95
|
-
// Don't fail the hook if logging fails
|
|
96
|
-
console.error(`[agent-failure-detector] Could not write to log: ${err.message}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Error categorization - determines fix type
|
|
101
|
-
const ERROR_CATEGORIES = {
|
|
102
|
-
// API/Schema errors -> Create skill (reusable knowledge)
|
|
103
|
-
skill: {
|
|
104
|
-
patterns: [
|
|
105
|
-
'validation error',
|
|
106
|
-
'invalid field',
|
|
107
|
-
'schema',
|
|
108
|
-
'required parameter',
|
|
109
|
-
'type mismatch',
|
|
110
|
-
'format error',
|
|
111
|
-
'join syntax',
|
|
112
|
-
'sql error',
|
|
113
|
-
'query error',
|
|
114
|
-
'activitylink',
|
|
115
|
-
'workflow.*not found',
|
|
116
|
-
'phase.*not found',
|
|
117
|
-
'field.*not found',
|
|
118
|
-
'functionvariables',
|
|
119
|
-
'functionfield',
|
|
120
|
-
'namefunction',
|
|
121
|
-
'wrong.*type',
|
|
122
|
-
'expected.*got',
|
|
123
|
-
'cannot read prop',
|
|
124
|
-
'undefined.*null',
|
|
125
|
-
'processid',
|
|
126
|
-
'phaseid',
|
|
127
|
-
'fieldid',
|
|
128
|
-
'workflowid',
|
|
129
|
-
'insight.*error',
|
|
130
|
-
'template.*error',
|
|
131
|
-
'pdfmake',
|
|
132
|
-
'mcp.*error',
|
|
133
|
-
'tool.*failed'
|
|
134
|
-
],
|
|
135
|
-
suggestion: 'Create a skill documenting the correct pattern',
|
|
136
|
-
action: 'create_skill'
|
|
137
|
-
},
|
|
138
|
-
// Agent behavior errors -> Update agent
|
|
139
|
-
agent: {
|
|
140
|
-
patterns: [
|
|
141
|
-
'wrong approach',
|
|
142
|
-
'misunderstood',
|
|
143
|
-
'incorrect assumption',
|
|
144
|
-
'should have',
|
|
145
|
-
'forgot to',
|
|
146
|
-
'didn\'t check',
|
|
147
|
-
'missing context',
|
|
148
|
-
'needs to first',
|
|
149
|
-
'order of operations',
|
|
150
|
-
'wrong agent',
|
|
151
|
-
'not my responsibility',
|
|
152
|
-
'outside.*scope',
|
|
153
|
-
'cannot handle',
|
|
154
|
-
'don\'t have.*tool',
|
|
155
|
-
'need.*first',
|
|
156
|
-
'pull.*before',
|
|
157
|
-
'push.*after',
|
|
158
|
-
'didn\'t read',
|
|
159
|
-
'assumed',
|
|
160
|
-
'skipped'
|
|
161
|
-
],
|
|
162
|
-
suggestion: 'Update agent definition with better instructions',
|
|
163
|
-
action: 'update_agent'
|
|
164
|
-
},
|
|
165
|
-
// Permission/Auth errors -> Neither (user issue)
|
|
166
|
-
user_issue: {
|
|
167
|
-
patterns: [
|
|
168
|
-
'permission denied',
|
|
169
|
-
'unauthorized',
|
|
170
|
-
'access denied',
|
|
171
|
-
'not allowed',
|
|
172
|
-
'admin required',
|
|
173
|
-
'401',
|
|
174
|
-
'403',
|
|
175
|
-
'oauth',
|
|
176
|
-
'token.*expired',
|
|
177
|
-
'token.*invalid',
|
|
178
|
-
'authentication_error',
|
|
179
|
-
'credentials',
|
|
180
|
-
'login failed',
|
|
181
|
-
'session expired'
|
|
182
|
-
],
|
|
183
|
-
suggestion: 'User permission issue - not an agent problem',
|
|
184
|
-
action: 'ignore'
|
|
185
|
-
},
|
|
186
|
-
// Connection/Transient errors -> Neither (retry)
|
|
187
|
-
transient: {
|
|
188
|
-
patterns: [
|
|
189
|
-
'timeout',
|
|
190
|
-
'connection',
|
|
191
|
-
'network',
|
|
192
|
-
'unavailable',
|
|
193
|
-
'try again',
|
|
194
|
-
'rate limit',
|
|
195
|
-
'econnrefused',
|
|
196
|
-
'enotfound',
|
|
197
|
-
'socket',
|
|
198
|
-
'500',
|
|
199
|
-
'502',
|
|
200
|
-
'503',
|
|
201
|
-
'504',
|
|
202
|
-
'server error',
|
|
203
|
-
'temporarily',
|
|
204
|
-
'overloaded',
|
|
205
|
-
'busy'
|
|
206
|
-
],
|
|
207
|
-
suggestion: 'Transient error - retry may work',
|
|
208
|
-
action: 'ignore'
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
function categorizeError(responseText) {
|
|
213
|
-
const lower = responseText.toLowerCase();
|
|
214
|
-
|
|
215
|
-
for (const [category, config] of Object.entries(ERROR_CATEGORIES)) {
|
|
216
|
-
for (const pattern of config.patterns) {
|
|
217
|
-
const regex = new RegExp(pattern, 'i');
|
|
218
|
-
if (regex.test(lower)) {
|
|
219
|
-
return {
|
|
220
|
-
category,
|
|
221
|
-
...config,
|
|
222
|
-
matchedPattern: pattern
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Default: likely needs skill (documentation)
|
|
229
|
-
return {
|
|
230
|
-
category: 'unknown',
|
|
231
|
-
suggestion: 'Analyze error to determine fix type',
|
|
232
|
-
action: 'analyze'
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function detectFailure(responseText) {
|
|
237
|
-
const lower = responseText.toLowerCase();
|
|
238
|
-
const failurePatterns = [
|
|
239
|
-
'"status":"error"',
|
|
240
|
-
'"status": "error"',
|
|
241
|
-
'failed to',
|
|
242
|
-
'error:',
|
|
243
|
-
'could not',
|
|
244
|
-
'unable to',
|
|
245
|
-
'invalid',
|
|
246
|
-
'not found',
|
|
247
|
-
'exception'
|
|
248
|
-
];
|
|
249
|
-
|
|
250
|
-
for (const pattern of failurePatterns) {
|
|
251
|
-
if (lower.includes(pattern)) {
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function extractErrorMessage(responseText) {
|
|
259
|
-
// Try to extract meaningful error message - more patterns
|
|
260
|
-
const patterns = [
|
|
261
|
-
/"error":\s*"([^"]+)"/i,
|
|
262
|
-
/"message":\s*"([^"]+)"/i,
|
|
263
|
-
/"summary":\s*"([^"]+)"/i,
|
|
264
|
-
/"reason":\s*"([^"]+)"/i,
|
|
265
|
-
/Error:\s*([^\n]+)/i,
|
|
266
|
-
/failed to ([^\n.]+)/i,
|
|
267
|
-
/could not ([^\n.]+)/i,
|
|
268
|
-
/unable to ([^\n.]+)/i,
|
|
269
|
-
/invalid ([^\n.]+)/i,
|
|
270
|
-
/missing ([^\n.]+)/i,
|
|
271
|
-
/\d{3}\s*[{"]([^"}\n]+)/i, // HTTP status followed by message
|
|
272
|
-
/"status":\s*"error"[^}]*"([^"]+)"/i
|
|
273
|
-
];
|
|
274
|
-
|
|
275
|
-
for (const pattern of patterns) {
|
|
276
|
-
const match = responseText.match(pattern);
|
|
277
|
-
if (match && match[1] && match[1].trim().length > 3) {
|
|
278
|
-
return match[1].trim().substring(0, 150); // Limit length
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Last resort: grab first 100 chars of anything that looks like an error
|
|
283
|
-
const errorSnippet = responseText.match(/error[^a-z]*(.{10,100})/i);
|
|
284
|
-
if (errorSnippet) {
|
|
285
|
-
return errorSnippet[1].trim().substring(0, 100);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return 'Unknown error - check agent output';
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function processHook(data) {
|
|
292
|
-
const { tool_name, tool_input, tool_response } = data;
|
|
293
|
-
|
|
294
|
-
if (tool_name !== 'Task') {
|
|
295
|
-
process.exit(0);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const agentName = tool_input?.subagent_type;
|
|
299
|
-
if (!agentName || agentName === 'ada') {
|
|
300
|
-
process.exit(0);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
const responseText = typeof tool_response === 'string'
|
|
304
|
-
? tool_response
|
|
305
|
-
: JSON.stringify(tool_response || '');
|
|
306
|
-
|
|
307
|
-
if (!detectFailure(responseText)) {
|
|
308
|
-
process.exit(0);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Categorize the error
|
|
312
|
-
const errorInfo = categorizeError(responseText);
|
|
313
|
-
const errorMessage = extractErrorMessage(responseText);
|
|
314
|
-
|
|
315
|
-
// Skip if it's a user issue or transient
|
|
316
|
-
if (errorInfo.action === 'ignore') {
|
|
317
|
-
process.exit(0);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Log to global file for persistent tracking
|
|
321
|
-
const projectDir = process.env.CLAUDE_PROJECT_DIR;
|
|
322
|
-
logFailureToGlobal(agentName, errorInfo, errorMessage, projectDir);
|
|
323
|
-
|
|
324
|
-
// Track the failure with category (session-level tracking for prompts)
|
|
325
|
-
const tracker = loadTracker();
|
|
326
|
-
const key = `${agentName}:${errorInfo.category}`;
|
|
327
|
-
tracker.failures[key] = (tracker.failures[key] || 0) + 1;
|
|
328
|
-
tracker.errorTypes[key] = errorInfo;
|
|
329
|
-
saveTracker(tracker);
|
|
330
|
-
|
|
331
|
-
const failureCount = tracker.failures[key];
|
|
332
|
-
|
|
333
|
-
if (failureCount >= FAILURE_THRESHOLD && !tracker.prompted[key]) {
|
|
334
|
-
tracker.prompted[key] = true;
|
|
335
|
-
saveTracker(tracker);
|
|
336
|
-
|
|
337
|
-
// Determine action type
|
|
338
|
-
let actionType = errorInfo.action;
|
|
339
|
-
if (actionType === 'analyze') {
|
|
340
|
-
actionType = 'create_skill'; // Default to skill creation
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Sanitize error message to prevent injection via temp file
|
|
344
|
-
const safeErrorMessage = errorMessage
|
|
345
|
-
.replace(/[`$\\]/g, '')
|
|
346
|
-
.substring(0, 500);
|
|
347
|
-
|
|
348
|
-
// Build the Ada task prompt
|
|
349
|
-
const adaPromptObj = {
|
|
350
|
-
task: actionType,
|
|
351
|
-
agent: agentName,
|
|
352
|
-
error: safeErrorMessage,
|
|
353
|
-
category: errorInfo.category,
|
|
354
|
-
pattern: errorInfo.matchedPattern || 'unknown'
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
// SECURITY: Write prompt to temp file to avoid shell injection
|
|
358
|
-
// Never embed user-controlled strings directly in shell commands
|
|
359
|
-
const tmpDir = os.tmpdir();
|
|
360
|
-
const tmpFile = path.join(tmpDir, `ada-prompt-${Date.now()}-${process.pid}.json`);
|
|
361
|
-
fs.writeFileSync(tmpFile, JSON.stringify(adaPromptObj, null, 2));
|
|
362
|
-
|
|
363
|
-
// AUTO-SPAWN Ada on first actionable failure
|
|
364
|
-
// The orchestrator reads the temp file path and handles the Task call safely
|
|
365
|
-
const output = `
|
|
366
|
-
<user-prompt-submit-hook>
|
|
367
|
-
🤖 AUTO-SPAWNING ADA - ${errorInfo.category} failure detected
|
|
368
|
-
|
|
369
|
-
Agent: ${agentName}
|
|
370
|
-
Action: ${actionType === 'create_skill' ? 'Creating skill' : 'Updating agent'}
|
|
371
|
-
|
|
372
|
-
Ada prompt saved to: ${tmpFile}
|
|
373
|
-
|
|
374
|
-
ORCHESTRATOR: Read the JSON file above and call:
|
|
375
|
-
Task(subagent_type="agent-ada-skill-builder", prompt=<contents of ${tmpFile}>)
|
|
376
|
-
</user-prompt-submit-hook>
|
|
377
|
-
`;
|
|
378
|
-
|
|
379
|
-
console.log(output);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
process.exit(0);
|
|
383
|
-
}
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* <hook-name>agent-usage-logger</hook-name>
|
|
4
|
-
*
|
|
5
|
-
* <purpose>
|
|
6
|
-
* Logs every agent call for analytics - which agents are used, success/fail rates, duration.
|
|
7
|
-
* </purpose>
|
|
8
|
-
*
|
|
9
|
-
* <triggers>
|
|
10
|
-
* - PostToolUse on Task
|
|
11
|
-
* </triggers>
|
|
12
|
-
*
|
|
13
|
-
* <log-file>$CLAUDE_PROJECT_DIR/inbox/usage.jsonl</log-file>
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
|
-
const os = require('os');
|
|
19
|
-
|
|
20
|
-
const LOG_FILE = path.join(
|
|
21
|
-
process.env.HAILER_INBOX_DIR || path.join(process.env.CLAUDE_PROJECT_DIR || process.cwd(), 'inbox'),
|
|
22
|
-
'usage.jsonl'
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
// Read hook input from stdin
|
|
26
|
-
let input = '';
|
|
27
|
-
process.stdin.setEncoding('utf8');
|
|
28
|
-
process.stdin.on('data', chunk => input += chunk);
|
|
29
|
-
process.stdin.on('end', () => {
|
|
30
|
-
try {
|
|
31
|
-
const data = JSON.parse(input);
|
|
32
|
-
processHook(data);
|
|
33
|
-
} catch (e) {
|
|
34
|
-
console.error(`[agent-usage-logger] Failed to parse input: ${e.message}`);
|
|
35
|
-
process.exit(0);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Cache directory creation state to avoid repeated mkdirSync calls
|
|
40
|
-
let _dirCreated = false;
|
|
41
|
-
|
|
42
|
-
function detectStatus(responseText) {
|
|
43
|
-
// Try to parse as JSON first for reliable status detection
|
|
44
|
-
try {
|
|
45
|
-
const parsed = JSON.parse(responseText);
|
|
46
|
-
if (parsed.status === 'success' || parsed.status === 'ready_to_push') {
|
|
47
|
-
return 'success';
|
|
48
|
-
}
|
|
49
|
-
if (parsed.status === 'error') {
|
|
50
|
-
return 'error';
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
// Not valid JSON, fall back to string matching
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Fallback: string matching for non-JSON responses
|
|
57
|
-
const lower = responseText.toLowerCase();
|
|
58
|
-
|
|
59
|
-
if (lower.includes('"status":"success"') || lower.includes('"status": "success"')) {
|
|
60
|
-
return 'success';
|
|
61
|
-
}
|
|
62
|
-
if (lower.includes('"status":"ready_to_push"') || lower.includes('"status": "ready_to_push"')) {
|
|
63
|
-
return 'success';
|
|
64
|
-
}
|
|
65
|
-
if (lower.includes('"status":"error"') || lower.includes('"status": "error"')) {
|
|
66
|
-
return 'error';
|
|
67
|
-
}
|
|
68
|
-
if (lower.includes('failed') || lower.includes('error:') || lower.includes('could not')) {
|
|
69
|
-
return 'error';
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return 'unknown';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function processHook(data) {
|
|
76
|
-
const { tool_name, tool_input, tool_response } = data;
|
|
77
|
-
|
|
78
|
-
if (tool_name !== 'Task') {
|
|
79
|
-
process.exit(0);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const agentName = tool_input?.subagent_type || 'unknown';
|
|
83
|
-
const description = tool_input?.description || '';
|
|
84
|
-
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
85
|
-
const project = path.basename(projectDir);
|
|
86
|
-
|
|
87
|
-
const responseText = typeof tool_response === 'string'
|
|
88
|
-
? tool_response
|
|
89
|
-
: JSON.stringify(tool_response || '');
|
|
90
|
-
|
|
91
|
-
const status = detectStatus(responseText);
|
|
92
|
-
|
|
93
|
-
const entry = {
|
|
94
|
-
ts: new Date().toISOString(),
|
|
95
|
-
agent: agentName,
|
|
96
|
-
status,
|
|
97
|
-
project,
|
|
98
|
-
description: (description || '').substring(0, 50)
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
// Ensure directory exists (recursive: true is idempotent, no TOCTOU race)
|
|
103
|
-
if (!_dirCreated) {
|
|
104
|
-
const claudeDir = path.dirname(LOG_FILE);
|
|
105
|
-
fs.mkdirSync(claudeDir, { recursive: true });
|
|
106
|
-
_dirCreated = true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
fs.appendFileSync(LOG_FILE, JSON.stringify(entry) + '\n');
|
|
110
|
-
} catch (err) {
|
|
111
|
-
// Don't fail the hook if logging fails
|
|
112
|
-
console.error(`[agent-usage-logger] Could not write: ${err.message}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
process.exit(0);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// CLI: Show recent usage
|
|
119
|
-
if (process.argv[2] === '--recent' || process.argv[2] === '-r') {
|
|
120
|
-
const limit = parseInt(process.argv[3]) || 20;
|
|
121
|
-
|
|
122
|
-
if (!fs.existsSync(LOG_FILE)) {
|
|
123
|
-
console.log('No usage data yet');
|
|
124
|
-
process.exit(0);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const lines = fs.readFileSync(LOG_FILE, 'utf8').trim().split('\n').filter(Boolean);
|
|
128
|
-
const recent = lines.slice(-limit);
|
|
129
|
-
|
|
130
|
-
console.log(`Last ${recent.length} agent calls:\n`);
|
|
131
|
-
for (const line of recent) {
|
|
132
|
-
try {
|
|
133
|
-
const entry = JSON.parse(line);
|
|
134
|
-
const status = entry.status === 'success' ? '✓' : entry.status === 'error' ? '✗' : '?';
|
|
135
|
-
const time = entry.ts.split('T')[1].split('.')[0];
|
|
136
|
-
console.log(`${time} ${status} ${entry.agent.padEnd(20)} ${entry.project}`);
|
|
137
|
-
} catch {}
|
|
138
|
-
}
|
|
139
|
-
process.exit(0);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// CLI: Show stats
|
|
143
|
-
if (process.argv[2] === '--stats' || process.argv[2] === '-s') {
|
|
144
|
-
if (!fs.existsSync(LOG_FILE)) {
|
|
145
|
-
console.log('No usage data yet');
|
|
146
|
-
process.exit(0);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const lines = fs.readFileSync(LOG_FILE, 'utf8').trim().split('\n').filter(Boolean);
|
|
150
|
-
const stats = {};
|
|
151
|
-
|
|
152
|
-
for (const line of lines) {
|
|
153
|
-
try {
|
|
154
|
-
const entry = JSON.parse(line);
|
|
155
|
-
if (!stats[entry.agent]) {
|
|
156
|
-
stats[entry.agent] = { total: 0, success: 0, error: 0 };
|
|
157
|
-
}
|
|
158
|
-
stats[entry.agent].total++;
|
|
159
|
-
if (entry.status === 'success') stats[entry.agent].success++;
|
|
160
|
-
if (entry.status === 'error') stats[entry.agent].error++;
|
|
161
|
-
} catch {}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
console.log('Agent Usage Stats:\n');
|
|
165
|
-
console.log('Agent'.padEnd(25) + 'Total'.padEnd(8) + 'Success'.padEnd(10) + 'Errors');
|
|
166
|
-
console.log('-'.repeat(50));
|
|
167
|
-
|
|
168
|
-
const sorted = Object.entries(stats).sort((a, b) => b[1].total - a[1].total);
|
|
169
|
-
for (const [agent, s] of sorted) {
|
|
170
|
-
const rate = s.total > 0 ? Math.round((s.success / s.total) * 100) : 0;
|
|
171
|
-
console.log(`${agent.padEnd(25)}${String(s.total).padEnd(8)}${(s.success + ' (' + rate + '%)').padEnd(10)}${s.error}`);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
console.log('-'.repeat(50));
|
|
175
|
-
console.log(`Total: ${lines.length} calls`);
|
|
176
|
-
process.exit(0);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// CLI: Clear log
|
|
180
|
-
if (process.argv[2] === '--clear') {
|
|
181
|
-
if (fs.existsSync(LOG_FILE)) {
|
|
182
|
-
fs.unlinkSync(LOG_FILE);
|
|
183
|
-
console.log('✓ Usage log cleared');
|
|
184
|
-
} else {
|
|
185
|
-
console.log('No log file to clear');
|
|
186
|
-
}
|
|
187
|
-
process.exit(0);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// CLI: Help
|
|
191
|
-
if (process.argv[2] === '--help' || process.argv[2] === '-h') {
|
|
192
|
-
console.log(`
|
|
193
|
-
Agent Usage Logger - Track agent calls
|
|
194
|
-
|
|
195
|
-
Usage:
|
|
196
|
-
node agent-usage-logger.cjs --recent [N] Show last N calls (default 20)
|
|
197
|
-
node agent-usage-logger.cjs --stats Show usage statistics
|
|
198
|
-
node agent-usage-logger.cjs --clear Clear the log
|
|
199
|
-
node agent-usage-logger.cjs --help Show this help
|
|
200
|
-
|
|
201
|
-
Log file: ${LOG_FILE}
|
|
202
|
-
`);
|
|
203
|
-
process.exit(0);
|
|
204
|
-
}
|