heyhank 0.1.0 → 0.3.0

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 (161) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -10
  3. package/bin/cli.ts +7 -7
  4. package/bin/ctl.ts +42 -42
  5. package/dist/assets/{AgentsPage-BPhirnCe.js → AgentsPage-DqjDAcIw.js} +3 -3
  6. package/dist/assets/AssistantPage-C50CQFSB.js +2 -0
  7. package/dist/assets/BusinessPage-AY70tf1k.js +1 -0
  8. package/dist/assets/{CronManager-DDbz-yiT.js → CronManager-Dt7LLuRr.js} +1 -1
  9. package/dist/assets/HelpPage-tlGx7fQF.js +1 -0
  10. package/dist/assets/{IntegrationsPage-CrOitCmJ.js → IntegrationsPage-B4XOuHXu.js} +1 -1
  11. package/dist/assets/JarvisHUD-BDvuRd0I.js +120 -0
  12. package/dist/assets/MediaPage-CofV9Rd-.js +1 -0
  13. package/dist/assets/MemoryPage-Cj7FeqmJ.js +1 -0
  14. package/dist/assets/{PlatformDashboard-Do6F0O2p.js → PlatformDashboard-B9kXAlH1.js} +1 -1
  15. package/dist/assets/{Playground-Fc5cdc5p.js → Playground-Cka-pRkP.js} +1 -1
  16. package/dist/assets/{ProcessPanel-CslEiZkI.js → ProcessPanel-BqhQgfYj.js} +1 -1
  17. package/dist/assets/{PromptsPage-D2EhsdNO.js → PromptsPage-VveKc9uX.js} +2 -2
  18. package/dist/assets/RunsPage-DXVEk0AZ.js +1 -0
  19. package/dist/assets/{SandboxManager-a1AVI5q2.js → SandboxManager-DACcwfDF.js} +1 -1
  20. package/dist/assets/SettingsPage-jfuQh8Tu.js +51 -0
  21. package/dist/assets/SkillsMarketplace-DrigiApe.js +1 -0
  22. package/dist/assets/SocialMediaPage-DOh3IPe8.js +10 -0
  23. package/dist/assets/{TailscalePage-CHiFhZXF.js → TailscalePage-DLhJWATT.js} +1 -1
  24. package/dist/assets/TelephonyPage-9C4C3_ot.js +9 -0
  25. package/dist/assets/{TerminalPage-Drwyrnfd.js → TerminalPage-ChX-8Wu7.js} +1 -1
  26. package/dist/assets/{gemini-live-client-C7rqAW7G.js → gemini-live-client-C70FEtX2.js} +11 -8
  27. package/dist/assets/index-C6Q5UQHD.js +229 -0
  28. package/dist/assets/index-ZxGXgiV3.css +32 -0
  29. package/dist/assets/sw-register-BBYuk-kw.js +1 -0
  30. package/dist/assets/text-chat-client-BSbLJerZ.js +2 -0
  31. package/dist/assets/workbox-window.prod.es5-BBnX5xw4.js +2 -0
  32. package/dist/index.html +2 -2
  33. package/dist/sw.js +1 -1
  34. package/dist/{workbox-d2a0910a.js → workbox-080c8b91.js} +1 -1
  35. package/package.json +6 -1
  36. package/server/agent-executor.ts +102 -2
  37. package/server/agent-store.ts +3 -3
  38. package/server/agent-types.ts +11 -0
  39. package/server/assistant-store.ts +232 -6
  40. package/server/auth-manager.ts +9 -0
  41. package/server/cache-headers.ts +1 -1
  42. package/server/calendar-service.ts +10 -0
  43. package/server/ceo/document-store.ts +129 -0
  44. package/server/ceo/finance-store.ts +343 -0
  45. package/server/ceo/kpi-store.ts +208 -0
  46. package/server/ceo/memory-import.ts +277 -0
  47. package/server/ceo/news-store.ts +208 -0
  48. package/server/ceo/template-store.ts +134 -0
  49. package/server/ceo/time-tracking-store.ts +227 -0
  50. package/server/claude-auth-monitor.ts +128 -0
  51. package/server/claude-code-worker.ts +86 -0
  52. package/server/claude-session-discovery.ts +74 -1
  53. package/server/cli-launcher.ts +32 -10
  54. package/server/codex-adapter.ts +2 -2
  55. package/server/codex-ws-proxy.cjs +1 -1
  56. package/server/container-manager.ts +4 -4
  57. package/server/content-intelligence/content-engine.ts +1112 -0
  58. package/server/content-intelligence/platform-knowledge.ts +870 -0
  59. package/server/cron-store.ts +3 -3
  60. package/server/embedding-service.ts +49 -0
  61. package/server/event-bus-types.ts +13 -0
  62. package/server/execution-store.ts +54 -1
  63. package/server/federation/node-store.ts +5 -4
  64. package/server/fs-utils.ts +28 -1
  65. package/server/hank-notifications-store.ts +91 -0
  66. package/server/hank-tool-executor.ts +1835 -0
  67. package/server/hank-tools.ts +2107 -0
  68. package/server/image-pull-manager.ts +2 -2
  69. package/server/index.ts +25 -2
  70. package/server/llm-providers-streaming.ts +541 -0
  71. package/server/llm-providers.ts +12 -0
  72. package/server/marketplace.ts +249 -0
  73. package/server/mcp-registry.ts +158 -0
  74. package/server/memory-service.ts +296 -0
  75. package/server/obsidian-sync.ts +184 -0
  76. package/server/provider-manager.ts +5 -2
  77. package/server/provider-registry.ts +12 -0
  78. package/server/reminder-scheduler.ts +37 -1
  79. package/server/routes/agent-routes.ts +44 -1
  80. package/server/routes/assistant-routes.ts +198 -5
  81. package/server/routes/ceo-finance-kpi-routes.ts +167 -0
  82. package/server/routes/ceo-news-time-routes.ts +137 -0
  83. package/server/routes/ceo-routes.ts +99 -0
  84. package/server/routes/content-routes.ts +116 -0
  85. package/server/routes/email-routes.ts +147 -0
  86. package/server/routes/env-routes.ts +3 -3
  87. package/server/routes/fs-routes.ts +12 -9
  88. package/server/routes/hank-chat-routes.ts +592 -0
  89. package/server/routes/llm-routes.ts +12 -0
  90. package/server/routes/marketplace-routes.ts +63 -0
  91. package/server/routes/media-routes.ts +1 -1
  92. package/server/routes/memory-routes.ts +127 -0
  93. package/server/routes/platform-routes.ts +14 -675
  94. package/server/routes/sandbox-routes.ts +1 -1
  95. package/server/routes/settings-routes.ts +51 -1
  96. package/server/routes/socialmedia-routes.ts +152 -2
  97. package/server/routes/system-routes.ts +2 -2
  98. package/server/routes/team-routes.ts +71 -0
  99. package/server/routes/telephony-routes.ts +98 -18
  100. package/server/routes.ts +36 -9
  101. package/server/session-creation-service.ts +2 -2
  102. package/server/session-orchestrator.ts +54 -2
  103. package/server/session-types.ts +2 -0
  104. package/server/settings-manager.ts +50 -2
  105. package/server/skill-discovery.ts +68 -0
  106. package/server/socialmedia/adapters/browser-adapter.ts +179 -0
  107. package/server/socialmedia/adapters/postiz-adapter.ts +291 -14
  108. package/server/socialmedia/manager.ts +234 -15
  109. package/server/socialmedia/store.ts +51 -1
  110. package/server/socialmedia/types.ts +35 -2
  111. package/server/socialview/browser-manager.ts +150 -0
  112. package/server/socialview/extractors.ts +1298 -0
  113. package/server/socialview/image-describe.ts +188 -0
  114. package/server/socialview/library.ts +119 -0
  115. package/server/socialview/poster.ts +276 -0
  116. package/server/socialview/routes.ts +371 -0
  117. package/server/socialview/style-analyzer.ts +187 -0
  118. package/server/socialview/style-profiles.ts +67 -0
  119. package/server/socialview/types.ts +166 -0
  120. package/server/socialview/vision.ts +127 -0
  121. package/server/socialview/vnc-manager.ts +110 -0
  122. package/server/style-injector.ts +135 -0
  123. package/server/team-service.ts +239 -0
  124. package/server/team-store.ts +75 -0
  125. package/server/team-types.ts +52 -0
  126. package/server/telephony/audio-bridge.ts +281 -35
  127. package/server/telephony/audio-recorder.ts +132 -0
  128. package/server/telephony/call-manager.ts +803 -104
  129. package/server/telephony/call-types.ts +67 -1
  130. package/server/telephony/esl-client.ts +319 -0
  131. package/server/telephony/freeswitch-sync.ts +155 -0
  132. package/server/telephony/phone-utils.ts +63 -0
  133. package/server/telephony/telephony-store.ts +9 -8
  134. package/server/url-validator.ts +82 -0
  135. package/server/vault-markdown.ts +317 -0
  136. package/server/vault-migration.ts +121 -0
  137. package/server/vault-store.ts +466 -0
  138. package/server/vault-watcher.ts +59 -0
  139. package/server/vector-store.ts +210 -0
  140. package/server/voice-pipeline/gemini-live-adapter.ts +97 -0
  141. package/server/voice-pipeline/greeting-cache.ts +200 -0
  142. package/server/voice-pipeline/manager.ts +249 -0
  143. package/server/voice-pipeline/pipeline.ts +335 -0
  144. package/server/voice-pipeline/providers/index.ts +47 -0
  145. package/server/voice-pipeline/providers/llm-internal.ts +527 -0
  146. package/server/voice-pipeline/providers/stt-google.ts +157 -0
  147. package/server/voice-pipeline/providers/tts-google.ts +126 -0
  148. package/server/voice-pipeline/types.ts +247 -0
  149. package/server/ws-bridge-types.ts +6 -1
  150. package/dist/assets/AssistantPage-DJ-cMQfb.js +0 -1
  151. package/dist/assets/HelpPage-DMfkzERp.js +0 -1
  152. package/dist/assets/MediaPage-CE5rdvkC.js +0 -1
  153. package/dist/assets/RunsPage-C5BZF5Rx.js +0 -1
  154. package/dist/assets/SettingsPage-DirhjQrJ.js +0 -51
  155. package/dist/assets/SocialMediaPage-DBuM28vD.js +0 -1
  156. package/dist/assets/TelephonyPage-x0VV0fOo.js +0 -1
  157. package/dist/assets/index-C8M_PUmX.css +0 -32
  158. package/dist/assets/index-CEqZnThB.js +0 -204
  159. package/dist/assets/sw-register-LSSpj6RU.js +0 -1
  160. package/dist/assets/workbox-window.prod.es5-BIl4cyR9.js +0 -2
  161. package/server/socialmedia/adapters/ayrshare-adapter.ts +0 -169
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 The Vibe Company
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,26 +1,37 @@
1
- # HeyHank
1
+ <p align="center">
2
+ <img src="public/logo.svg" alt="HeyHank" width="80" />
3
+ </p>
2
4
 
