@stoneforge/quarry 0.1.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 (330) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +160 -0
  3. package/dist/api/index.d.ts +8 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/api/index.js +8 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/quarry-api.d.ts +268 -0
  8. package/dist/api/quarry-api.d.ts.map +1 -0
  9. package/dist/api/quarry-api.js +3905 -0
  10. package/dist/api/quarry-api.js.map +1 -0
  11. package/dist/api/types.d.ts +1359 -0
  12. package/dist/api/types.d.ts.map +1 -0
  13. package/dist/api/types.js +204 -0
  14. package/dist/api/types.js.map +1 -0
  15. package/dist/bin/sf.d.ts +3 -0
  16. package/dist/bin/sf.d.ts.map +1 -0
  17. package/dist/bin/sf.js +9 -0
  18. package/dist/bin/sf.js.map +1 -0
  19. package/dist/cli/commands/admin.d.ts +11 -0
  20. package/dist/cli/commands/admin.d.ts.map +1 -0
  21. package/dist/cli/commands/admin.js +465 -0
  22. package/dist/cli/commands/admin.js.map +1 -0
  23. package/dist/cli/commands/alias.d.ts +8 -0
  24. package/dist/cli/commands/alias.d.ts.map +1 -0
  25. package/dist/cli/commands/alias.js +70 -0
  26. package/dist/cli/commands/alias.js.map +1 -0
  27. package/dist/cli/commands/channel.d.ts +13 -0
  28. package/dist/cli/commands/channel.d.ts.map +1 -0
  29. package/dist/cli/commands/channel.js +680 -0
  30. package/dist/cli/commands/channel.js.map +1 -0
  31. package/dist/cli/commands/completion.d.ts +8 -0
  32. package/dist/cli/commands/completion.d.ts.map +1 -0
  33. package/dist/cli/commands/completion.js +87 -0
  34. package/dist/cli/commands/completion.js.map +1 -0
  35. package/dist/cli/commands/config.d.ts +12 -0
  36. package/dist/cli/commands/config.d.ts.map +1 -0
  37. package/dist/cli/commands/config.js +242 -0
  38. package/dist/cli/commands/config.js.map +1 -0
  39. package/dist/cli/commands/crud.d.ts +64 -0
  40. package/dist/cli/commands/crud.d.ts.map +1 -0
  41. package/dist/cli/commands/crud.js +805 -0
  42. package/dist/cli/commands/crud.js.map +1 -0
  43. package/dist/cli/commands/dep.d.ts +16 -0
  44. package/dist/cli/commands/dep.d.ts.map +1 -0
  45. package/dist/cli/commands/dep.js +499 -0
  46. package/dist/cli/commands/dep.js.map +1 -0
  47. package/dist/cli/commands/document.d.ts +12 -0
  48. package/dist/cli/commands/document.d.ts.map +1 -0
  49. package/dist/cli/commands/document.js +1039 -0
  50. package/dist/cli/commands/document.js.map +1 -0
  51. package/dist/cli/commands/embeddings.d.ts +12 -0
  52. package/dist/cli/commands/embeddings.d.ts.map +1 -0
  53. package/dist/cli/commands/embeddings.js +273 -0
  54. package/dist/cli/commands/embeddings.js.map +1 -0
  55. package/dist/cli/commands/entity.d.ts +16 -0
  56. package/dist/cli/commands/entity.d.ts.map +1 -0
  57. package/dist/cli/commands/entity.js +522 -0
  58. package/dist/cli/commands/entity.js.map +1 -0
  59. package/dist/cli/commands/gc.d.ts +10 -0
  60. package/dist/cli/commands/gc.d.ts.map +1 -0
  61. package/dist/cli/commands/gc.js +257 -0
  62. package/dist/cli/commands/gc.js.map +1 -0
  63. package/dist/cli/commands/help.d.ts +11 -0
  64. package/dist/cli/commands/help.d.ts.map +1 -0
  65. package/dist/cli/commands/help.js +169 -0
  66. package/dist/cli/commands/help.js.map +1 -0
  67. package/dist/cli/commands/history.d.ts +9 -0
  68. package/dist/cli/commands/history.d.ts.map +1 -0
  69. package/dist/cli/commands/history.js +160 -0
  70. package/dist/cli/commands/history.js.map +1 -0
  71. package/dist/cli/commands/identity.d.ts +18 -0
  72. package/dist/cli/commands/identity.d.ts.map +1 -0
  73. package/dist/cli/commands/identity.js +698 -0
  74. package/dist/cli/commands/identity.js.map +1 -0
  75. package/dist/cli/commands/inbox.d.ts +20 -0
  76. package/dist/cli/commands/inbox.d.ts.map +1 -0
  77. package/dist/cli/commands/inbox.js +493 -0
  78. package/dist/cli/commands/inbox.js.map +1 -0
  79. package/dist/cli/commands/init.d.ts +20 -0
  80. package/dist/cli/commands/init.d.ts.map +1 -0
  81. package/dist/cli/commands/init.js +144 -0
  82. package/dist/cli/commands/init.js.map +1 -0
  83. package/dist/cli/commands/install.d.ts +9 -0
  84. package/dist/cli/commands/install.d.ts.map +1 -0
  85. package/dist/cli/commands/install.js +200 -0
  86. package/dist/cli/commands/install.js.map +1 -0
  87. package/dist/cli/commands/library.d.ts +12 -0
  88. package/dist/cli/commands/library.d.ts.map +1 -0
  89. package/dist/cli/commands/library.js +665 -0
  90. package/dist/cli/commands/library.js.map +1 -0
  91. package/dist/cli/commands/message.d.ts +11 -0
  92. package/dist/cli/commands/message.d.ts.map +1 -0
  93. package/dist/cli/commands/message.js +608 -0
  94. package/dist/cli/commands/message.js.map +1 -0
  95. package/dist/cli/commands/plan.d.ts +17 -0
  96. package/dist/cli/commands/plan.d.ts.map +1 -0
  97. package/dist/cli/commands/plan.js +698 -0
  98. package/dist/cli/commands/plan.js.map +1 -0
  99. package/dist/cli/commands/playbook.d.ts +12 -0
  100. package/dist/cli/commands/playbook.d.ts.map +1 -0
  101. package/dist/cli/commands/playbook.js +730 -0
  102. package/dist/cli/commands/playbook.js.map +1 -0
  103. package/dist/cli/commands/reset.d.ts +12 -0
  104. package/dist/cli/commands/reset.d.ts.map +1 -0
  105. package/dist/cli/commands/reset.js +306 -0
  106. package/dist/cli/commands/reset.js.map +1 -0
  107. package/dist/cli/commands/serve.d.ts +11 -0
  108. package/dist/cli/commands/serve.d.ts.map +1 -0
  109. package/dist/cli/commands/serve.js +106 -0
  110. package/dist/cli/commands/serve.js.map +1 -0
  111. package/dist/cli/commands/stats.d.ts +8 -0
  112. package/dist/cli/commands/stats.d.ts.map +1 -0
  113. package/dist/cli/commands/stats.js +82 -0
  114. package/dist/cli/commands/stats.js.map +1 -0
  115. package/dist/cli/commands/sync.d.ts +14 -0
  116. package/dist/cli/commands/sync.d.ts.map +1 -0
  117. package/dist/cli/commands/sync.js +370 -0
  118. package/dist/cli/commands/sync.js.map +1 -0
  119. package/dist/cli/commands/task.d.ts +25 -0
  120. package/dist/cli/commands/task.d.ts.map +1 -0
  121. package/dist/cli/commands/task.js +1153 -0
  122. package/dist/cli/commands/task.js.map +1 -0
  123. package/dist/cli/commands/team.d.ts +13 -0
  124. package/dist/cli/commands/team.d.ts.map +1 -0
  125. package/dist/cli/commands/team.js +471 -0
  126. package/dist/cli/commands/team.js.map +1 -0
  127. package/dist/cli/commands/workflow.d.ts +16 -0
  128. package/dist/cli/commands/workflow.d.ts.map +1 -0
  129. package/dist/cli/commands/workflow.js +753 -0
  130. package/dist/cli/commands/workflow.js.map +1 -0
  131. package/dist/cli/completion.d.ts +28 -0
  132. package/dist/cli/completion.d.ts.map +1 -0
  133. package/dist/cli/completion.js +295 -0
  134. package/dist/cli/completion.js.map +1 -0
  135. package/dist/cli/db.d.ts +38 -0
  136. package/dist/cli/db.d.ts.map +1 -0
  137. package/dist/cli/db.js +90 -0
  138. package/dist/cli/db.js.map +1 -0
  139. package/dist/cli/formatter.d.ts +87 -0
  140. package/dist/cli/formatter.d.ts.map +1 -0
  141. package/dist/cli/formatter.js +464 -0
  142. package/dist/cli/formatter.js.map +1 -0
  143. package/dist/cli/index.d.ts +33 -0
  144. package/dist/cli/index.d.ts.map +1 -0
  145. package/dist/cli/index.js +38 -0
  146. package/dist/cli/index.js.map +1 -0
  147. package/dist/cli/parser.d.ts +45 -0
  148. package/dist/cli/parser.d.ts.map +1 -0
  149. package/dist/cli/parser.js +256 -0
  150. package/dist/cli/parser.js.map +1 -0
  151. package/dist/cli/plugin-loader.d.ts +39 -0
  152. package/dist/cli/plugin-loader.d.ts.map +1 -0
  153. package/dist/cli/plugin-loader.js +165 -0
  154. package/dist/cli/plugin-loader.js.map +1 -0
  155. package/dist/cli/plugin-registry.d.ts +50 -0
  156. package/dist/cli/plugin-registry.d.ts.map +1 -0
  157. package/dist/cli/plugin-registry.js +206 -0
  158. package/dist/cli/plugin-registry.js.map +1 -0
  159. package/dist/cli/plugin-types.d.ts +106 -0
  160. package/dist/cli/plugin-types.d.ts.map +1 -0
  161. package/dist/cli/plugin-types.js +103 -0
  162. package/dist/cli/plugin-types.js.map +1 -0
  163. package/dist/cli/runner.d.ts +35 -0
  164. package/dist/cli/runner.d.ts.map +1 -0
  165. package/dist/cli/runner.js +340 -0
  166. package/dist/cli/runner.js.map +1 -0
  167. package/dist/cli/suggest.d.ts +15 -0
  168. package/dist/cli/suggest.d.ts.map +1 -0
  169. package/dist/cli/suggest.js +49 -0
  170. package/dist/cli/suggest.js.map +1 -0
  171. package/dist/cli/types.d.ts +138 -0
  172. package/dist/cli/types.d.ts.map +1 -0
  173. package/dist/cli/types.js +63 -0
  174. package/dist/cli/types.js.map +1 -0
  175. package/dist/config/config.d.ts +86 -0
  176. package/dist/config/config.d.ts.map +1 -0
  177. package/dist/config/config.js +348 -0
  178. package/dist/config/config.js.map +1 -0
  179. package/dist/config/defaults.d.ts +66 -0
  180. package/dist/config/defaults.d.ts.map +1 -0
  181. package/dist/config/defaults.js +114 -0
  182. package/dist/config/defaults.js.map +1 -0
  183. package/dist/config/duration.d.ts +75 -0
  184. package/dist/config/duration.d.ts.map +1 -0
  185. package/dist/config/duration.js +190 -0
  186. package/dist/config/duration.js.map +1 -0
  187. package/dist/config/env.d.ts +67 -0
  188. package/dist/config/env.d.ts.map +1 -0
  189. package/dist/config/env.js +207 -0
  190. package/dist/config/env.js.map +1 -0
  191. package/dist/config/file.d.ts +97 -0
  192. package/dist/config/file.d.ts.map +1 -0
  193. package/dist/config/file.js +365 -0
  194. package/dist/config/file.js.map +1 -0
  195. package/dist/config/index.d.ts +35 -0
  196. package/dist/config/index.d.ts.map +1 -0
  197. package/dist/config/index.js +41 -0
  198. package/dist/config/index.js.map +1 -0
  199. package/dist/config/merge.d.ts +53 -0
  200. package/dist/config/merge.d.ts.map +1 -0
  201. package/dist/config/merge.js +226 -0
  202. package/dist/config/merge.js.map +1 -0
  203. package/dist/config/types.d.ts +257 -0
  204. package/dist/config/types.d.ts.map +1 -0
  205. package/dist/config/types.js +72 -0
  206. package/dist/config/types.js.map +1 -0
  207. package/dist/config/validation.d.ts +55 -0
  208. package/dist/config/validation.d.ts.map +1 -0
  209. package/dist/config/validation.js +251 -0
  210. package/dist/config/validation.js.map +1 -0
  211. package/dist/http/index.d.ts +8 -0
  212. package/dist/http/index.d.ts.map +1 -0
  213. package/dist/http/index.js +12 -0
  214. package/dist/http/index.js.map +1 -0
  215. package/dist/http/sync-handlers.d.ts +162 -0
  216. package/dist/http/sync-handlers.d.ts.map +1 -0
  217. package/dist/http/sync-handlers.js +271 -0
  218. package/dist/http/sync-handlers.js.map +1 -0
  219. package/dist/index.d.ts +25 -0
  220. package/dist/index.d.ts.map +1 -0
  221. package/dist/index.js +69 -0
  222. package/dist/index.js.map +1 -0
  223. package/dist/server/index.d.ts +34 -0
  224. package/dist/server/index.d.ts.map +1 -0
  225. package/dist/server/index.js +3329 -0
  226. package/dist/server/index.js.map +1 -0
  227. package/dist/server/static.d.ts +18 -0
  228. package/dist/server/static.d.ts.map +1 -0
  229. package/dist/server/static.js +71 -0
  230. package/dist/server/static.js.map +1 -0
  231. package/dist/server/ws/broadcaster.d.ts +8 -0
  232. package/dist/server/ws/broadcaster.d.ts.map +1 -0
  233. package/dist/server/ws/broadcaster.js +7 -0
  234. package/dist/server/ws/broadcaster.js.map +1 -0
  235. package/dist/server/ws/handler.d.ts +55 -0
  236. package/dist/server/ws/handler.d.ts.map +1 -0
  237. package/dist/server/ws/handler.js +160 -0
  238. package/dist/server/ws/handler.js.map +1 -0
  239. package/dist/services/blocked-cache.d.ts +297 -0
  240. package/dist/services/blocked-cache.d.ts.map +1 -0
  241. package/dist/services/blocked-cache.js +755 -0
  242. package/dist/services/blocked-cache.js.map +1 -0
  243. package/dist/services/dependency.d.ts +205 -0
  244. package/dist/services/dependency.d.ts.map +1 -0
  245. package/dist/services/dependency.js +566 -0
  246. package/dist/services/dependency.js.map +1 -0
  247. package/dist/services/embeddings/fusion.d.ts +33 -0
  248. package/dist/services/embeddings/fusion.d.ts.map +1 -0
  249. package/dist/services/embeddings/fusion.js +34 -0
  250. package/dist/services/embeddings/fusion.js.map +1 -0
  251. package/dist/services/embeddings/index.d.ts +12 -0
  252. package/dist/services/embeddings/index.d.ts.map +1 -0
  253. package/dist/services/embeddings/index.js +10 -0
  254. package/dist/services/embeddings/index.js.map +1 -0
  255. package/dist/services/embeddings/local-provider.d.ts +31 -0
  256. package/dist/services/embeddings/local-provider.d.ts.map +1 -0
  257. package/dist/services/embeddings/local-provider.js +80 -0
  258. package/dist/services/embeddings/local-provider.js.map +1 -0
  259. package/dist/services/embeddings/service.d.ts +76 -0
  260. package/dist/services/embeddings/service.d.ts.map +1 -0
  261. package/dist/services/embeddings/service.js +153 -0
  262. package/dist/services/embeddings/service.js.map +1 -0
  263. package/dist/services/embeddings/types.d.ts +70 -0
  264. package/dist/services/embeddings/types.d.ts.map +1 -0
  265. package/dist/services/embeddings/types.js +8 -0
  266. package/dist/services/embeddings/types.js.map +1 -0
  267. package/dist/services/id-length-cache.d.ts +156 -0
  268. package/dist/services/id-length-cache.d.ts.map +1 -0
  269. package/dist/services/id-length-cache.js +197 -0
  270. package/dist/services/id-length-cache.js.map +1 -0
  271. package/dist/services/inbox.d.ts +147 -0
  272. package/dist/services/inbox.d.ts.map +1 -0
  273. package/dist/services/inbox.js +428 -0
  274. package/dist/services/inbox.js.map +1 -0
  275. package/dist/services/index.d.ts +10 -0
  276. package/dist/services/index.d.ts.map +1 -0
  277. package/dist/services/index.js +10 -0
  278. package/dist/services/index.js.map +1 -0
  279. package/dist/services/priority-service.d.ts +145 -0
  280. package/dist/services/priority-service.d.ts.map +1 -0
  281. package/dist/services/priority-service.js +272 -0
  282. package/dist/services/priority-service.js.map +1 -0
  283. package/dist/services/search-utils.d.ts +47 -0
  284. package/dist/services/search-utils.d.ts.map +1 -0
  285. package/dist/services/search-utils.js +83 -0
  286. package/dist/services/search-utils.js.map +1 -0
  287. package/dist/sync/hash.d.ts +48 -0
  288. package/dist/sync/hash.d.ts.map +1 -0
  289. package/dist/sync/hash.js +136 -0
  290. package/dist/sync/hash.js.map +1 -0
  291. package/dist/sync/index.d.ts +11 -0
  292. package/dist/sync/index.d.ts.map +1 -0
  293. package/dist/sync/index.js +16 -0
  294. package/dist/sync/index.js.map +1 -0
  295. package/dist/sync/merge.d.ts +80 -0
  296. package/dist/sync/merge.d.ts.map +1 -0
  297. package/dist/sync/merge.js +310 -0
  298. package/dist/sync/merge.js.map +1 -0
  299. package/dist/sync/serialization.d.ts +132 -0
  300. package/dist/sync/serialization.d.ts.map +1 -0
  301. package/dist/sync/serialization.js +306 -0
  302. package/dist/sync/serialization.js.map +1 -0
  303. package/dist/sync/service.d.ts +102 -0
  304. package/dist/sync/service.d.ts.map +1 -0
  305. package/dist/sync/service.js +493 -0
  306. package/dist/sync/service.js.map +1 -0
  307. package/dist/sync/types.d.ts +275 -0
  308. package/dist/sync/types.d.ts.map +1 -0
  309. package/dist/sync/types.js +76 -0
  310. package/dist/sync/types.js.map +1 -0
  311. package/dist/systems/identity.d.ts +479 -0
  312. package/dist/systems/identity.d.ts.map +1 -0
  313. package/dist/systems/identity.js +817 -0
  314. package/dist/systems/identity.js.map +1 -0
  315. package/dist/systems/index.d.ts +8 -0
  316. package/dist/systems/index.d.ts.map +1 -0
  317. package/dist/systems/index.js +29 -0
  318. package/dist/systems/index.js.map +1 -0
  319. package/package.json +121 -0
  320. package/web/assets/charts-vendor-D1YcbGux.js +55 -0
  321. package/web/assets/dnd-vendor-DmxE-_ZH.js +5 -0
  322. package/web/assets/editor-vendor-BxraAWts.js +279 -0
  323. package/web/assets/index-B77vv208.js +341 -0
  324. package/web/assets/index-CF_XnVLh.css +1 -0
  325. package/web/assets/router-vendor-BCKpRBrB.js +41 -0
  326. package/web/assets/ui-vendor-DUahGnbT.js +45 -0
  327. package/web/assets/utils-vendor-CfYKiENT.js +813 -0
  328. package/web/favicon.ico +0 -0
  329. package/web/index.html +23 -0
  330. package/web/logo.png +0 -0
