@rozek/nanoclaw 1.2.17

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 (305) hide show
  1. package/.claude/settings.json +1 -0
  2. package/.claude/skills/add-compact/SKILL.md +135 -0
  3. package/.claude/skills/add-discord/SKILL.md +203 -0
  4. package/.claude/skills/add-gmail/SKILL.md +220 -0
  5. package/.claude/skills/add-image-vision/SKILL.md +94 -0
  6. package/.claude/skills/add-ollama-tool/SKILL.md +153 -0
  7. package/.claude/skills/add-parallel/SKILL.md +290 -0
  8. package/.claude/skills/add-pdf-reader/SKILL.md +104 -0
  9. package/.claude/skills/add-reactions/SKILL.md +117 -0
  10. package/.claude/skills/add-slack/SKILL.md +207 -0
  11. package/.claude/skills/add-telegram/SKILL.md +222 -0
  12. package/.claude/skills/add-telegram-swarm/SKILL.md +384 -0
  13. package/.claude/skills/add-voice-transcription/SKILL.md +148 -0
  14. package/.claude/skills/add-whatsapp/SKILL.md +372 -0
  15. package/.claude/skills/convert-to-apple-container/SKILL.md +175 -0
  16. package/.claude/skills/customize/SKILL.md +110 -0
  17. package/.claude/skills/debug/SKILL.md +349 -0
  18. package/.claude/skills/get-qodo-rules/SKILL.md +122 -0
  19. package/.claude/skills/get-qodo-rules/references/output-format.md +41 -0
  20. package/.claude/skills/get-qodo-rules/references/pagination.md +33 -0
  21. package/.claude/skills/get-qodo-rules/references/repository-scope.md +26 -0
  22. package/.claude/skills/qodo-pr-resolver/SKILL.md +326 -0
  23. package/.claude/skills/qodo-pr-resolver/resources/providers.md +329 -0
  24. package/.claude/skills/setup/SKILL.md +218 -0
  25. package/.claude/skills/update-nanoclaw/SKILL.md +235 -0
  26. package/.claude/skills/update-skills/SKILL.md +130 -0
  27. package/.claude/skills/use-local-whisper/SKILL.md +152 -0
  28. package/.claude/skills/x-integration/SKILL.md +417 -0
  29. package/.claude/skills/x-integration/agent.ts +243 -0
  30. package/.claude/skills/x-integration/host.ts +159 -0
  31. package/.claude/skills/x-integration/lib/browser.ts +148 -0
  32. package/.claude/skills/x-integration/lib/config.ts +62 -0
  33. package/.claude/skills/x-integration/scripts/like.ts +56 -0
  34. package/.claude/skills/x-integration/scripts/post.ts +66 -0
  35. package/.claude/skills/x-integration/scripts/quote.ts +80 -0
  36. package/.claude/skills/x-integration/scripts/reply.ts +74 -0
  37. package/.claude/skills/x-integration/scripts/retweet.ts +62 -0
  38. package/.claude/skills/x-integration/scripts/setup.ts +87 -0
  39. package/.env.example +1 -0
  40. package/.github/CODEOWNERS +10 -0
  41. package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  42. package/.github/workflows/bump-version.yml +32 -0
  43. package/.github/workflows/ci.yml +25 -0
  44. package/.github/workflows/merge-forward-skills.yml +160 -0
  45. package/.github/workflows/update-tokens.yml +42 -0
  46. package/.husky/pre-commit +1 -0
  47. package/.mcp.json +3 -0
  48. package/.nvmrc +1 -0
  49. package/.prettierrc +3 -0
  50. package/CHANGELOG.md +8 -0
  51. package/CLAUDE.md +64 -0
  52. package/CONTRIBUTING.md +23 -0
  53. package/CONTRIBUTORS.md +15 -0
  54. package/LICENSE +21 -0
  55. package/NanoClaw_with_Web-Support.md +290 -0
  56. package/README.md +261 -0
  57. package/README_zh.md +200 -0
  58. package/assets/nanoclaw-favicon.png +0 -0
  59. package/assets/nanoclaw-icon.png +0 -0
  60. package/assets/nanoclaw-logo-dark.png +0 -0
  61. package/assets/nanoclaw-logo.png +0 -0
  62. package/assets/nanoclaw-profile.jpeg +0 -0
  63. package/assets/nanoclaw-sales.png +0 -0
  64. package/assets/social-preview.jpg +0 -0
  65. package/config-examples/mount-allowlist.json +25 -0
  66. package/container/Dockerfile +70 -0
  67. package/container/agent-runner/package-lock.json +1524 -0
  68. package/container/agent-runner/package.json +21 -0
  69. package/container/agent-runner/src/index.ts +558 -0
  70. package/container/agent-runner/src/ipc-mcp-stdio.ts +338 -0
  71. package/container/agent-runner/tsconfig.json +15 -0
  72. package/container/build.sh +23 -0
  73. package/container/skills/agent-browser/SKILL.md +159 -0
  74. package/container/skills/capabilities/SKILL.md +100 -0
  75. package/container/skills/status/SKILL.md +104 -0
  76. package/dist/channels/index.d.ts +2 -0
  77. package/dist/channels/index.d.ts.map +1 -0
  78. package/dist/channels/index.js +9 -0
  79. package/dist/channels/index.js.map +1 -0
  80. package/dist/channels/registry.d.ts +13 -0
  81. package/dist/channels/registry.d.ts.map +1 -0
  82. package/dist/channels/registry.js +11 -0
  83. package/dist/channels/registry.js.map +1 -0
  84. package/dist/channels/registry.test.d.ts +2 -0
  85. package/dist/channels/registry.test.d.ts.map +1 -0
  86. package/dist/channels/registry.test.js +32 -0
  87. package/dist/channels/registry.test.js.map +1 -0
  88. package/dist/channels/web.d.ts +2 -0
  89. package/dist/channels/web.d.ts.map +1 -0
  90. package/dist/channels/web.js +1738 -0
  91. package/dist/channels/web.js.map +1 -0
  92. package/dist/cli.d.ts +11 -0
  93. package/dist/cli.d.ts.map +1 -0
  94. package/dist/cli.js +182 -0
  95. package/dist/cli.js.map +1 -0
  96. package/dist/config.d.ts +19 -0
  97. package/dist/config.d.ts.map +1 -0
  98. package/dist/config.js +36 -0
  99. package/dist/config.js.map +1 -0
  100. package/dist/container-runner.d.ts +44 -0
  101. package/dist/container-runner.d.ts.map +1 -0
  102. package/dist/container-runner.js +467 -0
  103. package/dist/container-runner.js.map +1 -0
  104. package/dist/container-runner.test.d.ts +2 -0
  105. package/dist/container-runner.test.d.ts.map +1 -0
  106. package/dist/container-runner.test.js +150 -0
  107. package/dist/container-runner.test.js.map +1 -0
  108. package/dist/container-runtime.d.ts +22 -0
  109. package/dist/container-runtime.d.ts.map +1 -0
  110. package/dist/container-runtime.js +96 -0
  111. package/dist/container-runtime.js.map +1 -0
  112. package/dist/container-runtime.test.d.ts +2 -0
  113. package/dist/container-runtime.test.d.ts.map +1 -0
  114. package/dist/container-runtime.test.js +93 -0
  115. package/dist/container-runtime.test.js.map +1 -0
  116. package/dist/credential-proxy.d.ts +21 -0
  117. package/dist/credential-proxy.d.ts.map +1 -0
  118. package/dist/credential-proxy.js +95 -0
  119. package/dist/credential-proxy.js.map +1 -0
  120. package/dist/credential-proxy.test.d.ts +2 -0
  121. package/dist/credential-proxy.test.d.ts.map +1 -0
  122. package/dist/credential-proxy.test.js +134 -0
  123. package/dist/credential-proxy.test.js.map +1 -0
  124. package/dist/db.d.ts +115 -0
  125. package/dist/db.d.ts.map +1 -0
  126. package/dist/db.js +549 -0
  127. package/dist/db.js.map +1 -0
  128. package/dist/db.test.d.ts +2 -0
  129. package/dist/db.test.d.ts.map +1 -0
  130. package/dist/db.test.js +360 -0
  131. package/dist/db.test.js.map +1 -0
  132. package/dist/env.d.ts +8 -0
  133. package/dist/env.d.ts.map +1 -0
  134. package/dist/env.js +42 -0
  135. package/dist/env.js.map +1 -0
  136. package/dist/formatting.test.d.ts +2 -0
  137. package/dist/formatting.test.d.ts.map +1 -0
  138. package/dist/formatting.test.js +183 -0
  139. package/dist/formatting.test.js.map +1 -0
  140. package/dist/group-folder.d.ts +5 -0
  141. package/dist/group-folder.d.ts.map +1 -0
  142. package/dist/group-folder.js +44 -0
  143. package/dist/group-folder.js.map +1 -0
  144. package/dist/group-folder.test.d.ts +2 -0
  145. package/dist/group-folder.test.d.ts.map +1 -0
  146. package/dist/group-folder.test.js +29 -0
  147. package/dist/group-folder.test.js.map +1 -0
  148. package/dist/group-queue.d.ts +34 -0
  149. package/dist/group-queue.d.ts.map +1 -0
  150. package/dist/group-queue.js +263 -0
  151. package/dist/group-queue.js.map +1 -0
  152. package/dist/group-queue.test.d.ts +2 -0
  153. package/dist/group-queue.test.d.ts.map +1 -0
  154. package/dist/group-queue.test.js +341 -0
  155. package/dist/group-queue.test.js.map +1 -0
  156. package/dist/index.d.ts +12 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +518 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/ipc-auth.test.d.ts +2 -0
  161. package/dist/ipc-auth.test.d.ts.map +1 -0
  162. package/dist/ipc-auth.test.js +434 -0
  163. package/dist/ipc-auth.test.js.map +1 -0
  164. package/dist/ipc.d.ts +32 -0
  165. package/dist/ipc.d.ts.map +1 -0
  166. package/dist/ipc.js +311 -0
  167. package/dist/ipc.js.map +1 -0
  168. package/dist/logger.d.ts +3 -0
  169. package/dist/logger.d.ts.map +1 -0
  170. package/dist/logger.js +14 -0
  171. package/dist/logger.js.map +1 -0
  172. package/dist/mount-security.d.ts +34 -0
  173. package/dist/mount-security.d.ts.map +1 -0
  174. package/dist/mount-security.js +325 -0
  175. package/dist/mount-security.js.map +1 -0
  176. package/dist/remote-control.d.ts +32 -0
  177. package/dist/remote-control.d.ts.map +1 -0
  178. package/dist/remote-control.js +185 -0
  179. package/dist/remote-control.js.map +1 -0
  180. package/dist/remote-control.test.d.ts +2 -0
  181. package/dist/remote-control.test.d.ts.map +1 -0
  182. package/dist/remote-control.test.js +321 -0
  183. package/dist/remote-control.test.js.map +1 -0
  184. package/dist/router.d.ts +8 -0
  185. package/dist/router.d.ts.map +1 -0
  186. package/dist/router.js +37 -0
  187. package/dist/router.js.map +1 -0
  188. package/dist/routing.test.d.ts +2 -0
  189. package/dist/routing.test.d.ts.map +1 -0
  190. package/dist/routing.test.js +81 -0
  191. package/dist/routing.test.js.map +1 -0
  192. package/dist/sender-allowlist.d.ts +14 -0
  193. package/dist/sender-allowlist.d.ts.map +1 -0
  194. package/dist/sender-allowlist.js +79 -0
  195. package/dist/sender-allowlist.js.map +1 -0
  196. package/dist/sender-allowlist.test.d.ts +2 -0
  197. package/dist/sender-allowlist.test.d.ts.map +1 -0
  198. package/dist/sender-allowlist.test.js +186 -0
  199. package/dist/sender-allowlist.test.js.map +1 -0
  200. package/dist/session-commands.d.ts +47 -0
  201. package/dist/session-commands.d.ts.map +1 -0
  202. package/dist/session-commands.js +102 -0
  203. package/dist/session-commands.js.map +1 -0
  204. package/dist/session-commands.test.d.ts +2 -0
  205. package/dist/session-commands.test.d.ts.map +1 -0
  206. package/dist/session-commands.test.js +190 -0
  207. package/dist/session-commands.test.js.map +1 -0
  208. package/dist/task-scheduler.d.ts +22 -0
  209. package/dist/task-scheduler.d.ts.map +1 -0
  210. package/dist/task-scheduler.js +210 -0
  211. package/dist/task-scheduler.js.map +1 -0
  212. package/dist/task-scheduler.test.d.ts +2 -0
  213. package/dist/task-scheduler.test.d.ts.map +1 -0
  214. package/dist/task-scheduler.test.js +107 -0
  215. package/dist/task-scheduler.test.js.map +1 -0
  216. package/dist/timezone.d.ts +6 -0
  217. package/dist/timezone.d.ts.map +1 -0
  218. package/dist/timezone.js +17 -0
  219. package/dist/timezone.js.map +1 -0
  220. package/dist/timezone.test.d.ts +2 -0
  221. package/dist/timezone.test.d.ts.map +1 -0
  222. package/dist/timezone.test.js +23 -0
  223. package/dist/timezone.test.js.map +1 -0
  224. package/dist/types.d.ts +78 -0
  225. package/dist/types.d.ts.map +1 -0
  226. package/dist/types.js +2 -0
  227. package/dist/types.js.map +1 -0
  228. package/docs/APPLE-CONTAINER-NETWORKING.md +90 -0
  229. package/docs/DEBUG_CHECKLIST.md +143 -0
  230. package/docs/REQUIREMENTS.md +196 -0
  231. package/docs/SDK_DEEP_DIVE.md +643 -0
  232. package/docs/SECURITY.md +122 -0
  233. package/docs/SPEC.md +785 -0
  234. package/docs/docker-sandboxes.md +359 -0
  235. package/docs/nanoclaw-architecture-final.md +1063 -0
  236. package/docs/nanorepo-architecture.md +168 -0
  237. package/docs/skills-as-branches.md +662 -0
  238. package/groups/global/CLAUDE.md +58 -0
  239. package/groups/main/CLAUDE.md +246 -0
  240. package/launchd/com.nanoclaw.plist +32 -0
  241. package/package.json +45 -0
  242. package/repo-tokens/README.md +113 -0
  243. package/repo-tokens/action.yml +186 -0
  244. package/repo-tokens/badge.svg +23 -0
  245. package/repo-tokens/examples/green.svg +14 -0
  246. package/repo-tokens/examples/red.svg +14 -0
  247. package/repo-tokens/examples/yellow-green.svg +14 -0
  248. package/repo-tokens/examples/yellow.svg +14 -0
  249. package/scripts/run-migrations.ts +105 -0
  250. package/setup/container.ts +144 -0
  251. package/setup/environment.test.ts +121 -0
  252. package/setup/environment.ts +94 -0
  253. package/setup/groups.ts +229 -0
  254. package/setup/index.ts +58 -0
  255. package/setup/mounts.ts +115 -0
  256. package/setup/platform.test.ts +120 -0
  257. package/setup/platform.ts +132 -0
  258. package/setup/register.test.ts +257 -0
  259. package/setup/register.ts +177 -0
  260. package/setup/service.test.ts +187 -0
  261. package/setup/service.ts +362 -0
  262. package/setup/status.ts +16 -0
  263. package/setup/verify.ts +192 -0
  264. package/setup.sh +161 -0
  265. package/src/channels/index.ts +12 -0
  266. package/src/channels/registry.test.ts +42 -0
  267. package/src/channels/registry.ts +32 -0
  268. package/src/channels/web.ts +1856 -0
  269. package/src/cli.ts +209 -0
  270. package/src/config.ts +73 -0
  271. package/src/container-runner.test.ts +210 -0
  272. package/src/container-runner.ts +707 -0
  273. package/src/container-runtime.test.ts +149 -0
  274. package/src/container-runtime.ts +127 -0
  275. package/src/credential-proxy.test.ts +192 -0
  276. package/src/credential-proxy.ts +125 -0
  277. package/src/db.test.ts +484 -0
  278. package/src/db.ts +803 -0
  279. package/src/env.ts +42 -0
  280. package/src/formatting.test.ts +256 -0
  281. package/src/group-folder.test.ts +43 -0
  282. package/src/group-folder.ts +44 -0
  283. package/src/group-queue.test.ts +484 -0
  284. package/src/group-queue.ts +365 -0
  285. package/src/index.ts +731 -0
  286. package/src/ipc-auth.test.ts +679 -0
  287. package/src/ipc.ts +461 -0
  288. package/src/logger.ts +16 -0
  289. package/src/mount-security.ts +419 -0
  290. package/src/remote-control.test.ts +397 -0
  291. package/src/remote-control.ts +224 -0
  292. package/src/router.ts +52 -0
  293. package/src/routing.test.ts +170 -0
  294. package/src/sender-allowlist.test.ts +216 -0
  295. package/src/sender-allowlist.ts +128 -0
  296. package/src/session-commands.test.ts +247 -0
  297. package/src/session-commands.ts +163 -0
  298. package/src/task-scheduler.test.ts +129 -0
  299. package/src/task-scheduler.ts +295 -0
  300. package/src/timezone.test.ts +29 -0
  301. package/src/timezone.ts +16 -0
  302. package/src/types.ts +107 -0
  303. package/tsconfig.json +20 -0
  304. package/vitest.config.ts +7 -0
  305. package/vitest.skills.config.ts +7 -0
