@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.
Files changed (271) hide show
  1. package/CHANGELOG.md +0 -7
  2. package/{.claude → dist}/CLAUDE.md +2 -2
  3. package/dist/app.js +18 -5
  4. package/dist/bot/bot-config.d.ts +10 -1
  5. package/dist/bot/bot-config.js +64 -3
  6. package/dist/bot/bot-manager.d.ts +2 -0
  7. package/dist/bot/bot-manager.js +9 -2
  8. package/dist/bot/bot.d.ts +33 -0
  9. package/dist/bot/bot.js +461 -160
  10. package/dist/bot/services/message-classifier.js +17 -0
  11. package/dist/bot/services/permission-guard.d.ts +52 -0
  12. package/dist/bot/services/permission-guard.js +149 -0
  13. package/dist/bot/services/types.d.ts +5 -0
  14. package/dist/bot/services/typing-indicator.d.ts +6 -1
  15. package/dist/bot/services/typing-indicator.js +19 -3
  16. package/dist/cli.js +0 -0
  17. package/dist/config.d.ts +6 -1
  18. package/dist/config.js +43 -0
  19. package/dist/core.js +3 -6
  20. package/dist/lib/discussion-lock.d.ts +42 -0
  21. package/dist/lib/discussion-lock.js +110 -0
  22. package/dist/mcp/UserContextCache.d.ts +5 -0
  23. package/dist/mcp/UserContextCache.js +51 -19
  24. package/dist/mcp/hailer-clients.d.ts +19 -1
  25. package/dist/mcp/hailer-clients.js +158 -24
  26. package/dist/mcp/session-store.d.ts +68 -0
  27. package/dist/mcp/session-store.js +169 -0
  28. package/dist/mcp/signal-handler.js +2 -0
  29. package/dist/mcp/tool-registry.d.ts +17 -4
  30. package/dist/mcp/tool-registry.js +37 -7
  31. package/dist/mcp/tools/activity.js +99 -7
  32. package/dist/mcp/tools/app-scaffold.js +304 -336
  33. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  34. package/dist/mcp/tools/bot-config/constants.js +94 -0
  35. package/dist/mcp/tools/bot-config/core.d.ts +253 -0
  36. package/dist/mcp/tools/bot-config/core.js +2456 -0
  37. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  38. package/dist/mcp/tools/bot-config/index.js +59 -0
  39. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  40. package/dist/mcp/tools/bot-config/tools.js +15 -0
  41. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  42. package/dist/mcp/tools/bot-config/types.js +6 -0
  43. package/dist/mcp/tools/bug-fixer-tools.d.ts +45 -0
  44. package/dist/mcp/tools/bug-fixer-tools.js +1096 -0
  45. package/dist/mcp/tools/company.d.ts +9 -0
  46. package/dist/mcp/tools/company.js +88 -0
  47. package/dist/mcp/tools/discussion.js +68 -0
  48. package/dist/mcp/tools/document.d.ts +11 -0
  49. package/dist/mcp/tools/document.js +741 -0
  50. package/dist/mcp/tools/investigate.d.ts +9 -0
  51. package/dist/mcp/tools/investigate.js +254 -0
  52. package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
  53. package/dist/mcp/tools/workflow-permissions.js +204 -0
  54. package/dist/mcp/tools/workflow.js +57 -18
  55. package/dist/mcp/utils/index.d.ts +2 -0
  56. package/dist/mcp/utils/index.js +12 -1
  57. package/dist/mcp/utils/role-utils.d.ts +74 -0
  58. package/dist/mcp/utils/role-utils.js +151 -0
  59. package/dist/mcp/utils/types.d.ts +43 -1
  60. package/dist/mcp/utils/types.js +14 -0
  61. package/dist/mcp/webhook-handler.d.ts +4 -0
  62. package/dist/mcp/webhook-handler.js +8 -0
  63. package/dist/mcp-server.d.ts +23 -2
  64. package/dist/mcp-server.js +639 -127
  65. package/dist/plugins/vipunen/client.d.ts +150 -0
  66. package/dist/plugins/vipunen/client.js +535 -0
  67. package/dist/plugins/vipunen/config/schema-config.json +19 -0
  68. package/dist/plugins/vipunen/config/schema-doc.json +22 -0
  69. package/dist/plugins/vipunen/index.d.ts +41 -0
  70. package/dist/plugins/vipunen/index.js +88 -0
  71. package/dist/plugins/vipunen/tools.d.ts +26 -0
  72. package/dist/plugins/vipunen/tools.js +501 -0
  73. package/dist/stdio-server.d.ts +14 -0
  74. package/dist/stdio-server.js +101 -0
  75. package/package.json +2 -1
  76. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  77. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  78. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  79. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  80. package/.claude/agents/agent-code-simplifier.md +0 -53
  81. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  82. package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
  83. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  84. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  85. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  86. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  87. package/.claude/agents/agent-ivan-monolith.md +0 -154
  88. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  89. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  90. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  91. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  92. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  93. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  94. package/.claude/agents/agent-permissions-handler.md +0 -208
  95. package/.claude/agents/agent-simple-writer.md +0 -48
  96. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  97. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  98. package/.claude/agents/agent-ui-designer.md +0 -100
  99. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  100. package/.claude/agents/agent-web-search.md +0 -55
  101. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  102. package/.claude/agents/agent-zara-zapier.md +0 -159
  103. package/.claude/commands/app-squad.md +0 -135
  104. package/.claude/commands/audit-squad.md +0 -158
  105. package/.claude/commands/autoplan.md +0 -563
  106. package/.claude/commands/cleanup-squad.md +0 -98
  107. package/.claude/commands/config-squad.md +0 -106
  108. package/.claude/commands/crud-squad.md +0 -87
  109. package/.claude/commands/data-squad.md +0 -97
  110. package/.claude/commands/debug-squad.md +0 -303
  111. package/.claude/commands/doc-squad.md +0 -65
  112. package/.claude/commands/handoff.md +0 -137
  113. package/.claude/commands/health.md +0 -49
  114. package/.claude/commands/help.md +0 -29
  115. package/.claude/commands/help:agents.md +0 -151
  116. package/.claude/commands/help:commands.md +0 -78
  117. package/.claude/commands/help:faq.md +0 -79
  118. package/.claude/commands/help:plugins.md +0 -50
  119. package/.claude/commands/help:skills.md +0 -93
  120. package/.claude/commands/help:tools.md +0 -75
  121. package/.claude/commands/hotfix-squad.md +0 -112
  122. package/.claude/commands/integration-squad.md +0 -82
  123. package/.claude/commands/janitor-squad.md +0 -167
  124. package/.claude/commands/learn-auto.md +0 -120
  125. package/.claude/commands/learn.md +0 -120
  126. package/.claude/commands/mcp-list.md +0 -27
  127. package/.claude/commands/onboard-squad.md +0 -140
  128. package/.claude/commands/plan-workspace.md +0 -732
  129. package/.claude/commands/prd.md +0 -130
  130. package/.claude/commands/project-status.md +0 -82
  131. package/.claude/commands/publish.md +0 -138
  132. package/.claude/commands/recap.md +0 -69
  133. package/.claude/commands/restore.md +0 -64
  134. package/.claude/commands/review-squad.md +0 -152
  135. package/.claude/commands/save.md +0 -24
  136. package/.claude/commands/stats.md +0 -19
  137. package/.claude/commands/swarm.md +0 -210
  138. package/.claude/commands/tool-builder.md +0 -39
  139. package/.claude/commands/ws-pull.md +0 -44
  140. package/.claude/hooks/_shared-memory.cjs +0 -305
  141. package/.claude/hooks/_utils.cjs +0 -108
  142. package/.claude/hooks/agent-failure-detector.cjs +0 -383
  143. package/.claude/hooks/agent-usage-logger.cjs +0 -204
  144. package/.claude/hooks/app-edit-guard.cjs +0 -494
  145. package/.claude/hooks/auto-learn.cjs +0 -304
  146. package/.claude/hooks/bash-guard.cjs +0 -272
  147. package/.claude/hooks/builder-mode-manager.cjs +0 -354
  148. package/.claude/hooks/bulk-activity-guard.cjs +0 -271
  149. package/.claude/hooks/context-watchdog.cjs +0 -230
  150. package/.claude/hooks/delegation-reminder.cjs +0 -465
  151. package/.claude/hooks/design-system-lint.cjs +0 -271
  152. package/.claude/hooks/post-scaffold-hook.cjs +0 -181
  153. package/.claude/hooks/prompt-guard.cjs +0 -354
  154. package/.claude/hooks/publish-template-guard.cjs +0 -147
  155. package/.claude/hooks/session-start.cjs +0 -35
  156. package/.claude/hooks/shared-memory-writer.cjs +0 -147
  157. package/.claude/hooks/skill-injector.cjs +0 -140
  158. package/.claude/hooks/skill-usage-logger.cjs +0 -258
  159. package/.claude/hooks/src-edit-guard.cjs +0 -240
  160. package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
  161. package/.claude/settings.json +0 -257
  162. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  163. package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
  164. package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
  165. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  166. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  167. package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
  168. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
  169. package/.claude/skills/agent-structure/SKILL.md +0 -98
  170. package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
  171. package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
  172. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  173. package/.claude/skills/frontend-design/SKILL.md +0 -254
  174. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  175. package/.claude/skills/hailer-api-client/SKILL.md +0 -518
  176. package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
  177. package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
  178. package/.claude/skills/hailer-design-system/SKILL.md +0 -235
  179. package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
  180. package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
  181. package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
  182. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  183. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  184. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  185. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  186. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  187. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  188. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  189. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  190. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  191. package/.claude/skills/integration-patterns/SKILL.md +0 -421
  192. package/.claude/skills/json-only-output/SKILL.md +0 -72
  193. package/.claude/skills/lsp-setup/SKILL.md +0 -160
  194. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  195. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  196. package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
  197. package/.claude/skills/testing-patterns/SKILL.md +0 -630
  198. package/.claude/skills/tool-builder/SKILL.md +0 -250
  199. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  200. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  201. package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
  202. package/.mcp.json +0 -13
  203. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  204. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  205. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  206. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  207. package/.opencode/agent/agent-code-simplifier.md +0 -31
  208. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  209. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  210. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  211. package/.opencode/agent/agent-helga-workflow-config.md +0 -203
  212. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  213. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  214. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  215. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  216. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  217. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  218. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  219. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  220. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  221. package/.opencode/agent/agent-permissions-handler.md +0 -50
  222. package/.opencode/agent/agent-simple-writer.md +0 -45
  223. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  224. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  225. package/.opencode/agent/agent-ui-designer.md +0 -56
  226. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  227. package/.opencode/agent/agent-web-search.md +0 -42
  228. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  229. package/.opencode/agent/agent-zara-zapier.md +0 -53
  230. package/.opencode/commands/app-squad.md +0 -135
  231. package/.opencode/commands/audit-squad.md +0 -158
  232. package/.opencode/commands/autoplan.md +0 -563
  233. package/.opencode/commands/cleanup-squad.md +0 -98
  234. package/.opencode/commands/config-squad.md +0 -106
  235. package/.opencode/commands/crud-squad.md +0 -87
  236. package/.opencode/commands/data-squad.md +0 -97
  237. package/.opencode/commands/debug-squad.md +0 -303
  238. package/.opencode/commands/doc-squad.md +0 -65
  239. package/.opencode/commands/handoff.md +0 -137
  240. package/.opencode/commands/health.md +0 -49
  241. package/.opencode/commands/help-agents.md +0 -151
  242. package/.opencode/commands/help-commands.md +0 -32
  243. package/.opencode/commands/help-faq.md +0 -29
  244. package/.opencode/commands/help-plugins.md +0 -28
  245. package/.opencode/commands/help-skills.md +0 -7
  246. package/.opencode/commands/help-tools.md +0 -40
  247. package/.opencode/commands/help.md +0 -28
  248. package/.opencode/commands/hotfix-squad.md +0 -112
  249. package/.opencode/commands/integration-squad.md +0 -82
  250. package/.opencode/commands/janitor-squad.md +0 -167
  251. package/.opencode/commands/learn-auto.md +0 -120
  252. package/.opencode/commands/learn.md +0 -120
  253. package/.opencode/commands/mcp-list.md +0 -27
  254. package/.opencode/commands/onboard-squad.md +0 -140
  255. package/.opencode/commands/plan-workspace.md +0 -732
  256. package/.opencode/commands/prd.md +0 -131
  257. package/.opencode/commands/project-status.md +0 -82
  258. package/.opencode/commands/publish.md +0 -138
  259. package/.opencode/commands/recap.md +0 -69
  260. package/.opencode/commands/restore.md +0 -64
  261. package/.opencode/commands/review-squad.md +0 -152
  262. package/.opencode/commands/save.md +0 -24
  263. package/.opencode/commands/stats.md +0 -19
  264. package/.opencode/commands/swarm.md +0 -210
  265. package/.opencode/commands/tool-builder.md +0 -39
  266. package/.opencode/commands/ws-pull.md +0 -44
  267. package/.opencode/opencode.json +0 -28
  268. package/SESSION-HANDOFF.md +0 -68
  269. package/inbox/2026-03-04-bot-config-patterns.md +0 -24
  270. package/scripts/postinstall.cjs +0 -64
  271. package/scripts/test-hal-tools.ts +0 -154