@@ -0,0 +1,680 @@
1
+ /**
2
+ * Channel Commands - Collection command interface for channels
3
+ *
4
+ * Provides CLI commands for channel operations:
5
+ * - channel create: Create a new channel
6
+ * - channel join: Join a channel
7
+ * - channel leave: Leave a channel
8
+ * - channel list: List channels
9
+ * - channel members: List channel members
10
+ */
11
+ import { success, failure, ExitCode } from '../types.js';
12
+ import { getFormatter, getOutputMode } from '../formatter.js';
13
+ import { createGroupChannel, createDirectChannel, ChannelTypeValue, VisibilityValue, JoinPolicyValue, isMember, } from '@stoneforge/core';
14
+ import { suggestCommands } from '../suggest.js';
15
+ import { resolveActor, createAPI } from '../db.js';
16
+ const channelCreateOptions = [
17
+ {
18
+ name: 'name',
19
+ short: 'n',
20
+ description: 'Channel name (required for group channels)',
21
+ hasValue: true,
22
+ },
23
+ {
24
+ name: 'description',
25
+ short: 'D',
26
+ description: 'Channel description',
27
+ hasValue: true,
28
+ },
29
+ {
30
+ name: 'type',
31
+ short: 't',
32
+ description: 'Channel type: group (default) or direct',
33
+ hasValue: true,
34
+ },
35
+ {
36
+ name: 'visibility',
37
+ short: 'V',
38
+ description: 'Visibility: public or private (default)',
39
+ hasValue: true,
40
+ },
41
+ {
42
+ name: 'policy',
43
+ short: 'p',
44
+ description: 'Join policy: open, invite-only (default), or request',
45
+ hasValue: true,
46
+ },
47
+ {
48
+ name: 'member',
49
+ short: 'm',
50
+ description: 'Add member (can be repeated)',
51
+ hasValue: true,
52
+ array: true,
53
+ },
54
+ {
55
+ name: 'direct',
56
+ short: 'd',
57
+ description: 'Create direct channel with entity (for --type direct)',
58
+ hasValue: true,
59
+ },
60
+ {
61
+ name: 'tag',
62
+ description: 'Add tag (can be repeated)',
63
+ hasValue: true,
64
+ array: true,
65
+ },
66
+ ];
67
+ async function channelCreateHandler(_args, options) {
68
+ const channelType = (options.type || 'group');
69
+ if (channelType !== 'group' && channelType !== 'direct') {
70
+ return failure(`Invalid channel type: ${channelType}. Must be 'group' or 'direct'`, ExitCode.VALIDATION);
71
+ }
72
+ const { api, error } = createAPI(options, true);
73
+ if (error) {
74
+ return failure(error, ExitCode.GENERAL_ERROR);
75
+ }
76
+ try {
77
+ const actor = resolveActor(options);
78
+ // Handle tags
79
+ let tags;
80
+ if (options.tag) {
81
+ tags = Array.isArray(options.tag) ? options.tag : [options.tag];
82
+ }
83
+ let channel;
84
+ if (channelType === 'direct') {
85
+ if (!options.direct) {
86
+ return failure('--direct <entity-id> is required for direct channels', ExitCode.INVALID_ARGUMENTS);
87
+ }
88
+ const input = {
89
+ entityA: actor,
90
+ entityB: options.direct,
91
+ createdBy: actor,
92
+ ...(options.description && { description: options.description }),
93
+ ...(tags && { tags }),
94
+ };
95
+ channel = await createDirectChannel(input);
96
+ }
97
+ else {
98
+ if (!options.name) {
99
+ return failure('--name is required for group channels', ExitCode.INVALID_ARGUMENTS);
100
+ }
101
+ // Validate visibility
102
+ const visibility = (options.visibility || 'private');
103
+ if (!Object.values(VisibilityValue).includes(visibility)) {
104
+ return failure(`Invalid visibility: ${visibility}. Must be 'public' or 'private'`, ExitCode.VALIDATION);
105
+ }
106
+ // Validate join policy
107
+ const joinPolicy = (options.policy || 'invite-only');
108
+ if (!Object.values(JoinPolicyValue).includes(joinPolicy)) {
109
+ return failure(`Invalid join policy: ${joinPolicy}. Must be 'open', 'invite-only', or 'request'`, ExitCode.VALIDATION);
110
+ }
111
+ // Parse members
112
+ let members;
113
+ if (options.member) {
114
+ members = (Array.isArray(options.member) ? options.member : [options.member]);
115
+ }
116
+ const input = {
117
+ name: options.name,
118
+ createdBy: actor,
119
+ description: options.description ?? null,
120
+ visibility,
121
+ joinPolicy,
122
+ ...(members && { members }),
123
+ ...(tags && { tags }),
124
+ };
125
+ channel = await createGroupChannel(input);
126
+ }
127
+ const created = await api.create(channel);
128
+ const mode = getOutputMode(options);
129
+ if (mode === 'quiet') {
130
+ return success(created.id);
131
+ }
132
+ return success(created, `Created ${channelType} channel ${created.id}`);
133
+ }
134
+ catch (err) {
135
+ const message = err instanceof Error ? err.message : String(err);
136
+ return failure(`Failed to create channel: ${message}`, ExitCode.GENERAL_ERROR);
137
+ }
138
+ }
139
+ const channelCreateCommand = {
140
+ name: 'create',
141
+ description: 'Create a new channel',
142
+ usage: 'sf channel create [options]',
143
+ help: `Create a new channel for communication.
144
+
145
+ Options:
146
+ -n, --name <name> Channel name (required for group)
147
+ -D, --description <desc> Channel description
148
+ -t, --type <type> Type: group (default) or direct
149
+ -V, --visibility <vis> Visibility: public or private (default)
150
+ -p, --policy <policy> Join policy: open, invite-only (default), request
151
+ -m, --member <entity> Add member (can be repeated)
152
+ -d, --direct <entity> Create direct channel with entity
153
+ --tag <tag> Add tag (can be repeated)
154
+
155
+ Examples:
156
+ sf channel create --name general --description "General discussion"
157
+ sf channel create -n announcements -V public -p open
158
+ sf channel create --type direct --direct el-user123
159
+ sf channel create -n team -m el-user1 -m el-user2`,
160
+ options: channelCreateOptions,
161
+ handler: channelCreateHandler,
162
+ };
163
+ // ============================================================================
164
+ // Channel Join Command
165
+ // ============================================================================
166
+ async function channelJoinHandler(args, options) {
167
+ const [id] = args;
168
+ if (!id) {
169
+ return failure('Usage: sf channel join <id>\nExample: sf channel join el-abc123', ExitCode.INVALID_ARGUMENTS);
170
+ }
171
+ const { api, error } = createAPI(options);
172
+ if (error) {
173
+ return failure(error, ExitCode.GENERAL_ERROR);
174
+ }
175
+ try {
176
+ const actor = resolveActor(options);
177
+ const channel = await api.get(id);
178
+ if (!channel) {
179
+ return failure(`Channel not found: ${id}`, ExitCode.NOT_FOUND);
180
+ }
181
+ if (channel.type !== 'channel') {
182
+ return failure(`Element ${id} is not a channel (type: ${channel.type})`, ExitCode.VALIDATION);
183
+ }
184
+ if (channel.channelType === ChannelTypeValue.DIRECT) {
185
+ return failure('Cannot join a direct channel', ExitCode.VALIDATION);
186
+ }
187
+ if (isMember(channel, actor)) {
188
+ return success(channel, `Already a member of channel ${id}`);
189
+ }
190
+ // Check join policy
191
+ if (channel.permissions.joinPolicy === JoinPolicyValue.INVITE_ONLY) {
192
+ return failure('Channel is invite-only. Ask a moderator to add you.', ExitCode.VALIDATION);
193
+ }
194
+ if (channel.permissions.joinPolicy === JoinPolicyValue.OPEN &&
195
+ channel.permissions.visibility !== VisibilityValue.PUBLIC) {
196
+ return failure('Channel is private. Cannot join without invitation.', ExitCode.VALIDATION);
197
+ }
198
+ // Add actor to members
199
+ const newMembers = [...channel.members, actor];
200
+ const updated = await api.update(id, { members: newMembers }, { actor });
201
+ return success(updated, `Joined channel ${id}`);
202
+ }
203
+ catch (err) {
204
+ const message = err instanceof Error ? err.message : String(err);
205
+ return failure(`Failed to join channel: ${message}`, ExitCode.GENERAL_ERROR);
206
+ }
207
+ }
208
+ const channelJoinCommand = {
209
+ name: 'join',
210
+ description: 'Join a channel',
211
+ usage: 'sf channel join <id>',
212
+ help: `Join a channel.
213
+
214
+ Only works for group channels with open or request join policy.
215
+ Direct channels and invite-only channels cannot be joined directly.
216
+
217
+ Arguments:
218
+ id Channel identifier
219
+
220
+ Examples:
221
+ sf channel join el-abc123`,
222
+ handler: channelJoinHandler,
223
+ };
224
+ // ============================================================================
225
+ // Channel Leave Command
226
+ // ============================================================================
227
+ async function channelLeaveHandler(args, options) {
228
+ const [id] = args;
229
+ if (!id) {
230
+ return failure('Usage: sf channel leave <id>\nExample: sf channel leave el-abc123', ExitCode.INVALID_ARGUMENTS);
231
+ }
232
+ const { api, error } = createAPI(options);
233
+ if (error) {
234
+ return failure(error, ExitCode.GENERAL_ERROR);
235
+ }
236
+ try {
237
+ const actor = resolveActor(options);
238
+ const result = await api.leaveChannel(id, actor);
239
+ return success(result.channel, `Left channel ${id}`);
240
+ }
241
+ catch (err) {
242
+ // Handle specific error cases with user-friendly messages
243
+ if (err instanceof Error) {
244
+ if (err.message.includes('not found')) {
245
+ return failure(`Channel not found: ${id}`, ExitCode.NOT_FOUND);
246
+ }
247
+ if (err.message.includes('not a channel')) {
248
+ return failure(`Element ${id} is not a channel`, ExitCode.VALIDATION);
249
+ }
250
+ if (err.message.includes('Cannot leave a direct channel')) {
251
+ return failure('Cannot leave a direct channel', ExitCode.VALIDATION);
252
+ }
253
+ if (err.message.includes('not a member')) {
254
+ // Not an error - just inform the user
255
+ const channel = await api.get(id);
256
+ return success(channel, `Not a member of channel ${id}`);
257
+ }
258
+ }
259
+ const message = err instanceof Error ? err.message : String(err);
260
+ return failure(`Failed to leave channel: ${message}`, ExitCode.GENERAL_ERROR);
261
+ }
262
+ }
263
+ const channelLeaveCommand = {
264
+ name: 'leave',
265
+ description: 'Leave a channel',
266
+ usage: 'sf channel leave <id>',
267
+ help: `Leave a channel.
268
+
269
+ Only works for group channels. Direct channels cannot be left.
270
+
271
+ Arguments:
272
+ id Channel identifier
273
+
274
+ Examples:
275
+ sf channel leave el-abc123`,
276
+ handler: channelLeaveHandler,
277
+ };
278
+ const channelListOptions = [
279
+ {
280
+ name: 'type',
281
+ short: 't',
282
+ description: 'Filter by type: group or direct',
283
+ hasValue: true,
284
+ },
285
+ {
286
+ name: 'member',
287
+ short: 'm',
288
+ description: 'Filter by member entity',
289
+ hasValue: true,
290
+ },
291
+ {
292
+ name: 'limit',
293
+ short: 'l',
294
+ description: 'Maximum number of results',
295
+ hasValue: true,
296
+ },
297
+ ];
298
+ async function channelListHandler(_args, options) {
299
+ const { api, error } = createAPI(options);
300
+ if (error) {
301
+ return failure(error, ExitCode.GENERAL_ERROR);
302
+ }
303
+ try {
304
+ // Build filter
305
+ const filter = {
306
+ type: 'channel',
307
+ };
308
+ // Limit
309
+ if (options.limit) {
310
+ const limit = parseInt(options.limit, 10);
311
+ if (isNaN(limit) || limit < 1) {
312
+ return failure('Limit must be a positive number', ExitCode.VALIDATION);
313
+ }
314
+ filter.limit = limit;
315
+ }
316
+ const result = await api.listPaginated(filter);
317
+ // Post-filter
318
+ let items = result.items;
319
+ // Type filter
320
+ if (options.type) {
321
+ if (options.type !== 'group' && options.type !== 'direct') {
322
+ return failure(`Invalid type: ${options.type}. Must be 'group' or 'direct'`, ExitCode.VALIDATION);
323
+ }
324
+ items = items.filter((c) => c.channelType === options.type);
325
+ }
326
+ // Member filter
327
+ if (options.member) {
328
+ items = items.filter((c) => c.members.includes(options.member));
329
+ }
330
+ const mode = getOutputMode(options);
331
+ const formatter = getFormatter(mode);
332
+ if (mode === 'json') {
333
+ return success(items);
334
+ }
335
+ if (mode === 'quiet') {
336
+ return success(items.map((c) => c.id).join('\n'));
337
+ }
338
+ if (items.length === 0) {
339
+ return success(null, 'No channels found');
340
+ }
341
+ // Build table
342
+ const headers = ['ID', 'NAME', 'TYPE', 'MEMBERS', 'VISIBILITY', 'DESCRIPTION', 'CREATED'];
343
+ const rows = items.map((c) => {
344
+ const desc = c.description ?? '';
345
+ const truncDesc = desc.length > 30 ? desc.substring(0, 27) + '...' : desc;
346
+ return [
347
+ c.id,
348
+ c.name.length > 25 ? c.name.substring(0, 22) + '...' : c.name,
349
+ c.channelType,
350
+ String(c.members.length),
351
+ c.permissions.visibility,
352
+ truncDesc,
353
+ c.createdAt.split('T')[0],
354
+ ];
355
+ });
356
+ const table = formatter.table(headers, rows);
357
+ const summary = `\nShowing ${items.length} of ${result.total} channels`;
358
+ return success(items, table + summary);
359
+ }
360
+ catch (err) {
361
+ const message = err instanceof Error ? err.message : String(err);
362
+ return failure(`Failed to list channels: ${message}`, ExitCode.GENERAL_ERROR);
363
+ }
364
+ }
365
+ const channelListCommand = {
366
+ name: 'list',
367
+ description: 'List channels',
368
+ usage: 'sf channel list [options]',
369
+ help: `List channels with optional filtering.
370
+
371
+ Options:
372
+ -t, --type <type> Filter by type: group or direct
373
+ -m, --member <entity> Filter by member entity
374
+ -l, --limit <n> Maximum results
375
+
376
+ Examples:
377
+ sf channel list
378
+ sf channel list --type group
379
+ sf channel list --member el-user123`,
380
+ options: channelListOptions,
381
+ handler: channelListHandler,
382
+ };
383
+ // ============================================================================
384
+ // Channel Members Command
385
+ // ============================================================================
386
+ async function channelMembersHandler(args, options) {
387
+ const [id] = args;
388
+ if (!id) {
389
+ return failure('Usage: sf channel members <id>\nExample: sf channel members el-abc123', ExitCode.INVALID_ARGUMENTS);
390
+ }
391
+ const { api, error } = createAPI(options);
392
+ if (error) {
393
+ return failure(error, ExitCode.GENERAL_ERROR);
394
+ }
395
+ try {
396
+ const channel = await api.get(id);
397
+ if (!channel) {
398
+ return failure(`Channel not found: ${id}`, ExitCode.NOT_FOUND);
399
+ }
400
+ if (channel.type !== 'channel') {
401
+ return failure(`Element ${id} is not a channel (type: ${channel.type})`, ExitCode.VALIDATION);
402
+ }
403
+ const members = channel.members;
404
+ const modifiers = channel.permissions.modifyMembers;
405
+ const mode = getOutputMode(options);
406
+ const formatter = getFormatter(mode);
407
+ if (mode === 'json') {
408
+ return success({ members, modifiers, count: members.length });
409
+ }
410
+ if (mode === 'quiet') {
411
+ return success(members.join('\n'));
412
+ }
413
+ if (members.length === 0) {
414
+ return success({ members: [], count: 0 }, 'No members');
415
+ }
416
+ // Build table
417
+ const headers = ['MEMBER', 'ROLE'];
418
+ const rows = members.map((m) => [
419
+ m,
420
+ modifiers.includes(m) ? 'moderator' : 'member',
421
+ ]);
422
+ const table = formatter.table(headers, rows);
423
+ return success({ members, modifiers, count: members.length }, table + `\n${members.length} member(s)`);
424
+ }
425
+ catch (err) {
426
+ const message = err instanceof Error ? err.message : String(err);
427
+ return failure(`Failed to list members: ${message}`, ExitCode.GENERAL_ERROR);
428
+ }
429
+ }
430
+ const channelMembersCommand = {
431
+ name: 'members',
432
+ description: 'List channel members',
433
+ usage: 'sf channel members <id>',
434
+ help: `List members of a channel.
435
+
436
+ Arguments:
437
+ id Channel identifier
438
+
439
+ Examples:
440
+ sf channel members el-abc123`,
441
+ handler: channelMembersHandler,
442
+ };
443
+ // ============================================================================
444
+ // Channel Add Command
445
+ // ============================================================================
446
+ async function channelAddHandler(args, options) {
447
+ const [id, entityId] = args;
448
+ if (!id || !entityId) {
449
+ return failure('Usage: sf channel add <channel-id> <entity-id>\nExample: sf channel add el-abc123 el-user456', ExitCode.INVALID_ARGUMENTS);
450
+ }
451
+ const { api, error } = createAPI(options);
452
+ if (error) {
453
+ return failure(error, ExitCode.GENERAL_ERROR);
454
+ }
455
+ try {
456
+ const actor = resolveActor(options);
457
+ const result = await api.addChannelMember(id, entityId, { actor });
458
+ if (result.success) {
459
+ return success(result.channel, `Added ${entityId} to channel ${id}`);
460
+ }
461
+ return failure(`Failed to add member`, ExitCode.GENERAL_ERROR);
462
+ }
463
+ catch (err) {
464
+ // Handle specific error cases with user-friendly messages
465
+ if (err instanceof Error) {
466
+ if (err.message.includes('not found')) {
467
+ return failure(`Channel not found: ${id}`, ExitCode.NOT_FOUND);
468
+ }
469
+ if (err.message.includes('not a channel')) {
470
+ return failure(`Element ${id} is not a channel`, ExitCode.VALIDATION);
471
+ }
472
+ if (err.message.includes('direct channel')) {
473
+ return failure('Cannot modify members of a direct channel', ExitCode.VALIDATION);
474
+ }
475
+ if (err.message.includes('Cannot modify members')) {
476
+ return failure('You do not have permission to add members to this channel', ExitCode.PERMISSION);
477
+ }
478
+ }
479
+ const message = err instanceof Error ? err.message : String(err);
480
+ return failure(`Failed to add member: ${message}`, ExitCode.GENERAL_ERROR);
481
+ }
482
+ }
483
+ const channelAddCommand = {
484
+ name: 'add',
485
+ description: 'Add a member to a channel',
486
+ usage: 'sf channel add <channel-id> <entity-id>',
487
+ help: `Add a member to a group channel.
488
+
489
+ Only group channels support adding members. Direct channels have fixed membership.
490
+ You must have permission to modify members (be in the modifyMembers list).
491
+
492
+ Arguments:
493
+ channel-id Channel identifier
494
+ entity-id Entity to add as member
495
+
496
+ Examples:
497
+ sf channel add el-abc123 el-user456`,
498
+ handler: channelAddHandler,
499
+ };
500
+ // ============================================================================
501
+ // Channel Remove Command
502
+ // ============================================================================
503
+ async function channelRemoveHandler(args, options) {
504
+ const [id, entityId] = args;
505
+ if (!id || !entityId) {
506
+ return failure('Usage: sf channel remove <channel-id> <entity-id>\nExample: sf channel remove el-abc123 el-user456', ExitCode.INVALID_ARGUMENTS);
507
+ }
508
+ const { api, error } = createAPI(options);
509
+ if (error) {
510
+ return failure(error, ExitCode.GENERAL_ERROR);
511
+ }
512
+ try {
513
+ const actor = resolveActor(options);
514
+ const result = await api.removeChannelMember(id, entityId, { actor });
515
+ if (result.success) {
516
+ return success(result.channel, `Removed ${entityId} from channel ${id}`);
517
+ }
518
+ return failure(`Failed to remove member`, ExitCode.GENERAL_ERROR);
519
+ }
520
+ catch (err) {
521
+ // Handle specific error cases with user-friendly messages
522
+ if (err instanceof Error) {
523
+ if (err.message.includes('not found')) {
524
+ return failure(`Channel not found: ${id}`, ExitCode.NOT_FOUND);
525
+ }
526
+ if (err.message.includes('not a channel')) {
527
+ return failure(`Element ${id} is not a channel`, ExitCode.VALIDATION);
528
+ }
529
+ if (err.message.includes('direct channel')) {
530
+ return failure('Cannot modify members of a direct channel', ExitCode.VALIDATION);
531
+ }
532
+ if (err.message.includes('not a member')) {
533
+ return failure(`${entityId} is not a member of this channel`, ExitCode.VALIDATION);
534
+ }
535
+ if (err.message.includes('Cannot modify members')) {
536
+ return failure('You do not have permission to remove members from this channel', ExitCode.PERMISSION);
537
+ }
538
+ }
539
+ const message = err instanceof Error ? err.message : String(err);
540
+ return failure(`Failed to remove member: ${message}`, ExitCode.GENERAL_ERROR);
541
+ }
542
+ }
543
+ const channelRemoveCommand = {
544
+ name: 'remove',
545
+ description: 'Remove a member from a channel',
546
+ usage: 'sf channel remove <channel-id> <entity-id>',
547
+ help: `Remove a member from a group channel.
548
+
549
+ Only group channels support removing members. Direct channels have fixed membership.
550
+ You must have permission to modify members (be in the modifyMembers list).
551
+
552
+ Arguments:
553
+ channel-id Channel identifier
554
+ entity-id Entity to remove
555
+
556
+ Examples:
557
+ sf channel remove el-abc123 el-user456`,
558
+ handler: channelRemoveHandler,
559
+ };
560
+ // ============================================================================
561
+ // Channel Merge Command
562
+ // ============================================================================
563
+ async function channelMergeHandler(args, options) {
564
+ const sourceId = options.source;
565
+ const targetId = options.target;
566
+ const newName = options.name;
567
+ if (!sourceId || !targetId) {
568
+ return failure('Usage: sf channel merge --source <id> --target <id> [--name <new-name>]\nExample: sf channel merge --source el-abc123 --target el-def456', ExitCode.INVALID_ARGUMENTS);
569
+ }
570
+ const { api, error } = createAPI(options);
571
+ if (error) {
572
+ return failure(error, ExitCode.GENERAL_ERROR);
573
+ }
574
+ try {
575
+ const actor = resolveActor(options);
576
+ const result = await api.mergeChannels(sourceId, targetId, { newName, actor });
577
+ return success(result, `Merged channel ${sourceId} into ${targetId} (${result.messagesMoved} messages moved)`);
578
+ }
579
+ catch (err) {
580
+ if (err instanceof Error) {
581
+ if (err.message.includes('not found')) {
582
+ return failure(`Channel not found`, ExitCode.NOT_FOUND);
583
+ }
584
+ if (err.message.includes('not a group')) {
585
+ return failure('Only group channels can be merged', ExitCode.VALIDATION);
586
+ }
587
+ }
588
+ const message = err instanceof Error ? err.message : String(err);
589
+ return failure(`Failed to merge channels: ${message}`, ExitCode.GENERAL_ERROR);
590
+ }
591
+ }
592
+ const channelMergeOptions = [
593
+ { name: 'source', short: 's', hasValue: true, description: 'Source channel ID (will be archived)', required: true },
594
+ { name: 'target', short: 't', hasValue: true, description: 'Target channel ID (will receive messages)', required: true },
595
+ { name: 'name', short: 'n', hasValue: true, description: 'Optional new name for the target channel' },
596
+ ];
597
+ const channelMergeCommand = {
598
+ name: 'merge',
599
+ description: 'Merge two group channels',
600
+ usage: 'sf channel merge --source <id> --target <id> [--name <new-name>]',
601
+ options: channelMergeOptions,
602
+ help: `Merge a source channel into a target channel.
603
+
604
+ All messages from the source channel are moved to the target channel.
605
+ Members from both channels are combined. The source channel is archived.
606
+
607
+ Only group channels can be merged. Direct channels are not supported.
608
+
609
+ Options:
610
+ --source, -s Source channel ID (will be archived after merge)
611
+ --target, -t Target channel ID (will receive all messages and members)
612
+ --name, -n Optional new name for the merged target channel
613
+
614
+ Examples:
615
+ sf channel merge --source el-abc123 --target el-def456
616
+ sf channel merge -s el-abc123 -t el-def456 --name combined-channel`,
617
+ handler: channelMergeHandler,
618
+ };
619
+ // ============================================================================
620
+ // Channel Root Command
621
+ // ============================================================================
622
+ export const channelCommand = {
623
+ name: 'channel',
624
+ description: 'Manage channels (message containers)',
625
+ usage: 'sf channel <subcommand> [options]',
626
+ help: `Manage channels - containers for messages between entities.
627
+
628
+ Channels support both direct messaging (1:1) and group conversations.
629
+ Group channels have configurable visibility and join policies.
630
+
631
+ Subcommands:
632
+ create Create a new channel
633
+ join Join a channel
634
+ leave Leave a channel
635
+ list List channels
636
+ members List channel members
637
+ add Add a member to a channel
638
+ remove Remove a member from a channel
639
+ merge Merge two group channels
640
+
641
+ Examples:
642
+ sf channel create --name general
643
+ sf channel list --member el-user123
644
+ sf channel join el-abc123
645
+ sf channel members el-abc123
646
+ sf channel add el-abc123 el-user456
647
+ sf channel remove el-abc123 el-user456
648
+ sf channel merge --source el-abc123 --target el-def456
649
+
650
+ Note: Use 'sf show <id>', 'sf update <id>', 'sf delete <id>' for any element.`,
651
+ subcommands: {
652
+ create: channelCreateCommand,
653
+ join: channelJoinCommand,
654
+ leave: channelLeaveCommand,
655
+ list: channelListCommand,
656
+ members: channelMembersCommand,
657
+ add: channelAddCommand,
658
+ remove: channelRemoveCommand,
659
+ merge: channelMergeCommand,
660
+ // Aliases (hidden from --help via dedup in getCommandHelp)
661
+ new: channelCreateCommand,
662
+ ls: channelListCommand,
663
+ },
664
+ handler: async (args, options) => {
665
+ // Default to list if no subcommand
666
+ if (args.length === 0) {
667
+ return channelListHandler(args, options);
668
+ }
669
+ // Show "did you mean?" for unknown subcommands
670
+ const subNames = Object.keys(channelCommand.subcommands);
671
+ const suggestions = suggestCommands(args[0], subNames);
672
+ let msg = `Unknown subcommand: ${args[0]}`;
673
+ if (suggestions.length > 0) {
674
+ msg += `\n\nDid you mean?\n${suggestions.map(s => ` ${s}`).join('\n')}`;
675
+ }
676
+ msg += '\n\nRun "sf channel --help" to see available subcommands.';
677
+ return failure(msg, ExitCode.INVALID_ARGUMENTS);
678
+ },
679
+ };
680
+ //# sourceMappingURL=channel.js.map