@hailer/mcp 1.1.11 → 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.
Files changed (252) hide show
  1. package/dist/app.js +18 -5
  2. package/dist/bot/bot-config.d.ts +12 -1
  3. package/dist/bot/bot-config.js +98 -14
  4. package/dist/bot/bot-manager.d.ts +13 -3
  5. package/dist/bot/bot-manager.js +80 -25
  6. package/dist/bot/bot.d.ts +46 -0
  7. package/dist/bot/bot.js +542 -166
  8. package/dist/bot/services/message-classifier.js +17 -0
  9. package/dist/bot/services/permission-guard.d.ts +52 -0
  10. package/dist/bot/services/permission-guard.js +149 -0
  11. package/dist/bot/services/types.d.ts +5 -0
  12. package/dist/bot/services/typing-indicator.d.ts +6 -1
  13. package/dist/bot/services/typing-indicator.js +19 -3
  14. package/dist/config.d.ts +6 -1
  15. package/dist/config.js +43 -0
  16. package/dist/core.js +3 -6
  17. package/dist/mcp/UserContextCache.d.ts +5 -0
  18. package/dist/mcp/UserContextCache.js +51 -19
  19. package/dist/mcp/hailer-clients.d.ts +19 -1
  20. package/dist/mcp/hailer-clients.js +157 -20
  21. package/dist/mcp/session-store.d.ts +68 -0
  22. package/dist/mcp/session-store.js +169 -0
  23. package/dist/mcp/signal-handler.js +12 -12
  24. package/dist/mcp/tool-registry.d.ts +17 -4
  25. package/dist/mcp/tool-registry.js +37 -7
  26. package/dist/mcp/tools/activity.js +99 -7
  27. package/dist/mcp/tools/app-scaffold.js +304 -336
  28. package/dist/mcp/tools/company.d.ts +9 -0
  29. package/dist/mcp/tools/company.js +88 -0
  30. package/dist/mcp/tools/discussion.js +68 -0
  31. package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
  32. package/dist/mcp/tools/workflow-permissions.js +204 -0
  33. package/dist/mcp/tools/workflow.js +57 -18
  34. package/dist/mcp/utils/index.d.ts +2 -0
  35. package/dist/mcp/utils/index.js +12 -1
  36. package/dist/mcp/utils/role-utils.d.ts +74 -0
  37. package/dist/mcp/utils/role-utils.js +151 -0
  38. package/dist/mcp/utils/types.d.ts +43 -1
  39. package/dist/mcp/utils/types.js +14 -0
  40. package/dist/mcp/webhook-handler.d.ts +6 -0
  41. package/dist/mcp/webhook-handler.js +11 -0
  42. package/dist/mcp-server.d.ts +23 -2
  43. package/dist/mcp-server.js +639 -111
  44. package/dist/plugins/vipunen/client.d.ts +150 -0
  45. package/dist/plugins/vipunen/client.js +535 -0
  46. package/dist/plugins/vipunen/config/schema-config.json +19 -0
  47. package/dist/plugins/vipunen/config/schema-doc.json +22 -0
  48. package/dist/plugins/vipunen/index.d.ts +41 -0
  49. package/dist/plugins/vipunen/index.js +88 -0
  50. package/dist/plugins/vipunen/tools.d.ts +26 -0
  51. package/dist/plugins/vipunen/tools.js +501 -0
  52. package/package.json +2 -1
  53. package/.claude/.context-watchdog.json +0 -1
  54. package/.claude/.session-checked +0 -1
  55. package/.claude/CLAUDE.md +0 -370
  56. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  57. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  58. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  59. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  60. package/.claude/agents/agent-code-simplifier.md +0 -53
  61. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  62. package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
  63. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  64. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  65. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  66. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  67. package/.claude/agents/agent-ivan-monolith.md +0 -154
  68. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  69. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  70. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  71. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  72. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  73. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  74. package/.claude/agents/agent-permissions-handler.md +0 -208
  75. package/.claude/agents/agent-simple-writer.md +0 -48
  76. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  77. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  78. package/.claude/agents/agent-ui-designer.md +0 -100
  79. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  80. package/.claude/agents/agent-web-search.md +0 -55
  81. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  82. package/.claude/agents/agent-zara-zapier.md +0 -159
  83. package/.claude/commands/app-squad.md +0 -135
  84. package/.claude/commands/audit-squad.md +0 -158
  85. package/.claude/commands/autoplan.md +0 -563
  86. package/.claude/commands/cleanup-squad.md +0 -98
  87. package/.claude/commands/config-squad.md +0 -106
  88. package/.claude/commands/crud-squad.md +0 -87
  89. package/.claude/commands/data-squad.md +0 -97
  90. package/.claude/commands/debug-squad.md +0 -303
  91. package/.claude/commands/doc-squad.md +0 -65
  92. package/.claude/commands/handoff.md +0 -137
  93. package/.claude/commands/health.md +0 -49
  94. package/.claude/commands/help.md +0 -29
  95. package/.claude/commands/help:agents.md +0 -151
  96. package/.claude/commands/help:commands.md +0 -78
  97. package/.claude/commands/help:faq.md +0 -79
  98. package/.claude/commands/help:plugins.md +0 -50
  99. package/.claude/commands/help:skills.md +0 -93
  100. package/.claude/commands/help:tools.md +0 -75
  101. package/.claude/commands/hotfix-squad.md +0 -112
  102. package/.claude/commands/integration-squad.md +0 -82
  103. package/.claude/commands/janitor-squad.md +0 -167
  104. package/.claude/commands/learn-auto.md +0 -120
  105. package/.claude/commands/learn.md +0 -120
  106. package/.claude/commands/mcp-list.md +0 -27
  107. package/.claude/commands/onboard-squad.md +0 -140
  108. package/.claude/commands/plan-workspace.md +0 -732
  109. package/.claude/commands/prd.md +0 -130
  110. package/.claude/commands/project-status.md +0 -82
  111. package/.claude/commands/publish.md +0 -138
  112. package/.claude/commands/recap.md +0 -69
  113. package/.claude/commands/restore.md +0 -64
  114. package/.claude/commands/review-squad.md +0 -152
  115. package/.claude/commands/save.md +0 -24
  116. package/.claude/commands/stats.md +0 -19
  117. package/.claude/commands/swarm.md +0 -210
  118. package/.claude/commands/tool-builder.md +0 -39
  119. package/.claude/commands/ws-pull.md +0 -44
  120. package/.claude/hooks/_shared-memory.cjs +0 -305
  121. package/.claude/hooks/_utils.cjs +0 -108
  122. package/.claude/hooks/agent-failure-detector.cjs +0 -383
  123. package/.claude/hooks/agent-usage-logger.cjs +0 -204
  124. package/.claude/hooks/app-edit-guard.cjs +0 -494
  125. package/.claude/hooks/auto-learn.cjs +0 -304
  126. package/.claude/hooks/bash-guard.cjs +0 -272
  127. package/.claude/hooks/builder-mode-manager.cjs +0 -354
  128. package/.claude/hooks/bulk-activity-guard.cjs +0 -271
  129. package/.claude/hooks/context-watchdog.cjs +0 -230
  130. package/.claude/hooks/delegation-reminder.cjs +0 -465
  131. package/.claude/hooks/design-system-lint.cjs +0 -271
  132. package/.claude/hooks/post-scaffold-hook.cjs +0 -181
  133. package/.claude/hooks/prompt-guard.cjs +0 -354
  134. package/.claude/hooks/publish-template-guard.cjs +0 -147
  135. package/.claude/hooks/session-start.cjs +0 -35
  136. package/.claude/hooks/shared-memory-writer.cjs +0 -147
  137. package/.claude/hooks/skill-injector.cjs +0 -140
  138. package/.claude/hooks/skill-usage-logger.cjs +0 -258
  139. package/.claude/hooks/src-edit-guard.cjs +0 -240
  140. package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
  141. package/.claude/settings.json +0 -257
  142. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  143. package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
  144. package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
  145. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  146. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  147. package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
  148. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
  149. package/.claude/skills/agent-structure/SKILL.md +0 -98
  150. package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
  151. package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
  152. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  153. package/.claude/skills/frontend-design/SKILL.md +0 -254
  154. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  155. package/.claude/skills/hailer-api-client/SKILL.md +0 -518
  156. package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
  157. package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
  158. package/.claude/skills/hailer-design-system/SKILL.md +0 -235
  159. package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
  160. package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
  161. package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
  162. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  163. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  164. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  165. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  166. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  167. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  168. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  169. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  170. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  171. package/.claude/skills/integration-patterns/SKILL.md +0 -421
  172. package/.claude/skills/json-only-output/SKILL.md +0 -72
  173. package/.claude/skills/lsp-setup/SKILL.md +0 -160
  174. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  175. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  176. package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
  177. package/.claude/skills/testing-patterns/SKILL.md +0 -630
  178. package/.claude/skills/tool-builder/SKILL.md +0 -250
  179. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  180. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  181. package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
  182. package/.hailer-mcp-port +0 -1
  183. package/.mcp.json +0 -13
  184. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  185. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  186. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  187. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  188. package/.opencode/agent/agent-code-simplifier.md +0 -31
  189. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  190. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  191. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  192. package/.opencode/agent/agent-helga-workflow-config.md +0 -204
  193. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  194. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  195. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  196. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  197. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  198. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  199. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  200. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  201. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  202. package/.opencode/agent/agent-permissions-handler.md +0 -50
  203. package/.opencode/agent/agent-simple-writer.md +0 -45
  204. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  205. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  206. package/.opencode/agent/agent-ui-designer.md +0 -56
  207. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  208. package/.opencode/agent/agent-web-search.md +0 -42
  209. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  210. package/.opencode/agent/agent-zara-zapier.md +0 -53
  211. package/.opencode/commands/app-squad.md +0 -135
  212. package/.opencode/commands/audit-squad.md +0 -158
  213. package/.opencode/commands/autoplan.md +0 -563
  214. package/.opencode/commands/cleanup-squad.md +0 -98
  215. package/.opencode/commands/config-squad.md +0 -106
  216. package/.opencode/commands/crud-squad.md +0 -87
  217. package/.opencode/commands/data-squad.md +0 -97
  218. package/.opencode/commands/debug-squad.md +0 -303
  219. package/.opencode/commands/doc-squad.md +0 -65
  220. package/.opencode/commands/handoff.md +0 -137
  221. package/.opencode/commands/health.md +0 -49
  222. package/.opencode/commands/help-agents.md +0 -151
  223. package/.opencode/commands/help-commands.md +0 -32
  224. package/.opencode/commands/help-faq.md +0 -29
  225. package/.opencode/commands/help-plugins.md +0 -28
  226. package/.opencode/commands/help-skills.md +0 -7
  227. package/.opencode/commands/help-tools.md +0 -40
  228. package/.opencode/commands/help.md +0 -28
  229. package/.opencode/commands/hotfix-squad.md +0 -112
  230. package/.opencode/commands/integration-squad.md +0 -82
  231. package/.opencode/commands/janitor-squad.md +0 -167
  232. package/.opencode/commands/learn-auto.md +0 -120
  233. package/.opencode/commands/learn.md +0 -120
  234. package/.opencode/commands/mcp-list.md +0 -27
  235. package/.opencode/commands/onboard-squad.md +0 -140
  236. package/.opencode/commands/plan-workspace.md +0 -732
  237. package/.opencode/commands/prd.md +0 -131
  238. package/.opencode/commands/project-status.md +0 -82
  239. package/.opencode/commands/publish.md +0 -138
  240. package/.opencode/commands/recap.md +0 -69
  241. package/.opencode/commands/restore.md +0 -64
  242. package/.opencode/commands/review-squad.md +0 -152
  243. package/.opencode/commands/save.md +0 -24
  244. package/.opencode/commands/stats.md +0 -19
  245. package/.opencode/commands/swarm.md +0 -210
  246. package/.opencode/commands/tool-builder.md +0 -39
  247. package/.opencode/commands/ws-pull.md +0 -44
  248. package/.opencode/opencode.json +0 -21
  249. package/inbox/failures.log +0 -1
  250. package/inbox/usage.jsonl +0 -4
  251. package/scripts/postinstall.cjs +0 -64
  252. 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
- }