3
- Self-hosted web UI for running Claude Code and Codex agents. Multi-session management with streaming, tool call visibility, and permission control.
5
+ <h1 align="center">HeyHank</h1>
6
+ <p align="center"><strong>Self-hosted web UI for running Claude Code and Codex agents.</strong></p>
7
+ <p align="center">Multi-session management with streaming, tool call visibility, and permission control.</p>
4
8
 
5
- ## Install
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/heyhank"><img src="https://img.shields.io/npm/v/heyhank.svg" alt="npm version" /></a>
11
+ <a href="https://www.npmjs.com/package/heyhank"><img src="https://img.shields.io/npm/dm/heyhank.svg" alt="npm downloads" /></a>
12
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License" /></a>
13
+ </p>
14
+
15
+ ## Quick Start
16
+
17
+ **Requirements:** [Bun](https://bun.sh) v1.0+ and [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and/or [Codex](https://github.com/openai/codex) CLI.
6
18
 
7
19
  ```bash
8
20
  bunx heyhank
9
21
  ```
10
22
 
11
- Requires [Bun](https://bun.sh) v1.0+.
23
+ Open [http://localhost:3456](http://localhost:3456).
12
24
 
13
- ## Usage
25
+ ### Install Globally
14
26
 
15
27
  ```bash
16
- # Start the server
17
- heyhank serve
28
+ bun install -g heyhank
18
29
 
19
- # Install as background service
30
+ # Register as a background service (launchd on macOS, systemd on Linux)
20
31
  heyhank install
21
32
 
22
- # Check status
23
- heyhank status
33
+ # Start the service
34
+ heyhank start
24
35
  ```
25
36
 
26
37
  ## Features
@@ -30,11 +41,73 @@ heyhank status
30
41
  - **Scheduled Agents** — Cron-based agent automation
31
42
  - **Media Generation** — Image (Imagen 4) and video (Veo 3.1) generation
32
43
  - **Social Media** — Multi-backend posting (Postiz, Buffer, Ayrshare)
44
+ - **Email Integration** — Multi-account IMAP/SMTP email via UI and voice
33
45
  - **Telephony** — Voice calls via FreeSWITCH SIP integration
46
+ - **Personal Assistant** — Todos, notes, and reminders managed by voice or UI
34
47
  - **Federation** — Connect multiple HeyHank instances across machines
35
48
  - **Tailscale Funnel** — Public HTTPS access without port forwarding
36
49
  - **PWA** — Installable on mobile and desktop
37
50
 
51
+ ## CLI Commands
52
+
53
+ | Command | Description |
54
+ |---|---|
55
+ | `heyhank` | Start server in foreground (default) |
56
+ | `heyhank serve` | Start server in foreground (explicit) |
57
+ | `heyhank install` | Register as a background service (launchd/systemd) |
58
+ | `heyhank start` | Start the background service |
59
+ | `heyhank stop` | Stop the background service |
60
+ | `heyhank restart` | Restart the background service |
61
+ | `heyhank uninstall` | Remove the background service |
62
+ | `heyhank status` | Show service status |
63
+ | `heyhank logs` | Tail service log files |
64
+
65
+ **Options:** `--port <n>` overrides the default port (3456).
66
+
67
+ ## Architecture
68
+
69
+ ```
70
+ Browser (React)
71
+ <-> ws://localhost:3456/ws/browser/:session
72
+ HeyHank Server (Bun + Hono)
73
+ <-> ws://localhost:3456/ws/cli/:session
74
+ Claude Code / Codex CLI
75
+ ```
76
+
77
+ The server bridges the CLI's `--sdk-url` WebSocket (NDJSON) to a browser-friendly WebSocket.
78
+
79
+ ## Authentication
80
+
81
+ The server auto-generates an auth token on first start, stored at `~/.heyhank/auth.json`.
82
+
83
+ ```bash
84
+ # Show the current token
85
+ bun run generate-token
86
+
87
+ # Force-regenerate a new token
88
+ bun run generate-token --force
89
+ ```
90
+
91
+ Or set via environment variable:
92
+
93
+ ```bash
94
+ HEYHANK_AUTH_TOKEN="my-secret-token" bunx heyhank
95
+ ```
96
+
97
+ ## Development
98
+
99
+ ```bash
100
+ bun install
101
+ bun run dev
102
+ ```
103
+
104
+ Checks:
105
+
106
+ ```bash
107
+ bun run typecheck
108
+ bun run test
109
+ ```
110
+
38
111
  ## License
39
112
 
40
113
  MIT
package/bin/cli.ts CHANGED
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
4
4
 
5
5
  // Package root so the server can find dist/ regardless of CWD
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
- process.env.__COMPANION_PACKAGE_ROOT = resolve(__dirname, "..");
7
+ process.env.__HEYHANK_PACKAGE_ROOT = resolve(__dirname, "..");
8
8
 
9
9
  const command = process.argv[2];
10
10
 
@@ -25,7 +25,7 @@ Server commands:
25
25
  stop Stop the background service
26
26
  restart Restart the background service
27
27
  uninstall Remove the background service
28
- status Show service status (or use 'companion status' when server is running)
28
+ status Show service status (or use 'heyhank status' when server is running)
29
29
  logs Tail service log files
30
30
  help Show this help message
31
31
 
@@ -35,7 +35,7 @@ Management commands (requires running server):
35
35
  cron Manage scheduled jobs (list, get, create, update, delete, toggle, run)
36
36
  skills Manage Claude Code skills (list, get, create, update, delete)
37
37
  settings Manage settings (get, set)
38
- assistant Manage the Companion Assistant (status, launch, stop, config)
38
+ assistant Manage the HeyHank Assistant (status, launch, stop, config)
39
39
 
40
40
  Options:
41
41
  --port <n> Override the default port (default: 3456)
@@ -105,13 +105,13 @@ switch (command) {
105
105
  const { status } = await import("../server/service.js");
106
106
  const result = await status();
107
107
  if (!result.installed) {
108
- console.log("The Companion is not installed as a service.");
109
- console.log("Run: companion install");
108
+ console.log("HeyHank is not installed as a service.");
109
+ console.log("Run: heyhank install");
110
110
  } else if (result.running) {
111
- console.log(`The Companion is running (PID: ${result.pid})`);
111
+ console.log(`HeyHank is running (PID: ${result.pid})`);
112
112
  console.log(` URL: http://localhost:${result.port}`);
113
113
  } else {
114
- console.log("The Companion is installed but not running.");
114
+ console.log("HeyHank is installed but not running.");
115
115
  console.log("Check logs at ~/.heyhank/logs/");
116
116
  }
117
117
  }
package/bin/ctl.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
- * CLI handler module for `companion` management subcommands.
4
- * Each subcommand maps 1:1 to a Companion REST API endpoint.
3
+ * CLI handler module for `heyhank` management subcommands.
4
+ * Each subcommand maps 1:1 to a HeyHank REST API endpoint.
5
5
  * All output is JSON to stdout for easy parsing by both humans and AI agents.
6
6
  */
7
7
 
@@ -13,7 +13,7 @@ function getPort(argv: string[]): number {
13
13
  const p = Number(argv[idx + 1]);
14
14
  if (!Number.isNaN(p) && p > 0) return p;
15
15
  }
16
- return Number(process.env.COMPANION_PORT) || DEFAULT_PORT;
16
+ return Number(process.env.HEYHANK_PORT || process.env.COMPANION_PORT) || DEFAULT_PORT;
17
17
  }
18
18
 
19
19
  function getBase(argv: string[]): string {
@@ -175,7 +175,7 @@ async function handleSessions(base: string, args: string[]): Promise<void> {
175
175
  }
176
176
  case "get": {
177
177
  const id = rest[0];
178
- if (!id) err("Usage: companion sessions get <sessionId>");
178
+ if (!id) err("Usage: heyhank sessions get <sessionId>");
179
179
  out(await apiGet(base, `/sessions/${encodeURIComponent(id)}`));
180
180
  break;
181
181
  }
@@ -195,33 +195,33 @@ async function handleSessions(base: string, args: string[]): Promise<void> {
195
195
  }
196
196
  case "kill": {
197
197
  const id = rest[0];
198
- if (!id) err("Usage: companion sessions kill <sessionId>");
198
+ if (!id) err("Usage: heyhank sessions kill <sessionId>");
199
199
  out(await apiPost(base, `/sessions/${encodeURIComponent(id)}/kill`));
200
200
  break;
201
201
  }
202
202
  case "relaunch": {
203
203
  const id = rest[0];
204
- if (!id) err("Usage: companion sessions relaunch <sessionId>");
204
+ if (!id) err("Usage: heyhank sessions relaunch <sessionId>");
205
205
  out(await apiPost(base, `/sessions/${encodeURIComponent(id)}/relaunch`));
206
206
  break;
207
207
  }
208
208
  case "archive": {
209
209
  const id = rest[0];
210
- if (!id) err("Usage: companion sessions archive <sessionId>");
210
+ if (!id) err("Usage: heyhank sessions archive <sessionId>");
211
211
  out(await apiPost(base, `/sessions/${encodeURIComponent(id)}/archive`));
212
212
  break;
213
213
  }
214
214
  case "rename": {
215
215
  const id = rest[0];
216
216
  const name = rest.slice(1).join(" ");
217
- if (!id || !name) err("Usage: companion sessions rename <sessionId> <name>");
217
+ if (!id || !name) err("Usage: heyhank sessions rename <sessionId> <name>");
218
218
  out(await apiPatch(base, `/sessions/${encodeURIComponent(id)}/name`, { name }));
219
219
  break;
220
220
  }
221
221
  case "send-message": {
222
222
  const id = rest[0];
223
223
  const content = rest.slice(1).join(" ");
224
- if (!id || !content) err("Usage: companion sessions send-message <sessionId> <message>");
224
+ if (!id || !content) err("Usage: heyhank sessions send-message <sessionId> <message>");
225
225
  out(await apiPost(base, `/sessions/${encodeURIComponent(id)}/message`, { content }));
226
226
  break;
227
227
  }
@@ -241,20 +241,20 @@ async function handleEnvs(base: string, args: string[]): Promise<void> {
241
241
  }
242
242
  case "get": {
243
243
  const slug = rest[0];
244
- if (!slug) err("Usage: companion envs get <slug>");
244
+ if (!slug) err("Usage: heyhank envs get <slug>");
245
245
  out(await apiGet(base, `/envs/${encodeURIComponent(slug)}`));
246
246
  break;
247
247
  }
248
248
  case "create": {
249
249
  const flags = parseFlags(rest);
250
250
  const vars = parseVars(rest);
251
- if (!flags.name) err("Usage: companion envs create --name <name> [--var KEY=VALUE ...]");
251
+ if (!flags.name) err("Usage: heyhank envs create --name <name> [--var KEY=VALUE ...]");
252
252
  out(await apiPost(base, "/envs", { name: flags.name, variables: vars }));
253
253
  break;
254
254
  }
255
255
  case "update": {
256
256
  const slug = rest[0];
257
- if (!slug) err("Usage: companion envs update <slug> [--name <name>] [--var KEY=VALUE ...]");
257
+ if (!slug) err("Usage: heyhank envs update <slug> [--name <name>] [--var KEY=VALUE ...]");
258
258
  const flagArgs = rest.slice(1);
259
259
  const flags = parseFlags(flagArgs);
260
260
  const vars = parseVars(flagArgs);
@@ -266,7 +266,7 @@ async function handleEnvs(base: string, args: string[]): Promise<void> {
266
266
  }
267
267
  case "delete": {
268
268
  const slug = rest[0];
269
- if (!slug) err("Usage: companion envs delete <slug>");
269
+ if (!slug) err("Usage: heyhank envs delete <slug>");
270
270
  out(await apiDelete(base, `/envs/${encodeURIComponent(slug)}`));
271
271
  break;
272
272
  }
@@ -286,14 +286,14 @@ async function handleCron(base: string, args: string[]): Promise<void> {
286
286
  }
287
287
  case "get": {
288
288
  const id = rest[0];
289
- if (!id) err("Usage: companion cron get <jobId>");
289
+ if (!id) err("Usage: heyhank cron get <jobId>");
290
290
  out(await apiGet(base, `/cron/jobs/${encodeURIComponent(id)}`));
291
291
  break;
292
292
  }
293
293
  case "create": {
294
294
  const flags = parseFlags(rest);
295
295
  if (!flags.name || !flags.schedule || !flags.prompt)
296
- err("Usage: companion cron create --name <name> --schedule <cron|datetime> --prompt <prompt> [--cwd <path>] [--model <model>] [--env <slug>] [--recurring] [--backend <type>] [--permission-mode <mode>]");
296
+ err("Usage: heyhank cron create --name <name> --schedule <cron|datetime> --prompt <prompt> [--cwd <path>] [--model <model>] [--env <slug>] [--recurring] [--backend <type>] [--permission-mode <mode>]");
297
297
  const body: Record<string, unknown> = {
298
298
  name: flags.name,
299
299
  schedule: flags.schedule,
@@ -312,7 +312,7 @@ async function handleCron(base: string, args: string[]): Promise<void> {
312
312
  }
313
313
  case "update": {
314
314
  const id = rest[0];
315
- if (!id) err("Usage: companion cron update <jobId> [--name <n>] [--schedule <s>] [--prompt <p>] ...");
315
+ if (!id) err("Usage: heyhank cron update <jobId> [--name <n>] [--schedule <s>] [--prompt <p>] ...");
316
316
  const flagArgs = rest.slice(1);
317
317
  const flags = parseFlags(flagArgs);
318
318
  const body: Record<string, unknown> = {};
@@ -330,25 +330,25 @@ async function handleCron(base: string, args: string[]): Promise<void> {
330
330
  }
331
331
  case "delete": {
332
332
  const id = rest[0];
333
- if (!id) err("Usage: companion cron delete <jobId>");
333
+ if (!id) err("Usage: heyhank cron delete <jobId>");
334
334
  out(await apiDelete(base, `/cron/jobs/${encodeURIComponent(id)}`));
335
335
  break;
336
336
  }
337
337
  case "toggle": {
338
338
  const id = rest[0];
339
- if (!id) err("Usage: companion cron toggle <jobId>");
339
+ if (!id) err("Usage: heyhank cron toggle <jobId>");
340
340
  out(await apiPost(base, `/cron/jobs/${encodeURIComponent(id)}/toggle`));
341
341
  break;
342
342
  }
343
343
  case "run": {
344
344
  const id = rest[0];
345
- if (!id) err("Usage: companion cron run <jobId>");
345
+ if (!id) err("Usage: heyhank cron run <jobId>");
346
346
  out(await apiPost(base, `/cron/jobs/${encodeURIComponent(id)}/run`));
347
347
  break;
348
348
  }
349
349
  case "executions": {
350
350
  const id = rest[0];
351
- if (!id) err("Usage: companion cron executions <jobId>");
351
+ if (!id) err("Usage: heyhank cron executions <jobId>");
352
352
  out(await apiGet(base, `/cron/jobs/${encodeURIComponent(id)}/executions`));
353
353
  break;
354
354
  }
@@ -370,7 +370,7 @@ async function handleSettings(base: string, args: string[]): Promise<void> {
370
370
  const body: Record<string, unknown> = {};
371
371
  if (flags["anthropic-key"]) body.anthropicApiKey = flags["anthropic-key"];
372
372
  if (flags["anthropic-model"]) body.anthropicModel = flags["anthropic-model"];
373
- if (Object.keys(body).length === 0) err("Usage: companion settings set --anthropic-key <key> or --anthropic-model <model>");
373
+ if (Object.keys(body).length === 0) err("Usage: heyhank settings set --anthropic-key <key> or --anthropic-model <model>");
374
374
  out(await apiPut(base, "/settings", body));
375
375
  break;
376
376
  }
@@ -425,13 +425,13 @@ async function handleSkills(base: string, args: string[]): Promise<void> {
425
425
  }
426
426
  case "get": {
427
427
  const slug = rest[0];
428
- if (!slug) err("Usage: companion skills get <slug>");
428
+ if (!slug) err("Usage: heyhank skills get <slug>");
429
429
  out(await apiGet(base, `/skills/${encodeURIComponent(slug)}`));
430
430
  break;
431
431
  }
432
432
  case "create": {
433
433
  const flags = parseFlags(rest);
434
- if (!flags.name) err("Usage: companion skills create --name <name> [--description <desc>] [--content <markdown>]");
434
+ if (!flags.name) err("Usage: heyhank skills create --name <name> [--description <desc>] [--content <markdown>]");
435
435
  const body: Record<string, unknown> = { name: flags.name };
436
436
  if (flags.description) body.description = flags.description;
437
437
  if (flags.content) body.content = flags.content;
@@ -440,15 +440,15 @@ async function handleSkills(base: string, args: string[]): Promise<void> {
440
440
  }
441
441
  case "update": {
442
442
  const slug = rest[0];
443
- if (!slug) err("Usage: companion skills update <slug> --content <markdown>");
443
+ if (!slug) err("Usage: heyhank skills update <slug> --content <markdown>");
444
444
  const flags = parseFlags(rest.slice(1));
445
- if (!flags.content) err("Usage: companion skills update <slug> --content <full SKILL.md content>");
445
+ if (!flags.content) err("Usage: heyhank skills update <slug> --content <full SKILL.md content>");
446
446
  out(await apiPut(base, `/skills/${encodeURIComponent(slug)}`, { content: flags.content }));
447
447
  break;
448
448
  }
449
449
  case "delete": {
450
450
  const slug = rest[0];
451
- if (!slug) err("Usage: companion skills delete <slug>");
451
+ if (!slug) err("Usage: heyhank skills delete <slug>");
452
452
  out(await apiDelete(base, `/skills/${encodeURIComponent(slug)}`));
453
453
  break;
454
454
  }
@@ -463,18 +463,18 @@ function printCtlUsage(): void {
463
463
  console.log(`
464
464
  Management commands:
465
465
 
466
- companion status Overall Companion status
467
- companion sessions <subcommand> Manage sessions
468
- companion envs <subcommand> Manage environment profiles
469
- companion cron <subcommand> Manage scheduled jobs
470
- companion skills <subcommand> Manage Claude Code skills
471
- companion settings <subcommand> Manage settings
472
- companion assistant <subcommand> Manage the Companion Assistant
466
+ heyhank status Overall HeyHank status
467
+ heyhank sessions <subcommand> Manage sessions
468
+ heyhank envs <subcommand> Manage environment profiles
469
+ heyhank cron <subcommand> Manage scheduled jobs
470
+ heyhank skills <subcommand> Manage Claude Code skills
471
+ heyhank settings <subcommand> Manage settings
472
+ heyhank assistant <subcommand> Manage the HeyHank Assistant
473
473
 
474
474
  Global options:
475
- --port <n> Override the Companion API port (default: 3456, or COMPANION_PORT env)
475
+ --port <n> Override the HeyHank API port (default: 3456, or HEYHANK_PORT env)
476
476
 
477
- Run 'companion <command>' without subcommand for available subcommands.
477
+ Run 'heyhank <command>' without subcommand for available subcommands.
478
478
  `);
479
479
  }
480
480
 
@@ -488,27 +488,27 @@ export async function handleCtlCommand(command: string, rawArgv: string[]): Prom
488
488
  await handleStatus(base);
489
489
  break;
490
490
  case "sessions":
491
- if (argv.length === 0) err("Usage: companion sessions <list|get|create|kill|relaunch|archive|rename|send-message>");
491
+ if (argv.length === 0) err("Usage: heyhank sessions <list|get|create|kill|relaunch|archive|rename|send-message>");
492
492
  await handleSessions(base, argv);
493
493
  break;
494
494
  case "envs":
495
- if (argv.length === 0) err("Usage: companion envs <list|get|create|update|delete>");
495
+ if (argv.length === 0) err("Usage: heyhank envs <list|get|create|update|delete>");
496
496
  await handleEnvs(base, argv);
497
497
  break;
498
498
  case "cron":
499
- if (argv.length === 0) err("Usage: companion cron <list|get|create|update|delete|toggle|run|executions>");
499
+ if (argv.length === 0) err("Usage: heyhank cron <list|get|create|update|delete|toggle|run|executions>");
500
500
  await handleCron(base, argv);
501
501
  break;
502
502
  case "settings":
503
- if (argv.length === 0) err("Usage: companion settings <get|set>");
503
+ if (argv.length === 0) err("Usage: heyhank settings <get|set>");
504
504
  await handleSettings(base, argv);
505
505
  break;
506
506
  case "skills":
507
- if (argv.length === 0) err("Usage: companion skills <list|get|create|update|delete>");
507
+ if (argv.length === 0) err("Usage: heyhank skills <list|get|create|update|delete>");
508
508
  await handleSkills(base, argv);
509
509
  break;
510
510
  case "assistant":
511
- if (argv.length === 0) err("Usage: companion assistant <status|launch|stop|config>");
511
+ if (argv.length === 0) err("Usage: heyhank assistant <status|launch|stop|config>");
512
512
  await handleAssistant(base, argv);
513
513
  break;
514
514
  case "ctl-help":
@@ -521,7 +521,7 @@ export async function handleCtlCommand(command: string, rawArgv: string[]): Prom
521
521
  const message = e instanceof Error ? e.message : String(e);
522
522
  // Check if it's a connection error
523
523
  if (message.includes("ECONNREFUSED") || message.includes("fetch failed")) {
524
- err(`Cannot connect to The Companion at ${base}. Is the server running?`);
524
+ err(`Cannot connect to HeyHank at ${base}. Is the server running?`);
525
525
  }
526
526
  err(message);
527
527
  }