@@ -1,230 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * <hook-name>context-watchdog</hook-name>
4
- *
5
- * <purpose>
6
- * Auto-detect context exhaustion and trigger handoff before context is lost.
7
- * Three layers:
8
- * 1. PreCompact (auto) - escalating response by compaction count:
9
- * 1st: inform (context still good after one compaction)
10
- * 2nd: strongly urge handoff (summary-of-summary, quality degrades)
11
- * 3rd+: force handoff
12
- * 2. PostToolUse (Task) - count agent calls, warn at thresholds
13
- * 3. Stop - if heavily compacted, block stop until handoff written
14
- * </purpose>
15
- *
16
- * <triggers>
17
- * - PreCompact (matcher: auto)
18
- * - PostToolUse (matcher: Task)
19
- * - Stop (matcher: "")
20
- * </triggers>
21
- */
22
-
23
- const fs = require('fs');
24
- const path = require('path');
25
-
26
- // --- Config ---
27
- const EARLY_WARNING_CALLS = 20; // Soft heads-up
28
- const URGENT_WARNING_CALLS = 35; // Strong warning
29
- const MAX_STOP_BLOCKS = 2; // Prevent infinite stop-block loops
30
-
31
- // --- Helpers ---
32
-
33
- function ordinal(n) {
34
- const s = ['th', 'st', 'nd', 'rd'];
35
- const v = n % 100;
36
- return n + (s[(v - 20) % 10] || s[v] || s[0]);
37
- }
38
-
39
- function getProjectRoot() {
40
- let dir = process.cwd();
41
- while (dir !== '/' && !fs.existsSync(path.join(dir, '.claude'))) {
42
- dir = path.dirname(dir);
43
- }
44
- return dir;
45
- }
46
-
47
- function statePath(projectRoot) {
48
- return path.join(projectRoot, '.claude', '.context-watchdog.json');
49
- }
50
-
51
- function loadState(projectRoot, sessionId) {
52
- const fp = statePath(projectRoot);
53
- try {
54
- if (fs.existsSync(fp)) {
55
- const state = JSON.parse(fs.readFileSync(fp, 'utf8'));
56
- if (state.sessionId === sessionId) return state;
57
- }
58
- } catch {}
59
- // New session or corrupted state - reset
60
- return {
61
- sessionId,
62
- toolCalls: 0,
63
- compactCount: 0,
64
- lastWarning: 'none', // none | early | urgent | compact
65
- stopBlocks: 0,
66
- };
67
- }
68
-
69
- function saveState(projectRoot, state) {
70
- try {
71
- fs.writeFileSync(statePath(projectRoot), JSON.stringify(state));
72
- } catch {}
73
- }
74
-
75
- function handoffRecentlyWritten(projectRoot) {
76
- const fp = path.join(projectRoot, 'SESSION-HANDOFF.md');
77
- try {
78
- if (fs.existsSync(fp)) {
79
- const age = Date.now() - fs.statSync(fp).mtimeMs;
80
- return age < 120_000; // Written within last 2 minutes
81
- }
82
- } catch {}
83
- return false;
84
- }
85
-
86
- // Output helpers - schema differs by hook event type
87
- let _hookEvent = null; // Set during processHook
88
-
89
- function allow(message) {
90
- if (_hookEvent === 'Stop') {
91
- // Stop schema: { continue?, stopReason? }
92
- console.log(JSON.stringify({}));
93
- } else if (_hookEvent === 'PreCompact') {
94
- // PreCompact: just output empty or with message
95
- if (message) {
96
- console.log(JSON.stringify({ additionalContext: message }));
97
- } else {
98
- console.log(JSON.stringify({}));
99
- }
100
- } else {
101
- // PreToolUse/PostToolUse schema
102
- const out = { decision: 'allow' };
103
- if (message) out.message = message;
104
- console.log(JSON.stringify(out));
105
- }
106
- process.exit(0);
107
- }
108
-
109
- function block(reason) {
110
- if (_hookEvent === 'Stop') {
111
- // Stop schema: continue=true means "don't stop, keep going"
112
- console.log(JSON.stringify({ continue: true, stopReason: reason }));
113
- } else {
114
- console.log(JSON.stringify({ decision: 'block', reason }));
115
- }
116
- process.exit(0);
117
- }
118
-
119
- // --- Main ---
120
-
121
- let input = '';
122
- process.stdin.setEncoding('utf8');
123
- process.stdin.on('data', chunk => input += chunk);
124
- process.stdin.on('end', () => {
125
- try {
126
- processHook(JSON.parse(input));
127
- } catch {
128
- allow();
129
- }
130
- });
131
-
132
- function processHook(data) {
133
- const projectRoot = getProjectRoot();
134
- const sessionId = data.session_id || '';
135
- const state = loadState(projectRoot, sessionId);
136
- const event = data.hook_event_name;
137
- _hookEvent = event; // Set for allow/block output formatting
138
-
139
- // ─── Layer 1: PreCompact (auto) ────────────────────────
140
- // Context IS full. Escalating response by compaction count.
141
- if (event === 'PreCompact') {
142
- state.compactCount++;
143
- state.lastWarning = 'compact';
144
- saveState(projectRoot, state);
145
-
146
- // 1st compaction: inform — context is still usable
147
- if (state.compactCount === 1) {
148
- allow(`📋 Context compacting (1st time). Context is still good — consider running /handoff soon to preserve state.`);
149
- }
150
-
151
- // 2nd compaction: strongly urge handoff — quality starts degrading
152
- if (state.compactCount === 2) {
153
- allow(
154
- `⚠️ Context compacting for the 2nd time. Earlier details are now a summary-of-a-summary.\n\n` +
155
- `Strongly recommended: run /handoff now and start a fresh session with /recap.\n` +
156
- `Continuing risks: forgetting decisions, re-reading files, repeating mistakes.`
157
- );
158
- }
159
-
160
- // 3rd+ compaction: force handoff
161
- if (state.compactCount >= 3) {
162
- allow(
163
- `🛑 Context compacting for the ${ordinal(state.compactCount)} time — session is significantly degraded.\n\n` +
164
- `You should run /handoff and start fresh. Continuing will lead to:\n` +
165
- `- Forgotten decisions and context\n` +
166
- `- Re-reading files already read\n` +
167
- `- Potential mistakes from lost context\n\n` +
168
- `Please run /handoff now.`
169
- );
170
- }
171
- }
172
-
173
- // ─── Layer 2: PostToolUse (Task) - agent call counter ──
174
- if (event === 'PostToolUse' && data.tool_name === 'Task') {
175
- state.toolCalls++;
176
- saveState(projectRoot, state);
177
-
178
- // Skip warnings if compact already fired (more urgent message already sent)
179
- if (state.lastWarning === 'compact') {
180
- allow();
181
- }
182
-
183
- // Urgent warning
184
- if (state.toolCalls === URGENT_WARNING_CALLS && state.lastWarning !== 'urgent') {
185
- state.lastWarning = 'urgent';
186
- saveState(projectRoot, state);
187
- allow(`📊 ${state.toolCalls} agent calls this session. Context may be getting full - consider /handoff.`);
188
- }
189
-
190
- // Early warning
191
- if (state.toolCalls === EARLY_WARNING_CALLS && state.lastWarning === 'none') {
192
- state.lastWarning = 'early';
193
- saveState(projectRoot, state);
194
- allow(`📊 Context check: ${state.toolCalls} agent calls. Consider /handoff soon.`);
195
- }
196
-
197
- allow();
198
- }
199
-
200
- // ─── Layer 3: Stop - safety net ────────────────────────
201
- // Block stop if context was heavily compacted and no handoff written.
202
- if (event === 'Stop') {
203
- // Prevent infinite loop: if stop hook already active, let it through
204
- if (data.stop_hook_active) {
205
- allow();
206
- }
207
-
208
- // After 2+ compactions (any mode), block stop until handoff is written
209
- const shouldBlock = state.compactCount >= 2 && state.stopBlocks < MAX_STOP_BLOCKS;
210
-
211
- if (shouldBlock && !handoffRecentlyWritten(projectRoot)) {
212
- state.stopBlocks++;
213
- saveState(projectRoot, state);
214
- block(
215
- `Context was compacted ${state.compactCount} time(s) but no handoff found.\n\n` +
216
- `Before stopping, you MUST:\n` +
217
- `1. Write SESSION-HANDOFF.md with current state and next steps\n` +
218
- `2. Update DEVELOPMENT.md with progress\n` +
219
- `3. Run /save "Handoff: ${state.compactCount}x compacted"\n` +
220
- `4. Tell user: "Session degraded after ${state.compactCount} compactions. Start fresh with /recap."`
221
- );
222
- }
223
-
224
- allow();
225
- }
226
-
227
- // Default - unknown event, output safe empty JSON
228
- console.log(JSON.stringify({}));
229
- process.exit(0);
230
- }
@@ -1,465 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * <hook-name>delegation-reminder</hook-name>
4
- * <purpose>Enforces delegation pattern - orchestrator should delegate, not do directly</purpose>
5
- * <triggers>PreToolUse</triggers>
6
- *
7
- * delegation-reminder.cjs
8
- *
9
- * HARD BLOCKS (data safety - writes only):
10
- * - MCP write tools: create_activity, update_activity → Dmitri
11
- * - install_workflow → Helga (use SDK)
12
- *
13
- * SOFT SUGGESTIONS (allows but reminds - specialists may need direct access):
14
- * - MCP read tools: list_activities, get_workflow_schema, etc. → appropriate specialist
15
- * - workspace/ reads → Kenji (but Helga/Viktor/Alejandro/Ingrid need access too)
16
- * - Glob/Grep code searches → Explore agent
17
- * - Task(giuseppe) for new app: Suggest ui-designer first
18
- * - Task(giuseppe) for demo/mockup: Suggest marco-mockup instead
19
- * - workspace/ writes: Suggest Helga
20
- * - apps/ files: Suggest Giuseppe
21
- * - .claude/agents/: Suggest Builder
22
- * - .claude/skills/: Suggest Ada
23
- * - git commit: Suggest Svetlana for review
24
- * - After .ts/.tsx edits: Suggest Tanya for tests
25
- *
26
- * SILENTLY ALLOWS:
27
- * - Schema/list tools used by multiple specialists (get_workflow_schema, list_workflows, etc.)
28
- *
29
- * SKIPS:
30
- * - When called from within a subagent (checks agent stack + env vars)
31
- *
32
- * NOTE: File read/write suggestions are ALWAYS soft (allow + message).
33
- * Only MCP write tools and built-in agent types are hard-blocked.
34
- *
35
- * Hook type: PreToolUse
36
- */
37
-
38
- const fs = require('fs');
39
- const path = require('path');
40
- const os = require('os');
41
-
42
- // Cross-platform temp directory
43
- const TEMP_DIR = os.tmpdir();
44
-
45
- // Agent stack file maintained by builder-mode-manager.cjs
46
- const AGENT_STACK_FILE = path.join(TEMP_DIR, '.claude-agent-stack.json');
47
-
48
- /**
49
- * Check if we're running inside a subagent.
50
- * Uses multiple detection methods:
51
- * 1. Agent stack file (maintained by builder-mode-manager.cjs)
52
- * 2. CLAUDE_SUBAGENT environment variable (set by Claude Code Task tool)
53
- * 3. CLAUDE_AGENT_* environment variables (agent identity markers)
54
- */
55
- function isInsideSubagent() {
56
- // Method 1: Check agent stack file
57
- try {
58
- const stack = JSON.parse(fs.readFileSync(AGENT_STACK_FILE, 'utf8'));
59
- if (stack.agents && stack.agents.length > 0) {
60
- return true;
61
- }
62
- } catch (e) {
63
- // File doesn't exist or invalid JSON - continue to other methods
64
- }
65
-
66
- // Method 2: Check CLAUDE_SUBAGENT env var (may be set by Task tool)
67
- if (process.env.CLAUDE_SUBAGENT === 'true' || process.env.CLAUDE_SUBAGENT === '1') {
68
- return true;
69
- }
70
-
71
- // Method 3: Check for agent identity markers in environment
72
- // When Task tool spawns a subagent, certain env vars may be present
73
- if (process.env.CLAUDE_AGENT_TYPE || process.env.CLAUDE_AGENT_ID) {
74
- return true;
75
- }
76
-
77
- return false;
78
- }
79
-
80
- // Tool -> Agent mappings
81
- const MCP_TOOL_AGENTS = {
82
- // Kenji - data reader
83
- 'mcp__hailer__list_activities': 'agent-kenji-data-reader',
84
- 'mcp__hailer__count_activities': 'agent-kenji-data-reader',
85
- 'mcp__hailer__get_activity': 'agent-kenji-data-reader',
86
- 'mcp__hailer__list_workflows': 'agent-kenji-data-reader',
87
- 'mcp__hailer__list_workflows_minimal': 'agent-kenji-data-reader',
88
- 'mcp__hailer__get_workflow_schema': 'agent-kenji-data-reader',
89
- 'mcp__hailer__list_workflow_phases': 'agent-kenji-data-reader',
90
-
91
- // Dmitri - activity CRUD
92
- 'mcp__hailer__create_activity': 'agent-dmitri-activity-crud',
93
- 'mcp__hailer__update_activity': 'agent-dmitri-activity-crud',
94
-
95
- // Viktor - insights
96
- 'mcp__hailer__preview_insight': 'agent-viktor-sql-insights',
97
- 'mcp__hailer__get_insight_data': 'agent-viktor-sql-insights',
98
- 'mcp__hailer__list_insights': 'agent-viktor-sql-insights',
99
-
100
- // Yevgeni - discussions
101
- 'mcp__hailer__list_my_discussions': 'agent-yevgeni-discussions',
102
- 'mcp__hailer__fetch_discussion_messages': 'agent-yevgeni-discussions',
103
- 'mcp__hailer__add_discussion_message': 'agent-yevgeni-discussions',
104
- 'mcp__hailer__join_discussion': 'agent-yevgeni-discussions',
105
- 'mcp__hailer__leave_discussion': 'agent-yevgeni-discussions',
106
- 'mcp__hailer__invite_discussion_members': 'agent-yevgeni-discussions',
107
-
108
- // Permissions
109
- 'mcp__hailer__list_apps': 'agent-permissions-handler',
110
- 'mcp__hailer__add_app_member': 'agent-permissions-handler',
111
- 'mcp__hailer__remove_app_member': 'agent-permissions-handler',
112
- 'mcp__hailer__search_workspace_users': 'agent-permissions-handler',
113
-
114
- // Giuseppe - app scaffold and local dev
115
- 'mcp__hailer__scaffold_hailer_app': 'agent-giuseppe-app-builder',
116
- 'mcp__hailer__create_app': 'agent-giuseppe-app-builder',
117
-
118
- // Helga - workflow config (use SDK, not MCP)
119
- 'mcp__hailer__install_workflow': 'agent-helga-workflow-config',
120
- 'mcp__hailer__create_workflow': 'agent-helga-workflow-config',
121
- 'mcp__hailer__update_workflow': 'agent-helga-workflow-config',
122
- 'mcp__hailer__delete_workflow': 'agent-helga-workflow-config',
123
- };
124
-
125
- // File patterns that suggest delegation
126
- const FILE_PATTERN_AGENTS = {
127
- 'workspace/': 'agent-kenji-data-reader',
128
- '/workspace/': 'agent-kenji-data-reader',
129
- 'apps/': 'agent-giuseppe-app-builder',
130
- '/apps/': 'agent-giuseppe-app-builder',
131
- '.claude/agents/': 'agent-builder-agent-creator',
132
- '.claude/skills/': 'agent-ada-skill-builder',
133
- };
134
-
135
- // All file read/write suggestions always allow with a soft message.
136
- // Only MCP write tools (create_activity, update_activity, install_workflow)
137
- // and built-in agent types are hard-blocked.
138
-
139
- // Read stdin asynchronously for better cross-platform support
140
- let stdinData = '';
141
- process.stdin.setEncoding('utf8');
142
- process.stdin.on('data', chunk => stdinData += chunk);
143
- process.stdin.on('end', () => {
144
- try {
145
- const input = JSON.parse(stdinData);
146
- processInput(input);
147
- } catch (e) {
148
- console.error(`[delegation-reminder] Failed to parse input: ${e.message}`);
149
- console.log(JSON.stringify({ decision: 'allow' }));
150
- process.exit(0);
151
- }
152
- });
153
-
154
- // Check if stdin is TTY (no piped input)
155
- if (process.stdin.isTTY) {
156
- console.log(JSON.stringify({ decision: 'allow' }));
157
- process.exit(0);
158
- }
159
-
160
- function processInput(input) {
161
- const { tool_name, tool_input } = input;
162
-
163
- // Skip if running inside a subagent (check agent stack, not env var)
164
- if (isInsideSubagent()) {
165
- console.log(JSON.stringify({ decision: "allow" }));
166
- return;
167
- }
168
-
169
- // WORKFLOW SUGGESTIONS: Task tool spawning
170
- if (tool_name === 'Task') {
171
- const agentType = tool_input?.subagent_type || '';
172
- // ReDoS protection: limit prompt size before regex matching
173
- let prompt = (tool_input?.prompt || '').toLowerCase();
174
- if (prompt.length > 10000) prompt = prompt.substring(0, 10000);
175
-
176
- // HARD BLOCK: Built-in agent types - use specialized agents instead
177
- // Built-in agents lack Skill tool and specialized domain knowledge
178
- const BUILTIN_AGENTS = {
179
- 'Plan': 'Agents should plan their own work. Give the executing agent a prompt that includes research + planning + implementation. E.g., Ingrid can load SDK-document-templates skill and plan the template herself.',
180
- 'general-purpose': 'Use the appropriate specialized agent. Check /help:agents for the right one.',
181
- 'Bash': 'Run bash commands directly with the Bash tool instead of spawning a Bash agent.',
182
- };
183
-
184
- if (BUILTIN_AGENTS[agentType]) {
185
- console.log(JSON.stringify({
186
- decision: "block",
187
- reason: `🚫 BUILT-IN AGENT BLOCKED: "${agentType}" is a Claude Code built-in agent. Use specialized agents instead.\n\n${BUILTIN_AGENTS[agentType]}\n\nAgents should do their own planning+research+execution. Include research steps in the agent's prompt instead of splitting into separate Plan/Explore agents.`,
188
- }));
189
- return;
190
- }
191
-
192
- // Giuseppe for new app - suggest ui-designer first
193
- if (agentType.includes('giuseppe')) {
194
- // Check if it's a demo/mockup request - use word boundaries to avoid false positives
195
- if (/\b(demo|mockup|prototype)\b/i.test(prompt) ||
196
- ((/\b(show|present)\b/i.test(prompt)) &&
197
- (/\b(customer|client|stakeholder)\b/i.test(prompt)))) {
198
- console.log(JSON.stringify({
199
- decision: "allow",
200
- message: `💡 FOR DEMOS: Consider using agent-marco-mockup-builder instead.\n\nMarco creates interactive demos with mock data - perfect for showing customers concepts.\nGiuseppe builds production apps.\n\nUse marco for: demos, prototypes, "what if" explorations\nUse giuseppe for: real apps with SDK integration`,
201
- }));
202
- return;
203
- }
204
-
205
- // Check if design was mentioned
206
- if (!prompt.includes('design') && !prompt.includes('spec') && !prompt.includes('following the design')) {
207
- console.log(JSON.stringify({
208
- decision: "allow",
209
- message: `💡 APP WORKFLOW: Consider the full flow:\n\n1. Plan Mode → understand requirements\n2. ui-designer → create design spec\n3. Giuseppe → build the app\n\nIf you haven't created a design spec yet, consider:\nTask(subagent_type="ui-designer", prompt='{"task":"design_app","requirements":"..."}')`,
210
- }));
211
- return;
212
- }
213
- }
214
- }
215
-
216
- // SUGGEST: Git commit - run tests and code review first
217
- if (tool_name === 'Bash') {
218
- const command = tool_input?.command || '';
219
-
220
- if (command.includes('git commit')) {
221
- console.log(JSON.stringify({
222
- decision: "allow",
223
- message: `💡 BEFORE COMMIT: Consider running tests and code review.\n\n1. Task(subagent_type="agent-tanya-test-runner", prompt='{"task":"run_tests"}')\n2. Task(subagent_type="agent-svetlana-code-review", prompt='{"task":"review_changes"}')\n\nTanya runs tests, Svetlana checks for bugs and security issues.`,
224
- }));
225
- return;
226
- }
227
-
228
- // Suggest tests after build passes
229
- if (command.includes('npm run build') && !command.includes('test')) {
230
- console.log(JSON.stringify({
231
- decision: "allow",
232
- message: `💡 BUILD PASSED? Consider running tests.\n\nTask(subagent_type="agent-tanya-test-runner", prompt='{"task":"run_tests"}')\n\nTanya runs vitest/playwright and reports failures.`,
233
- }));
234
- return;
235
- }
236
- }
237
-
238
- // SOFT SUGGEST: Glob/Grep code searches - always soft (orchestrator needs these for delegation)
239
- // These are orchestration tools, not domain work - never block always
240
- if (tool_name === 'Glob' || tool_name === 'Grep') {
241
- console.log(JSON.stringify({
242
- decision: "allow",
243
- message: `💡 CODE SEARCH: For workspace/schema searches, delegate to Kenji.\nFor broader research, include search instructions in the appropriate agent's prompt.\n\n(Specialist agents may search within their domains - this is just a reminder.)`,
244
- }));
245
- return;
246
- }
247
-
248
- // SUGGEST: Web search - delegate to save context (always soft - orchestrator may need quick lookups)
249
- if (tool_name === 'WebSearch' || tool_name === 'WebFetch') {
250
- console.log(JSON.stringify({
251
- decision: "allow",
252
- message: `💡 SAVE CONTEXT: Consider delegating web research to agent-web-search.\n\nThe agent searches, fetches pages, and returns concise summaries instead of dumping raw content.\n\nTask(subagent_type="agent-web-search", prompt='{"query":"your question","context":"optional background"}')`,
253
- }));
254
- return;
255
- }
256
-
257
- // MCP tools - block writes, suggest for reads
258
- if (tool_name?.startsWith('mcp__hailer__')) {
259
- // HARD BLOCK: install_workflow should use SDK, not MCP
260
- // Enforced always mode - delegation is about correctness, not permissions
261
- if (tool_name === 'mcp__hailer__install_workflow') {
262
- console.log(JSON.stringify({
263
- decision: "block",
264
- reason: `🚫 USE SDK, NOT MCP: For workflow creation, use agent-helga-workflow-config with the SDK approach.
265
-
266
- Helga manages workflows via workspace/ files + npm commands, not MCP tools.
267
-
268
- Task(subagent_type="agent-helga-workflow-config", prompt='{"task":"create_workflow","name":"MyWorkflow","description":"..."}')
269
-
270
- The install_workflow MCP tool is for admin/dev use only.`,
271
- }));
272
- return;
273
- }
274
-
275
- // HARD BLOCK: Activity writes must go through Dmitri
276
- // Enforced always mode - Dmitri validates field formats
277
- if (tool_name === 'mcp__hailer__create_activity' || tool_name === 'mcp__hailer__update_activity') {
278
- console.log(JSON.stringify({
279
- decision: "block",
280
- reason: `🚫 DELEGATE TO DMITRI: Activity writes must go through agent-dmitri-activity-crud.
281
-
282
- Dmitri validates:
283
- - Required fields are provided
284
- - Field value formats (activitylink=string, date=timestamp)
285
- - Real MongoDB ObjectIds (not SDK enums)
286
-
287
- Task(subagent_type="agent-dmitri-activity-crud", prompt='{"task":"create","workflow_id":"...","phase_id":"...","activities":[...]}')`,
288
- }));
289
- return;
290
- }
291
-
292
- // MCP READ TOOLS: Always allow with soft message (never block, always)
293
- // Subagent detection is unreliable — we can't tell if Viktor or the orchestrator
294
- // is calling preview_insight. Blocking would break agents using their own tools.
295
- const suggestedAgent = MCP_TOOL_AGENTS[tool_name];
296
- if (suggestedAgent) {
297
- // Skip suggestion for tools that multiple agents legitimately use
298
- const multiAgentTools = [
299
- 'mcp__hailer__get_workflow_schema',
300
- 'mcp__hailer__list_workflows',
301
- 'mcp__hailer__list_workflows_minimal',
302
- 'mcp__hailer__list_workflow_phases',
303
- ];
304
-
305
- if (multiAgentTools.includes(tool_name)) {
306
- console.log(JSON.stringify({ decision: "allow" }));
307
- return;
308
- }
309
-
310
- // Always allow — agents need their own tools
311
- // (Viktor→preview_insight, Kenji→list_activities, etc.)
312
- console.log(JSON.stringify({
313
- decision: "allow",
314
- message: `💡 MCP TOOL: If you're the orchestrator, consider delegating to ${suggestedAgent}.`,
315
- }));
316
- return;
317
- }
318
-
319
- // Unknown MCP tool - allow with reminder
320
- console.log(JSON.stringify({
321
- decision: "allow",
322
- message: `💡 DELEGATE: Consider /help:agents for the right agent. Tool: ${tool_name}`,
323
- }));
324
- return;
325
- }
326
-
327
- // BLOCK: Reading workspace/ - must delegate to Kenji (with bypass option)
328
- if (tool_name === 'Read') {
329
- const filePath = tool_input?.file_path || '';
330
-
331
- // workspace/ reads - ALWAYS ALLOW (never block, always)
332
- // Multiple specialist agents (Helga, Viktor, Alejandro, Ingrid) need workspace access
333
- // Subagent detection isn't reliable, so we can't distinguish orchestrator from agents
334
- if (filePath.includes('workspace/') || filePath.includes('/workspace/')) {
335
- console.log(JSON.stringify({
336
- decision: "allow",
337
- message: `💡 WORKSPACE READ: If you're the orchestrator, consider delegating to Kenji.\n\nTask(subagent_type="agent-kenji-data-reader", prompt='{"task":"read_workspace_file","path":"${filePath}"}')\n\n(Specialist agents like Helga/Viktor need direct access - this is just a reminder.)`,
338
- }));
339
- return;
340
- }
341
-
342
- // Other file patterns - ALWAYS ALLOW reads (never block, always)
343
- // Agents need to read files in their domain (Giuseppe reads apps/, etc.)
344
- for (const [pattern, agent] of Object.entries(FILE_PATTERN_AGENTS)) {
345
- if (filePath.includes(pattern) && !pattern.includes('workspace')) {
346
- const suggestions = {
347
- 'apps/': 'Giuseppe builds and maintains apps. Consider delegating app work.',
348
- '.claude/agents/': 'Use agent-builder-agent-creator for creating/modifying agents.',
349
- '.claude/skills/': 'Use agent-ada-skill-builder for creating/modifying skills.',
350
- };
351
- const suggestion = suggestions[pattern];
352
- if (suggestion) {
353
- console.log(JSON.stringify({
354
- decision: "allow",
355
- message: `💡 CONSIDER DELEGATING: ${suggestion}\n\nAgent: ${agent}`,
356
- }));
357
- return;
358
- }
359
- }
360
- }
361
- }
362
-
363
- // SOFT REMIND: Write/Edit on various files
364
- // ALWAYS ALLOW writes — agents need to write in their domains
365
- // Subagent detection is unreliable, so blocking writes breaks agents
366
- if (tool_name === 'Write' || tool_name === 'Edit') {
367
- const filePath = tool_input?.file_path || '';
368
-
369
- // WORKSPACE WRITES: Suggest appropriate specialist (always allow)
370
- if (filePath.includes('workspace/')) {
371
- let message;
372
- if (filePath.includes('/functions/')) {
373
- message = `💡 FUNCTION FIELD CODE: If you're the orchestrator, use agent-alejandro-function-fields.`;
374
- } else if (filePath.includes('fields.ts')) {
375
- message = `💡 FIELD DEFINITIONS: If you're the orchestrator, use agent-helga-workflow-config for field config, agent-alejandro-function-fields for function code.`;
376
- } else if (filePath.includes('/templates/')) {
377
- message = `💡 DOCUMENT TEMPLATES: If you're the orchestrator, use agent-ingrid-doc-templates.`;
378
- } else if (filePath.includes('insights.ts')) {
379
- message = `💡 INSIGHTS: If you're the orchestrator, use agent-viktor-sql-insights.`;
380
- } else {
381
- message = `💡 WORKSPACE CONFIG: If you're the orchestrator, use agent-helga-workflow-config.`;
382
- }
383
- console.log(JSON.stringify({ decision: "allow", message }));
384
- return;
385
- }
386
-
387
- // Suggest delegation for agent/skill modifications (always allow)
388
- if (filePath.includes('.claude/agents/')) {
389
- console.log(JSON.stringify({
390
- decision: "allow",
391
- message: `💡 CONSIDER DELEGATING: Use agent-builder-agent-creator for agent modifications.`,
392
- }));
393
- return;
394
- }
395
-
396
- if (filePath.includes('.claude/skills/')) {
397
- console.log(JSON.stringify({
398
- decision: "allow",
399
- message: `💡 CONSIDER DELEGATING: Use agent-ada-skill-builder for skill modifications.`,
400
- }));
401
- return;
402
- }
403
-
404
- // .claude/ config files - always allow
405
- if (filePath.includes('.claude/') && (filePath.endsWith('.json') || filePath.endsWith('.cjs'))) {
406
- console.log(JSON.stringify({
407
- decision: "allow",
408
- message: `💡 CONFIG CHANGE: After editing .claude/ config, consider running audit.\n\nTask(subagent_type="agent-bjorn-config-audit", prompt='{"task":"audit_config"}')`,
409
- }));
410
- return;
411
- }
412
-
413
- if (filePath.includes('apps/') && (filePath.endsWith('.tsx') || filePath.endsWith('.ts'))) {
414
- console.log(JSON.stringify({
415
- decision: "allow",
416
- message: `💡 CONSIDER DELEGATING: If you're the orchestrator, use agent-giuseppe-app-builder for app code.`,
417
- }));
418
- return;
419
- }
420
-
421
- // Integration files
422
- if (filePath.includes('integrations/') || filePath.includes('activity-mover')) {
423
- console.log(JSON.stringify({
424
- decision: "allow",
425
- message: `💡 INTEGRATIONS: If you're the orchestrator, consider: agent-igor (movers), agent-ivan (monolith), agent-zara (Zapier).`,
426
- }));
427
- return;
428
- }
429
-
430
- // General .ts/.tsx code edits - allow with test reminder
431
- if ((filePath.endsWith('.ts') || filePath.endsWith('.tsx')) &&
432
- !filePath.includes('workspace/') &&
433
- !filePath.includes('apps/') &&
434
- !filePath.includes('.claude/')) {
435
- console.log(JSON.stringify({
436
- decision: "allow",
437
- message: `💡 CODE CHANGE: Consider running tests after editing.\n\nTask(subagent_type="agent-tanya-test-runner", prompt='{"task":"run_tests"}')`,
438
- }));
439
- return;
440
- }
441
- }
442
-
443
- // SUGGEST: Lars for debugging when errors mentioned in prompt
444
- if (tool_name === 'Task') {
445
- // ReDoS protection: limit prompt size before regex matching
446
- let prompt = (tool_input?.prompt || '').toLowerCase();
447
- if (prompt.length > 10000) prompt = prompt.substring(0, 10000);
448
- const agentType = tool_input?.subagent_type || '';
449
-
450
- // If spawning general-purpose or explore for debugging, suggest lars
451
- if ((agentType.includes('general') || agentType.includes('explore')) &&
452
- (prompt.includes('bug') || prompt.includes('debug') || prompt.includes('error') ||
453
- prompt.includes('not working') || prompt.includes('broken') || prompt.includes('why'))) {
454
- console.log(JSON.stringify({
455
- decision: "allow",
456
- message: `💡 FOR CODE ISSUES: Consider agent-lars-code-inspector for dead code, unused imports, and type errors.`,
457
- }));
458
- return;
459
- }
460
- }
461
-
462
- // Allow the tool call
463
- console.log(JSON.stringify({ decision: "allow" }));
464
- process.exit(0);
465
- }