@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,494 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * <hook-name>app-edit-guard</hook-name>
4
- *
5
- * <purpose>
6
- * Blocks direct edits to Hailer app directories.
7
- * Forces use of builder agents for app development.
8
- * </purpose>
9
- *
10
- * <triggers>
11
- * - PreToolUse on Write and Edit tools
12
- * - Only when file is inside a detected Hailer app directory
13
- * </triggers>
14
- *
15
- * <detection>
16
- * A directory is a Hailer app if it contains:
17
- * - public/manifest.json with "appId" field
18
- * - package.json with @hailer/app-sdk dependency
19
- * - vite.config.ts referencing hailer
20
- * </detection>
21
- *
22
- * <allowed-when>
23
- * - Builder agent is active (/tmp/.claude-builder-agent-active exists)
24
- * - Builder mode enabled for specific app (--builder-on)
25
- * - App released for manual editing (--release)
26
- * </allowed-when>
27
- *
28
- * <cli-commands>
29
- * --agent-on/off: Global builder mode (affects all apps + src/)
30
- * --builder-on/off: Per-app builder mode
31
- * --release/revoke: Manual editing permission
32
- * --check: Verify if path is Hailer app
33
- * --list: Show released apps
34
- * </cli-commands>
35
- *
36
- * <shared-files>
37
- * /tmp/.claude-builder-agent-active (shared with builder-mode-manager, src-edit-guard)
38
- * /tmp/.claude-released-apps.json
39
- * /tmp/.claude-builder-mode/
40
- * </shared-files>
41
- */
42
-
43
- const fs = require('fs');
44
- const path = require('path');
45
- const os = require('os');
46
-
47
- // Skip in subagent context - subagents can't use AskUserQuestion or Bash to recover
48
- // Orchestrator should use --agent-on before spawning, but this is a safety fallback
49
- if (process.env.CLAUDE_AGENT_ID || process.env.CLAUDE_SUBAGENT) {
50
- console.log(JSON.stringify({ decision: 'allow' }));
51
- process.exit(0);
52
- }
53
-
54
- const TEMP_DIR = os.tmpdir();
55
- const RELEASE_TRACKER = path.join(TEMP_DIR, '.claude-released-apps.json');
56
- const BUILDER_MODE_DIR = path.join(TEMP_DIR, '.claude-builder-mode');
57
- const BUILDER_AGENT_ACTIVE = path.join(TEMP_DIR, '.claude-builder-agent-active');
58
-
59
- // Read hook input from stdin
60
- let input = '';
61
- process.stdin.setEncoding('utf8');
62
- process.stdin.on('data', chunk => input += chunk);
63
- process.stdin.on('end', () => {
64
- try {
65
- const data = JSON.parse(input);
66
- processHook(data);
67
- } catch (e) {
68
- // Invalid JSON - fail safe by BLOCKING
69
- outputBlock('Hook received invalid input - blocking for safety');
70
- }
71
- });
72
-
73
- function outputAllow() {
74
- console.log(JSON.stringify({ decision: 'allow' }));
75
- process.exit(0);
76
- }
77
-
78
- function outputBlock(message) {
79
- console.log(JSON.stringify({
80
- decision: 'block',
81
- reason: message
82
- }));
83
- process.exit(0);
84
- }
85
-
86
- /**
87
- * Check if a directory is a Hailer app by examining its contents
88
- */
89
- function isHailerAppDirectory(dirPath) {
90
- try {
91
- // Check 1: public/manifest.json with appId
92
- const manifestPath = path.join(dirPath, 'public', 'manifest.json');
93
- if (fs.existsSync(manifestPath)) {
94
- try {
95
- const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
96
- if (manifest.appId || manifest.name) {
97
- return { isApp: true, name: manifest.name || path.basename(dirPath), reason: 'manifest.json' };
98
- }
99
- } catch {
100
- // Invalid JSON in manifest, still might be a Hailer app structure
101
- }
102
- }
103
-
104
- // Check 2: package.json with @hailer/app-sdk
105
- const packagePath = path.join(dirPath, 'package.json');
106
- if (fs.existsSync(packagePath)) {
107
- try {
108
- const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
109
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
110
- if (deps['@hailer/app-sdk']) {
111
- return { isApp: true, name: pkg.name || path.basename(dirPath), reason: '@hailer/app-sdk dependency' };
112
- }
113
- } catch {
114
- // Invalid package.json
115
- }
116
- }
117
-
118
- // Check 3: vite.config with hailer in comments or specific CORS config
119
- const viteConfigPath = path.join(dirPath, 'vite.config.ts');
120
- if (fs.existsSync(viteConfigPath)) {
121
- try {
122
- const viteConfig = fs.readFileSync(viteConfigPath, 'utf8');
123
- if (viteConfig.includes('hailer') || viteConfig.includes('app.hailer.com')) {
124
- return { isApp: true, name: path.basename(dirPath), reason: 'vite.config.ts hailer reference' };
125
- }
126
- } catch {
127
- // Can't read vite config
128
- }
129
- }
130
-
131
- return { isApp: false };
132
- } catch {
133
- return { isApp: false };
134
- }
135
- }
136
-
137
- /**
138
- * Walk up the directory tree to find if file is inside a Hailer app
139
- */
140
- function findHailerAppRoot(filePath) {
141
- let currentDir = path.dirname(filePath);
142
- const root = path.parse(currentDir).root;
143
-
144
- // Walk up max 10 levels
145
- for (let i = 0; i < 10 && currentDir !== root; i++) {
146
- const result = isHailerAppDirectory(currentDir);
147
- if (result.isApp) {
148
- return { ...result, path: currentDir };
149
- }
150
- currentDir = path.dirname(currentDir);
151
- }
152
-
153
- return null;
154
- }
155
-
156
- /**
157
- * Check if an app directory has been released for manual editing
158
- */
159
- function isAppReleased(appPath) {
160
- try {
161
- if (!fs.existsSync(RELEASE_TRACKER)) {
162
- return false;
163
- }
164
- const released = JSON.parse(fs.readFileSync(RELEASE_TRACKER, 'utf8'));
165
- return released.includes(path.resolve(appPath));
166
- } catch {
167
- return false;
168
- }
169
- }
170
-
171
- /**
172
- * Check if a builder agent is currently active (global flag)
173
- * Main Claude enables this before spawning builder agents
174
- */
175
- function isBuilderAgentActive() {
176
- return fs.existsSync(BUILDER_AGENT_ACTIVE);
177
- }
178
-
179
- /**
180
- * Check if builder mode is active for an app directory
181
- * Builder mode is enabled by creating a marker file in BUILDER_MODE_DIR
182
- */
183
- function isBuilderModeActive(appPath) {
184
- try {
185
- if (!fs.existsSync(BUILDER_MODE_DIR)) {
186
- return false;
187
- }
188
- // Hash the app path to create a unique marker filename
189
- const normalizedPath = path.resolve(appPath);
190
- const markerFile = path.join(BUILDER_MODE_DIR, Buffer.from(normalizedPath).toString('base64').replace(/[/+=]/g, '_'));
191
- return fs.existsSync(markerFile);
192
- } catch {
193
- return false;
194
- }
195
- }
196
-
197
- /**
198
- * Enable builder mode for an app directory
199
- */
200
- function enableBuilderMode(appPath) {
201
- const normalizedPath = path.resolve(appPath);
202
- if (!fs.existsSync(BUILDER_MODE_DIR)) {
203
- fs.mkdirSync(BUILDER_MODE_DIR, { recursive: true });
204
- }
205
- const markerFile = path.join(BUILDER_MODE_DIR, Buffer.from(normalizedPath).toString('base64').replace(/[/+=]/g, '_'));
206
- fs.writeFileSync(markerFile, JSON.stringify({ appPath: normalizedPath, enabledAt: new Date().toISOString() }));
207
- return markerFile;
208
- }
209
-
210
- /**
211
- * Disable builder mode for an app directory
212
- */
213
- function disableBuilderMode(appPath) {
214
- const normalizedPath = path.resolve(appPath);
215
- const markerFile = path.join(BUILDER_MODE_DIR, Buffer.from(normalizedPath).toString('base64').replace(/[/+=]/g, '_'));
216
- if (fs.existsSync(markerFile)) {
217
- fs.unlinkSync(markerFile);
218
- return true;
219
- }
220
- return false;
221
- }
222
-
223
- function processHook(data) {
224
- const { tool_name, tool_input } = data;
225
-
226
- // Only guard Write and Edit tools
227
- if (tool_name !== 'Write' && tool_name !== 'Edit') {
228
- outputAllow();
229
- return;
230
- }
231
-
232
- const filePath = tool_input?.file_path;
233
- if (!filePath) {
234
- outputAllow();
235
- return;
236
- }
237
-
238
- // Normalize path
239
- const normalizedPath = path.resolve(filePath);
240
-
241
- // Find if this file is inside a Hailer app
242
- const appInfo = findHailerAppRoot(normalizedPath);
243
-
244
- if (!appInfo) {
245
- // Not in a Hailer app directory
246
- outputAllow();
247
- return;
248
- }
249
-
250
- // Check if a builder agent is globally active - ALLOW
251
- // Main Claude enables this before spawning builder agents
252
- if (isBuilderAgentActive()) {
253
- outputAllow();
254
- return;
255
- }
256
-
257
- // Check if builder mode is active for this app - ALLOW
258
- // This is the primary mechanism for spawned builder agents
259
- if (isBuilderModeActive(appInfo.path)) {
260
- outputAllow();
261
- return;
262
- }
263
-
264
- // Check if this app has been released for manual editing - ALLOW
265
- if (isAppReleased(appInfo.path)) {
266
- outputAllow();
267
- return;
268
- }
269
-
270
- // BLOCK with helpful message
271
- outputBlock(`
272
- đŸšĢ BLOCKED: Direct edit to Hailer app "${appInfo.name}"
273
-
274
- Detected as Hailer app via: ${appInfo.reason}
275
- App directory: ${appInfo.path}
276
-
277
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
278
- WHY: Hailer apps must be built by a specialized builder agent
279
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
280
-
281
- The builder agent has:
282
- â€ĸ Access to @hailer/app-sdk documentation
283
- â€ĸ Live dev server feedback for iteration
284
- â€ĸ Proper TypeScript patterns for Hailer apps
285
-
286
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
287
- TO PROCEED: Spawn a builder agent
288
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
289
-
290
- 1. Load the spawn skill:
291
- Skill("spawn-app-builder")
292
-
293
- 2. Follow the skill instructions to spawn the agent
294
-
295
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
296
- OR: Release for manual editing (if user explicitly requests)
297
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
298
-
299
- Ask the user first! If they confirm manual editing, run:
300
- Bash: node "${process.argv[1].replace(/'/g, "'\\''")}" --release "${appInfo.path}"
301
-
302
- Then retry your edit.
303
- `);
304
- }
305
-
306
- // CLI: Release an app for manual editing
307
- if (process.argv[2] === '--release' && process.argv[3]) {
308
- const appPath = path.resolve(process.argv[3]);
309
-
310
- // Verify it's actually a Hailer app
311
- const appInfo = isHailerAppDirectory(appPath);
312
- if (!appInfo.isApp) {
313
- console.error(`Error: ${appPath} is not a Hailer app directory`);
314
- process.exit(1);
315
- }
316
-
317
- // Load existing releases
318
- let released = [];
319
- try {
320
- if (fs.existsSync(RELEASE_TRACKER)) {
321
- released = JSON.parse(fs.readFileSync(RELEASE_TRACKER, 'utf8'));
322
- }
323
- } catch {
324
- released = [];
325
- }
326
-
327
- // Add this app if not already released
328
- if (!released.includes(appPath)) {
329
- released.push(appPath);
330
- fs.writeFileSync(RELEASE_TRACKER, JSON.stringify(released, null, 2));
331
- console.log(`✅ Released "${appInfo.name}" for manual editing`);
332
- console.log(` Path: ${appPath}`);
333
- } else {
334
- console.log(`â„šī¸ "${appInfo.name}" was already released`);
335
- }
336
- process.exit(0);
337
- }
338
-
339
- // CLI: List released apps
340
- if (process.argv[2] === '--list') {
341
- try {
342
- if (fs.existsSync(RELEASE_TRACKER)) {
343
- const released = JSON.parse(fs.readFileSync(RELEASE_TRACKER, 'utf8'));
344
- if (released.length === 0) {
345
- console.log('No apps released for manual editing');
346
- } else {
347
- console.log('Released apps:');
348
- released.forEach(p => console.log(` - ${p}`));
349
- }
350
- } else {
351
- console.log('No apps released for manual editing');
352
- }
353
- } catch {
354
- console.log('No apps released for manual editing');
355
- }
356
- process.exit(0);
357
- }
358
-
359
- // CLI: Enable builder mode for an app
360
- if (process.argv[2] === '--builder-on' && process.argv[3]) {
361
- const appPath = path.resolve(process.argv[3]);
362
-
363
- // Verify it's actually a Hailer app
364
- const appInfo = isHailerAppDirectory(appPath);
365
- if (!appInfo.isApp) {
366
- console.error(`Error: ${appPath} is not a Hailer app directory`);
367
- process.exit(1);
368
- }
369
-
370
- enableBuilderMode(appPath);
371
- console.log(`🔧 Builder mode ENABLED for "${appInfo.name}"`);
372
- console.log(` Path: ${appPath}`);
373
- console.log(` Spawned agents can now edit this app`);
374
- process.exit(0);
375
- }
376
-
377
- // CLI: Disable builder mode for an app
378
- if (process.argv[2] === '--builder-off' && process.argv[3]) {
379
- const appPath = path.resolve(process.argv[3]);
380
-
381
- if (disableBuilderMode(appPath)) {
382
- console.log(`🔒 Builder mode DISABLED for: ${appPath}`);
383
- } else {
384
- console.log(`â„šī¸ Builder mode was not active for: ${appPath}`);
385
- }
386
- process.exit(0);
387
- }
388
-
389
- // CLI: Revoke release
390
- if (process.argv[2] === '--revoke' && process.argv[3]) {
391
- const appPath = path.resolve(process.argv[3]);
392
-
393
- try {
394
- if (fs.existsSync(RELEASE_TRACKER)) {
395
- let released = JSON.parse(fs.readFileSync(RELEASE_TRACKER, 'utf8'));
396
- const before = released.length;
397
- released = released.filter(p => p !== appPath);
398
- if (released.length < before) {
399
- fs.writeFileSync(RELEASE_TRACKER, JSON.stringify(released, null, 2));
400
- console.log(`✅ Revoked manual editing for: ${appPath}`);
401
- } else {
402
- console.log(`â„šī¸ App was not in released list: ${appPath}`);
403
- }
404
- }
405
- } catch {
406
- console.error('Error reading release tracker');
407
- }
408
- process.exit(0);
409
- }
410
-
411
- // CLI: Check if a path is a Hailer app
412
- if (process.argv[2] === '--check' && process.argv[3]) {
413
- const checkPath = path.resolve(process.argv[3]);
414
- const result = isHailerAppDirectory(checkPath);
415
- if (result.isApp) {
416
- console.log(`✅ Hailer app detected: ${result.name}`);
417
- console.log(` Detected via: ${result.reason}`);
418
- console.log(` Builder mode: ${isBuilderModeActive(checkPath) ? 'ACTIVE' : 'Off'}`);
419
- console.log(` Manual release: ${isAppReleased(checkPath) ? 'Yes' : 'No'}`);
420
- } else {
421
- console.log(`❌ Not a Hailer app: ${checkPath}`);
422
- }
423
- process.exit(0);
424
- }
425
-
426
- // CLI: Enable global builder agent mode
427
- if (process.argv[2] === '--agent-on') {
428
- fs.writeFileSync(BUILDER_AGENT_ACTIVE, JSON.stringify({ enabledAt: new Date().toISOString() }));
429
- console.log('🔧 Builder agent mode ENABLED globally');
430
- console.log(' All Hailer app edits are now allowed');
431
- console.log(' Run --agent-off when done');
432
- process.exit(0);
433
- }
434
-
435
- // CLI: Disable global builder agent mode
436
- if (process.argv[2] === '--agent-off') {
437
- if (fs.existsSync(BUILDER_AGENT_ACTIVE)) {
438
- fs.unlinkSync(BUILDER_AGENT_ACTIVE);
439
- console.log('🔒 Builder agent mode DISABLED');
440
- } else {
441
- console.log('â„šī¸ Builder agent mode was not active');
442
- }
443
- process.exit(0);
444
- }
445
-
446
- // CLI: Check global builder agent status
447
- if (process.argv[2] === '--agent-status') {
448
- if (fs.existsSync(BUILDER_AGENT_ACTIVE)) {
449
- console.log('🔧 Builder agent mode is ACTIVE');
450
- } else {
451
- console.log('🔒 Builder agent mode is OFF');
452
- }
453
- process.exit(0);
454
- }
455
-
456
- // CLI: Help
457
- if (process.argv[2] === '--help' || process.argv[2] === '-h') {
458
- console.log(`
459
- Hailer App Edit Guard - Bulletproof protection for Hailer apps
460
-
461
- UNIFIED SYSTEM: --agent-on/--agent-off controls BOTH this hook AND src-edit-guard.cjs.
462
- One command enables builder mode for Hailer apps AND src/ directory edits.
463
-
464
- Usage:
465
- Global Builder Agent Mode (RECOMMENDED for spawning agents):
466
- node app-edit-guard.cjs --agent-on Enable global builder mode
467
- node app-edit-guard.cjs --agent-off Disable global builder mode
468
- node app-edit-guard.cjs --agent-status Check if builder mode is active
469
-
470
- Per-App Builder Mode:
471
- node app-edit-guard.cjs --builder-on <path> Enable builder mode for an app
472
- node app-edit-guard.cjs --builder-off <path> Disable builder mode for an app
473
-
474
- Manual Editing (for direct edits by main agent):
475
- node app-edit-guard.cjs --release <path> Release an app for manual editing
476
- node app-edit-guard.cjs --revoke <path> Revoke manual editing permission
477
-
478
- Utilities:
479
- node app-edit-guard.cjs --check <path> Check if path is a Hailer app
480
- node app-edit-guard.cjs --list List all released apps
481
- node app-edit-guard.cjs --help Show this help
482
-
483
- Workflow for spawning builder agents (RECOMMENDED):
484
- 1. Main agent: node app-edit-guard.cjs --agent-on
485
- 2. Main agent spawns builder agent via Task tool
486
- 3. Builder agent can freely edit ANY Hailer app AND src/ files
487
- 4. Main agent: node app-edit-guard.cjs --agent-off
488
-
489
- As a hook:
490
- Reads JSON from stdin with tool_name and tool_input
491
- Outputs JSON with decision: "allow" or "block"
492
- `);
493
- process.exit(0);
494
- }