@clearlysh/beehaven 0.8.16

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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/dist/__tests__/_cli-switch.js +105 -0
  4. package/dist/__tests__/agent-wrap-probe.js +136 -0
  5. package/dist/agent-attribution.js +192 -0
  6. package/dist/agent-identity-daemon.js +135 -0
  7. package/dist/agent-onboard.js +156 -0
  8. package/dist/agent-scope.js +79 -0
  9. package/dist/agent-sessions.js +370 -0
  10. package/dist/agent-state.js +482 -0
  11. package/dist/app-manifest.js +221 -0
  12. package/dist/app-signer.js +54 -0
  13. package/dist/app-signing.js +127 -0
  14. package/dist/audio-play.js +98 -0
  15. package/dist/avatar-protocol.js +25 -0
  16. package/dist/avatar-route.js +79 -0
  17. package/dist/bee/cloud-proxy.js +130 -0
  18. package/dist/blocked-actions.js +120 -0
  19. package/dist/build-channel.js +101 -0
  20. package/dist/buildings/daemon-workspace.js +475 -0
  21. package/dist/claude-bridge.js +310 -0
  22. package/dist/claude-credential-store.js +633 -0
  23. package/dist/clearly-sync.js +518 -0
  24. package/dist/clearly.js +616 -0
  25. package/dist/cli-state.js +334 -0
  26. package/dist/cli.js +6973 -0
  27. package/dist/commands/agent-skills.js +302 -0
  28. package/dist/commands/agent.js +1310 -0
  29. package/dist/commands/app.js +1123 -0
  30. package/dist/commands/auth.js +171 -0
  31. package/dist/commands/building-shell.js +392 -0
  32. package/dist/commands/canvas.js +932 -0
  33. package/dist/commands/claude.js +218 -0
  34. package/dist/commands/compliance.js +387 -0
  35. package/dist/commands/compose.js +507 -0
  36. package/dist/commands/composition.js +95 -0
  37. package/dist/commands/connect-session.js +409 -0
  38. package/dist/commands/conversations.js +160 -0
  39. package/dist/commands/costs.js +443 -0
  40. package/dist/commands/d1.js +253 -0
  41. package/dist/commands/daemon-cmd.js +162 -0
  42. package/dist/commands/deploy.js +164 -0
  43. package/dist/commands/design.js +617 -0
  44. package/dist/commands/dev-generate.js +125 -0
  45. package/dist/commands/dev.js +109 -0
  46. package/dist/commands/devices.js +135 -0
  47. package/dist/commands/explain-router.js +24 -0
  48. package/dist/commands/explain.js +882 -0
  49. package/dist/commands/explore.js +264 -0
  50. package/dist/commands/help.js +2418 -0
  51. package/dist/commands/init.js +408 -0
  52. package/dist/commands/install.js +129 -0
  53. package/dist/commands/library.js +229 -0
  54. package/dist/commands/marketplace.js +138 -0
  55. package/dist/commands/mcp-install.js +476 -0
  56. package/dist/commands/mention.js +257 -0
  57. package/dist/commands/omni.js +529 -0
  58. package/dist/commands/secrets.js +323 -0
  59. package/dist/commands/self-update.js +206 -0
  60. package/dist/commands/sheet.js +264 -0
  61. package/dist/commands/shell-output.js +309 -0
  62. package/dist/commands/shell.js +1048 -0
  63. package/dist/commands/shop.js +368 -0
  64. package/dist/commands/skills.js +311 -0
  65. package/dist/commands/slides.js +418 -0
  66. package/dist/commands/swarm.js +341 -0
  67. package/dist/commands/ticket.js +1301 -0
  68. package/dist/commands/tool.js +312 -0
  69. package/dist/commands/trash.js +106 -0
  70. package/dist/commands/treehouse.js +120 -0
  71. package/dist/commands/user.js +240 -0
  72. package/dist/commands/voice-tts.js +319 -0
  73. package/dist/commands/voice.js +166 -0
  74. package/dist/commands/watch-git.js +401 -0
  75. package/dist/commands/webhook.js +159 -0
  76. package/dist/commands/workspace.js +3354 -0
  77. package/dist/composition-repos.js +91 -0
  78. package/dist/daemon-avatar.js +130 -0
  79. package/dist/daemon-claude-code-auto-install.js +52 -0
  80. package/dist/daemon-client.js +363 -0
  81. package/dist/daemon-codex.js +349 -0
  82. package/dist/daemon-entry.js +101 -0
  83. package/dist/daemon-fetch-allowlist.js +194 -0
  84. package/dist/daemon-gemini.js +224 -0
  85. package/dist/daemon-mcp-clearly.js +353 -0
  86. package/dist/daemon-mcp-sandbox.js +127 -0
  87. package/dist/daemon-omni-company.js +338 -0
  88. package/dist/daemon-omni-hooks.js +375 -0
  89. package/dist/daemon-omni-identity.js +229 -0
  90. package/dist/daemon-omni-pipeline.js +251 -0
  91. package/dist/daemon-omni-policies.js +346 -0
  92. package/dist/daemon-omni-principal.js +580 -0
  93. package/dist/daemon-omni-tool-gate.js +116 -0
  94. package/dist/daemon-omni.js +1442 -0
  95. package/dist/daemon-path-transform.js +120 -0
  96. package/dist/daemon-write-sandbox.js +191 -0
  97. package/dist/daemon.js +4471 -0
  98. package/dist/dashboard.js +846 -0
  99. package/dist/dep-installer.js +286 -0
  100. package/dist/dev-mode.js +67 -0
  101. package/dist/doc-indexer.js +169 -0
  102. package/dist/e2e-crypto.js +94 -0
  103. package/dist/feature-flags.js +154 -0
  104. package/dist/file-browser.js +88 -0
  105. package/dist/first-party-hives.js +211 -0
  106. package/dist/folder-sync.js +226 -0
  107. package/dist/health.js +56 -0
  108. package/dist/ipc-auth.js +299 -0
  109. package/dist/ipc-client.js +495 -0
  110. package/dist/ipc-server.js +684 -0
  111. package/dist/keychain.js +224 -0
  112. package/dist/lib/admin-client.js +73 -0
  113. package/dist/lib/mobile-build-parser.js +156 -0
  114. package/dist/local-app-manager.js +660 -0
  115. package/dist/log-redaction.js +89 -0
  116. package/dist/logger.js +108 -0
  117. package/dist/manifest.js +143 -0
  118. package/dist/marketplace.js +793 -0
  119. package/dist/min-version-copy.js +51 -0
  120. package/dist/min-version.js +214 -0
  121. package/dist/public-surface.js +23 -0
  122. package/dist/relay-presets.js +89 -0
  123. package/dist/relay.js +2723 -0
  124. package/dist/repl.js +619 -0
  125. package/dist/setup-relay.js +363 -0
  126. package/dist/setup-service.js +536 -0
  127. package/dist/shared/bee-memory/index.js +6 -0
  128. package/dist/shared/bee-memory/types.js +682 -0
  129. package/dist/shared/claude-code/daemon-types.js +112 -0
  130. package/dist/shared/claude-code/index.js +2 -0
  131. package/dist/shared/claude-code/types.js +1 -0
  132. package/dist/shared/status/schema.js +133 -0
  133. package/dist/shell-session.js +198 -0
  134. package/dist/speak-lock.js +97 -0
  135. package/dist/spinner.js +57 -0
  136. package/dist/telemetry.js +166 -0
  137. package/dist/terminal/block-parser.js +207 -0
  138. package/dist/terminal/shell-integration.js +108 -0
  139. package/dist/transcript-tailer.js +215 -0
  140. package/dist/tts-qwen3.js +547 -0
  141. package/dist/types.js +4 -0
  142. package/dist/utm.js +38 -0
  143. package/dist/verb-surface.js +331 -0
  144. package/dist/version-utils.js +85 -0
  145. package/dist/watcher.js +207 -0
  146. package/package.json +88 -0
  147. package/python/qwen3_tts.py +230 -0
  148. package/scripts/stamp-build-channel.mjs +115 -0
  149. package/scripts/sync-installed.mjs +159 -0
  150. package/scripts/sync-skills.mjs +112 -0
  151. package/skills/README.md +24 -0
  152. package/skills/agent-doodle-space/SKILL.md +118 -0
  153. package/skills/agent-home/SKILL.md +98 -0
  154. package/skills/beehaven-cli/SKILL.md +144 -0
  155. package/skills/claude-shopper/README.md +90 -0
  156. package/skills/claude-shopper/SKILL.md +151 -0
  157. package/skills/clearly-agent/SKILL.md +183 -0
  158. package/skills/clearly-canvas/SKILL.md +222 -0
  159. package/skills/clearly-canvas/authoring.md +160 -0
  160. package/skills/clearly-canvas/communications.md +32 -0
  161. package/skills/clearly-canvas/composition-patterns.md +84 -0
  162. package/skills/clearly-canvas/example.mjs +78 -0
  163. package/skills/clearly-canvas/project-plans.md +156 -0
  164. package/skills/clearly-canvas/review.mjs +68 -0
  165. package/skills/clearly-workspace/SKILL.md +79 -0
  166. package/skills/clearly-workspace/survey.mjs +101 -0
  167. package/skills/codebase-map/SKILL.md +142 -0
  168. package/skills/design-craft/SKILL.md +300 -0
  169. package/skills/index.json +79 -0
  170. package/skills/layout-systems/SKILL.md +184 -0
  171. package/skills/pair-on-canvas/SKILL.md +92 -0
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Claude Code Bridge — makes Claude Code a first-class beehaven citizen.
3
+ *
4
+ * When Claude Code runs in a beehaven project, this bridge:
5
+ * 1. Connects to the daemon via IPC
6
+ * 2. Discovers installed apps and their actions
7
+ * 3. Sends session events (so the avatar, dashboard, cloud all know)
8
+ * 4. Provides app context for Claude's system prompt
9
+ *
10
+ * Usage from Claude Code hooks or the beehaven skill:
11
+ * import { ClaudeBridge } from './claude-bridge.js';
12
+ * const bridge = new ClaudeBridge(process.cwd());
13
+ * await bridge.connect();
14
+ * const context = await bridge.getAppContext();
15
+ * await bridge.callApp('recorder', 'record', { source: 'mic' });
16
+ */
17
+ import { createConnection } from 'net';
18
+ import { existsSync, readFileSync, readdirSync } from 'fs';
19
+ import { join } from 'path';
20
+ import { homedir } from 'os';
21
+ import { EventEmitter } from 'events';
22
+ import { activeAgentWrap } from './agent-attribution.js';
23
+ const IPC_SOCKET_PATH = '/tmp/beehaven-ipc.sock';
24
+ const CONFIG_DIR = join(homedir(), '.beehaven');
25
+ export class ClaudeBridge extends EventEmitter {
26
+ socket = null;
27
+ buffer = '';
28
+ connected = false;
29
+ ridCounter = 0;
30
+ pending = new Map();
31
+ cwd;
32
+ sessionId;
33
+ constructor(cwd) {
34
+ super();
35
+ this.cwd = cwd;
36
+ this.sessionId = `claude-${Date.now()}`;
37
+ }
38
+ // ── Connection ─────────────────────────────────────────────────────
39
+ async connect() {
40
+ if (this.connected)
41
+ return true;
42
+ if (!existsSync(IPC_SOCKET_PATH))
43
+ return false;
44
+ return new Promise((resolve) => {
45
+ const timeout = setTimeout(() => resolve(false), 5_000);
46
+ const socket = createConnection({ path: IPC_SOCKET_PATH });
47
+ this.socket = socket;
48
+ socket.on('connect', () => {
49
+ this.connected = true;
50
+ clearTimeout(timeout);
51
+ // Subscribe to app events
52
+ this.send({ type: 'subscribe', patterns: ['app:*', 'recorder:*', 'ableton:*', 'avatar:*', 'session:*'] });
53
+ // Announce ourselves
54
+ this.send({ type: 'session:announce', label: 'claude-code', app: 'bridge' });
55
+ resolve(true);
56
+ });
57
+ socket.on('data', (data) => {
58
+ this.buffer += data.toString();
59
+ const lines = this.buffer.split('\n');
60
+ this.buffer = lines.pop() || '';
61
+ for (const line of lines) {
62
+ if (!line.trim())
63
+ continue;
64
+ try {
65
+ this.handleMessage(JSON.parse(line));
66
+ }
67
+ catch { }
68
+ }
69
+ });
70
+ socket.on('close', () => { this.connected = false; this.socket = null; });
71
+ socket.on('error', () => { clearTimeout(timeout); this.connected = false; resolve(false); });
72
+ });
73
+ }
74
+ disconnect() {
75
+ this.socket?.destroy();
76
+ this.socket = null;
77
+ this.connected = false;
78
+ }
79
+ get isConnected() { return this.connected; }
80
+ // ── App Discovery ──────────────────────────────────────────────────
81
+ /** Get all installed apps with their actions — for Claude's context. */
82
+ async getInstalledApps() {
83
+ if (!this.connected)
84
+ return this.getInstalledAppsLocal();
85
+ try {
86
+ const result = await this.rpc('daemon:app-list', {});
87
+ const apps = [];
88
+ for (const app of result.installed ?? []) {
89
+ // Fetch manifest for each app's buildings
90
+ const actions = await this.getAppActions(app.buildings?.[0] ?? app.name);
91
+ apps.push({
92
+ name: app.name,
93
+ version: app.version,
94
+ description: app.description,
95
+ buildings: app.buildings ?? [],
96
+ actions,
97
+ });
98
+ }
99
+ return apps;
100
+ }
101
+ catch {
102
+ return this.getInstalledAppsLocal();
103
+ }
104
+ }
105
+ /** Get actions for a specific building. */
106
+ async getAppActions(building) {
107
+ try {
108
+ const manifest = await this.appCall(building, 'manifest', {});
109
+ const actions = [];
110
+ for (const [, categoryActions] of Object.entries(manifest?.categories ?? {})) {
111
+ for (const a of categoryActions) {
112
+ actions.push({ name: a.name, description: a.description, params: a.params });
113
+ }
114
+ }
115
+ return actions;
116
+ }
117
+ catch {
118
+ return [];
119
+ }
120
+ }
121
+ /** Fallback — read manifests from disk without daemon. */
122
+ getInstalledAppsLocal() {
123
+ const apps = [];
124
+ for (const root of [join(CONFIG_DIR, 'apps'), join(CONFIG_DIR, 'hives')]) {
125
+ if (!existsSync(root))
126
+ continue;
127
+ for (const entry of readdirSync(root)) {
128
+ if (entry.startsWith('.'))
129
+ continue;
130
+ const dir = join(root, entry);
131
+ const am = join(dir, 'app.json');
132
+ const hm = join(dir, 'hive.json');
133
+ const mp = existsSync(am) ? am : existsSync(hm) ? hm : null;
134
+ if (!mp)
135
+ continue;
136
+ try {
137
+ const m = JSON.parse(readFileSync(mp, 'utf8'));
138
+ if (apps.some(a => a.name === m.name))
139
+ continue;
140
+ apps.push({
141
+ name: m.name, version: m.version ?? '0.0.0',
142
+ description: m.description ?? '',
143
+ buildings: m.buildings ? Object.keys(m.buildings) : [],
144
+ actions: [],
145
+ });
146
+ }
147
+ catch { }
148
+ }
149
+ }
150
+ return apps;
151
+ }
152
+ // ── App Calls ──────────────────────────────────────────────────────
153
+ /** Call an action on a building — same as `beehaven app call <building> <action>`. */
154
+ async callApp(building, action, input = {}) {
155
+ return this.appCall(building, action, input);
156
+ }
157
+ /** Get context string for Claude's system prompt — describes all available apps. */
158
+ async getAppContext() {
159
+ const apps = await this.getInstalledApps();
160
+ if (apps.length === 0)
161
+ return '';
162
+ const lines = ['## Beehaven Apps', ''];
163
+ lines.push('You have access to the following installed apps via `beehaven app call <building> <action> \'{"key":"value"}\'`:');
164
+ lines.push('');
165
+ for (const app of apps) {
166
+ lines.push(`### ${app.name} (v${app.version})`);
167
+ lines.push(app.description);
168
+ if (app.actions.length > 0) {
169
+ lines.push('Actions:');
170
+ for (const a of app.actions) {
171
+ const params = a.params ? ` — ${Object.entries(a.params).map(([k, v]) => `${k}: ${v}`).join(', ')}` : '';
172
+ lines.push(` - ${a.name}: ${a.description}${params}`);
173
+ }
174
+ }
175
+ lines.push('');
176
+ }
177
+ return lines.join('\n');
178
+ }
179
+ // ── Session Events ─────────────────────────────────────────────────
180
+ /** Notify the daemon that Claude Code started a session. */
181
+ sendSessionStart() {
182
+ this.sendEvent('SessionStart');
183
+ }
184
+ /** Notify the daemon that Claude Code ended a session. */
185
+ sendSessionEnd() {
186
+ this.sendEvent('SessionEnd');
187
+ }
188
+ /** Notify the daemon of a tool use. */
189
+ sendToolUse(tool, input, status = 'done') {
190
+ this.sendEvent(status === 'running' ? 'PreToolUse' : status === 'error' ? 'PostToolUseFailure' : 'PostToolUse', {
191
+ tool_name: tool,
192
+ tool_input: typeof input === 'string' ? input : JSON.stringify(input),
193
+ });
194
+ }
195
+ /** Notify the daemon of a user prompt. */
196
+ sendPrompt(prompt) {
197
+ this.sendEvent('UserPromptSubmit', { prompt });
198
+ }
199
+ // ── Internal ───────────────────────────────────────────────────────
200
+ sendEvent(hookEvent, extra = {}) {
201
+ // Send via the watcher socket (HTTP POST to /tmp/beehaven.sock)
202
+ // This is the same protocol mwah uses.
203
+ if (!existsSync('/tmp/beehaven.sock'))
204
+ return;
205
+ const http = require('http');
206
+ const body = JSON.stringify({
207
+ hook_event_name: hookEvent,
208
+ session_id: this.sessionId,
209
+ cwd: this.cwd,
210
+ timestamp: new Date().toISOString(),
211
+ source: 'claude-code',
212
+ ...extra,
213
+ });
214
+ const req = http.request({
215
+ socketPath: '/tmp/beehaven.sock',
216
+ path: '/event',
217
+ method: 'POST',
218
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) },
219
+ });
220
+ req.on('error', () => { });
221
+ req.write(body);
222
+ req.end();
223
+ }
224
+ appCall(building, action, input) {
225
+ return new Promise((resolve, reject) => {
226
+ if (!this.socket || !this.connected)
227
+ return reject(new Error('Not connected'));
228
+ const rid = `claude_${++this.ridCounter}_${Date.now().toString(36)}`;
229
+ const timer = setTimeout(() => { this.pending.delete(rid); reject(new Error('Timeout')); }, 30_000);
230
+ this.pending.set(rid, { resolve, reject, timer });
231
+ this.send({ type: 'app-rpc', action, input, building, instanceId: 'live', rid });
232
+ });
233
+ }
234
+ /**
235
+ * ⚠ A THIRD RPC-FRAME BUILDER — attributed for the same reason as the other two.
236
+ *
237
+ * Its one caller today asks for `daemon:app-list`, which the daemon answers itself and which
238
+ * `DAEMON_LOCAL_ACTIONS` exempts, so in practice this changes nothing. It is wrapped anyway
239
+ * because the method is GENERAL: the day someone adds `this.rpc('ticket-create', …)` it becomes
240
+ * a workspace call that writes no `agent_activity` row, which is exactly the defect CBH2-65 was
241
+ * about and exactly the kind nothing reports. Wrapping costs one line; an exemption would cost a
242
+ * list somebody has to keep true.
243
+ */
244
+ rpc(action, input) {
245
+ const wrapped = activeAgentWrap(action, input, {});
246
+ return new Promise((resolve, reject) => {
247
+ if (!this.socket || !this.connected)
248
+ return reject(new Error('Not connected'));
249
+ const rid = `claude_${++this.ridCounter}_${Date.now().toString(36)}`;
250
+ const timer = setTimeout(() => { this.pending.delete(rid); reject(new Error('Timeout')); }, 30_000);
251
+ this.pending.set(rid, { resolve, reject, timer });
252
+ this.send({ type: 'rpc', action: wrapped.action, input: wrapped.input, rid });
253
+ });
254
+ }
255
+ send(msg) {
256
+ if (this.socket?.writable)
257
+ this.socket.write(JSON.stringify(msg) + '\n');
258
+ }
259
+ handleMessage(msg) {
260
+ if (msg.type === 'rpc-result' && msg.rid && this.pending.has(msg.rid)) {
261
+ const p = this.pending.get(msg.rid);
262
+ clearTimeout(p.timer);
263
+ this.pending.delete(msg.rid);
264
+ p.resolve(msg.result);
265
+ return;
266
+ }
267
+ if (msg.type === 'rpc-error' && msg.rid && this.pending.has(msg.rid)) {
268
+ const p = this.pending.get(msg.rid);
269
+ clearTimeout(p.timer);
270
+ this.pending.delete(msg.rid);
271
+ p.reject(new Error(msg.error));
272
+ return;
273
+ }
274
+ if (msg.type === 'broadcast') {
275
+ this.emit('broadcast', msg.msg);
276
+ }
277
+ }
278
+ }
279
+ /**
280
+ * One-shot: connect, get app context, disconnect.
281
+ * Use this to inject beehaven context into Claude Code's system prompt.
282
+ */
283
+ export async function getBeehavenContext(cwd) {
284
+ const bridge = new ClaudeBridge(cwd);
285
+ const ok = await bridge.connect();
286
+ if (!ok)
287
+ return '';
288
+ try {
289
+ return await bridge.getAppContext();
290
+ }
291
+ finally {
292
+ bridge.disconnect();
293
+ }
294
+ }
295
+ /**
296
+ * One-shot: connect, call an app action, disconnect.
297
+ * Use this from Claude Code tool calls.
298
+ */
299
+ export async function callBeehavenApp(building, action, input = {}) {
300
+ const bridge = new ClaudeBridge(process.cwd());
301
+ const ok = await bridge.connect();
302
+ if (!ok)
303
+ throw new Error('Daemon not running');
304
+ try {
305
+ return await bridge.callApp(building, action, input);
306
+ }
307
+ finally {
308
+ bridge.disconnect();
309
+ }
310
+ }