package/setup.sh ADDED
@@ -0,0 +1,161 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # setup.sh — Bootstrap script for NanoClaw
5
+ # Handles Node.js/npm setup, then hands off to the Node.js setup modules.
6
+ # This is the only bash script in the setup flow.
7
+
8
+ PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ LOG_FILE="$PROJECT_ROOT/logs/setup.log"
10
+
11
+ mkdir -p "$PROJECT_ROOT/logs"
12
+
13
+ log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [bootstrap] $*" >> "$LOG_FILE"; }
14
+
15
+ # --- Platform detection ---
16
+
17
+ detect_platform() {
18
+ local uname_s
19
+ uname_s=$(uname -s)
20
+ case "$uname_s" in
21
+ Darwin*) PLATFORM="macos" ;;
22
+ Linux*) PLATFORM="linux" ;;
23
+ *) PLATFORM="unknown" ;;
24
+ esac
25
+
26
+ IS_WSL="false"
27
+ if [ "$PLATFORM" = "linux" ] && [ -f /proc/version ]; then
28
+ if grep -qi 'microsoft\|wsl' /proc/version 2>/dev/null; then
29
+ IS_WSL="true"
30
+ fi
31
+ fi
32
+
33
+ IS_ROOT="false"
34
+ if [ "$(id -u)" -eq 0 ]; then
35
+ IS_ROOT="true"
36
+ fi
37
+
38
+ log "Platform: $PLATFORM, WSL: $IS_WSL, Root: $IS_ROOT"
39
+ }
40
+
41
+ # --- Node.js check ---
42
+
43
+ check_node() {
44
+ NODE_OK="false"
45
+ NODE_VERSION="not_found"
46
+ NODE_PATH_FOUND=""
47
+
48
+ if command -v node >/dev/null 2>&1; then
49
+ NODE_VERSION=$(node --version 2>/dev/null | sed 's/^v//')
50
+ NODE_PATH_FOUND=$(command -v node)
51
+ local major
52
+ major=$(echo "$NODE_VERSION" | cut -d. -f1)
53
+ if [ "$major" -ge 20 ] 2>/dev/null; then
54
+ NODE_OK="true"
55
+ fi
56
+ log "Node $NODE_VERSION at $NODE_PATH_FOUND (major=$major, ok=$NODE_OK)"
57
+ else
58
+ log "Node not found"
59
+ fi
60
+ }
61
+
62
+ # --- npm install ---
63
+
64
+ install_deps() {
65
+ DEPS_OK="false"
66
+ NATIVE_OK="false"
67
+
68
+ if [ "$NODE_OK" = "false" ]; then
69
+ log "Skipping npm install — Node not available"
70
+ return
71
+ fi
72
+
73
+ cd "$PROJECT_ROOT"
74
+
75
+ # npm install with --unsafe-perm if root (needed for native modules)
76
+ local npm_flags=""
77
+ if [ "$IS_ROOT" = "true" ]; then
78
+ npm_flags="--unsafe-perm"
79
+ log "Running as root, using --unsafe-perm"
80
+ fi
81
+
82
+ log "Running npm ci $npm_flags"
83
+ if npm ci $npm_flags >> "$LOG_FILE" 2>&1; then
84
+ DEPS_OK="true"
85
+ log "npm install succeeded"
86
+ else
87
+ log "npm install failed"
88
+ return
89
+ fi
90
+
91
+ # Verify native module (better-sqlite3)
92
+ log "Verifying native modules"
93
+ if node -e "require('better-sqlite3')" >> "$LOG_FILE" 2>&1; then
94
+ NATIVE_OK="true"
95
+ log "better-sqlite3 loads OK"
96
+ else
97
+ log "better-sqlite3 failed to load"
98
+ fi
99
+ }
100
+
101
+ # --- Build tools check ---
102
+
103
+ check_build_tools() {
104
+ HAS_BUILD_TOOLS="false"
105
+
106
+ if [ "$PLATFORM" = "macos" ]; then
107
+ if xcode-select -p >/dev/null 2>&1; then
108
+ HAS_BUILD_TOOLS="true"
109
+ fi
110
+ elif [ "$PLATFORM" = "linux" ]; then
111
+ if command -v gcc >/dev/null 2>&1 && command -v make >/dev/null 2>&1; then
112
+ HAS_BUILD_TOOLS="true"
113
+ fi
114
+ fi
115
+
116
+ log "Build tools: $HAS_BUILD_TOOLS"
117
+ }
118
+
119
+ # --- Main ---
120
+
121
+ log "=== Bootstrap started ==="
122
+
123
+ detect_platform
124
+ check_node
125
+ install_deps
126
+ check_build_tools
127
+
128
+ # Emit status block
129
+ STATUS="success"
130
+ if [ "$NODE_OK" = "false" ]; then
131
+ STATUS="node_missing"
132
+ elif [ "$DEPS_OK" = "false" ]; then
133
+ STATUS="deps_failed"
134
+ elif [ "$NATIVE_OK" = "false" ]; then
135
+ STATUS="native_failed"
136
+ fi
137
+
138
+ cat <<EOF
139
+ === NANOCLAW SETUP: BOOTSTRAP ===
140
+ PLATFORM: $PLATFORM
141
+ IS_WSL: $IS_WSL
142
+ IS_ROOT: $IS_ROOT
143
+ NODE_VERSION: $NODE_VERSION
144
+ NODE_OK: $NODE_OK
145
+ NODE_PATH: ${NODE_PATH_FOUND:-not_found}
146
+ DEPS_OK: $DEPS_OK
147
+ NATIVE_OK: $NATIVE_OK
148
+ HAS_BUILD_TOOLS: $HAS_BUILD_TOOLS
149
+ STATUS: $STATUS
150
+ LOG: logs/setup.log
151
+ === END ===
152
+ EOF
153
+
154
+ log "=== Bootstrap completed: $STATUS ==="
155
+
156
+ if [ "$NODE_OK" = "false" ]; then
157
+ exit 2
158
+ fi
159
+ if [ "$DEPS_OK" = "false" ] || [ "$NATIVE_OK" = "false" ]; then
160
+ exit 1
161
+ fi
@@ -0,0 +1,12 @@
1
+ // Channel self-registration barrel file.
2
+ // Each import triggers the channel module's registerChannel() call.
3
+
4
+ // discord
5
+
6
+ // gmail
7
+
8
+ // slack
9
+
10
+ // telegram
11
+
12
+ // whatsapp
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+
3
+ import {
4
+ registerChannel,
5
+ getChannelFactory,
6
+ getRegisteredChannelNames,
7
+ } from './registry.js';
8
+
9
+ // The registry is module-level state, so we need a fresh module per test.
10
+ // We use dynamic import with cache-busting to isolate tests.
11
+ // However, since vitest runs each file in its own context and we control
12
+ // registration order, we can test the public API directly.
13
+
14
+ describe('channel registry', () => {
15
+ // Note: registry is shared module state across tests in this file.
16
+ // Tests are ordered to account for cumulative registrations.
17
+
18
+ it('getChannelFactory returns undefined for unknown channel', () => {
19
+ expect(getChannelFactory('nonexistent')).toBeUndefined();
20
+ });
21
+
22
+ it('registerChannel and getChannelFactory round-trip', () => {
23
+ const factory = () => null;
24
+ registerChannel('test-channel', factory);
25
+ expect(getChannelFactory('test-channel')).toBe(factory);
26
+ });
27
+
28
+ it('getRegisteredChannelNames includes registered channels', () => {
29
+ registerChannel('another-channel', () => null);
30
+ const names = getRegisteredChannelNames();
31
+ expect(names).toContain('test-channel');
32
+ expect(names).toContain('another-channel');
33
+ });
34
+
35
+ it('later registration overwrites earlier one', () => {
36
+ const factory1 = () => null;
37
+ const factory2 = () => null;
38
+ registerChannel('overwrite-test', factory1);
39
+ registerChannel('overwrite-test', factory2);
40
+ expect(getChannelFactory('overwrite-test')).toBe(factory2);
41
+ });
42
+ });
@@ -0,0 +1,32 @@
1
+ import {
2
+ Channel,
3
+ OnInboundMessage,
4
+ OnChatMetadata,
5
+ RegisteredGroup,
6
+ } from '../types.js';
7
+
8
+ export interface ChannelOpts {
9
+ onMessage: OnInboundMessage;
10
+ onChatMetadata: OnChatMetadata;
11
+ registeredGroups: () => Record<string, RegisteredGroup>;
12
+ // Optional: channels that self-register their main group call this during connect()
13
+ registerGroup?: (jid: string, group: RegisteredGroup) => void;
14
+ // Optional: cancel the active agent run for a JID (e.g. write _close sentinel)
15
+ onCancelRequest?: (jid: string) => void;
16
+ }
17
+
18
+ export type ChannelFactory = (opts: ChannelOpts) => Channel | null;
19
+
20
+ const registry = new Map<string, ChannelFactory>();
21
+
22
+ export function registerChannel(name: string, factory: ChannelFactory): void {
23
+ registry.set(name, factory);
24
+ }
25
+
26
+ export function getChannelFactory(name: string): ChannelFactory | undefined {
27
+ return registry.get(name);
28
+ }
29
+
30
+ export function getRegisteredChannelNames(): string[] {
31
+ return [...registry.keys()];
32
+ }