@cuylabs/channel-slack 0.5.1 → 0.7.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 (66) hide show
  1. package/README.md +25 -136
  2. package/dist/app-home.d.ts +23 -0
  3. package/dist/app-home.js +40 -0
  4. package/dist/artifacts/index.d.ts +135 -0
  5. package/dist/artifacts/index.js +299 -0
  6. package/dist/{assistant.d.ts → assistant/index.d.ts} +1 -1
  7. package/dist/{assistant.js → assistant/index.js} +2 -2
  8. package/dist/auth/index.d.ts +56 -0
  9. package/dist/auth/index.js +168 -0
  10. package/dist/{chunk-IDVDMJ5U.js → chunk-6JSGIVQH.js} +110 -3
  11. package/dist/chunk-6WHFQUYQ.js +54 -0
  12. package/dist/{bolt.js → chunk-73QXT7MA.js} +25 -320
  13. package/dist/{chunk-CMR6B76C.js → chunk-DNVSH7H5.js} +407 -1
  14. package/dist/chunk-IRFKUPJN.js +235 -0
  15. package/dist/chunk-QJYCHWN6.js +76 -0
  16. package/dist/chunk-S3SWPYXJ.js +81 -0
  17. package/dist/{chunk-JZG4IETE.js → chunk-X4WBBBYM.js} +0 -52
  18. package/dist/core.js +5 -3
  19. package/dist/diagnostics/index.d.ts +71 -0
  20. package/dist/{diagnostics.js → diagnostics/index.js} +5 -1
  21. package/dist/entrypoints/index.d.ts +120 -0
  22. package/dist/entrypoints/index.js +132 -0
  23. package/dist/{feedback.js → feedback/index.js} +5 -7
  24. package/dist/{history.d.ts → history/index.d.ts} +2 -2
  25. package/dist/{history.js → history/index.js} +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.js +28 -15
  28. package/dist/{policy.d.ts → policy/index.d.ts} +103 -2
  29. package/dist/{policy.js → policy/index.js} +13 -1
  30. package/dist/runtime-BNBHOZSQ.d.ts +53 -0
  31. package/dist/{setup.d.ts → setup/index.d.ts} +30 -3
  32. package/dist/{setup.js → setup/index.js} +137 -3
  33. package/dist/transports/http/index.d.ts +68 -0
  34. package/dist/transports/http/index.js +8 -0
  35. package/dist/transports/index.d.ts +8 -0
  36. package/dist/transports/index.js +24 -0
  37. package/dist/transports/socket/index.d.ts +94 -0
  38. package/dist/transports/socket/index.js +19 -0
  39. package/dist/types-B9NfCVrk.d.ts +141 -0
  40. package/dist/views/index.d.ts +98 -0
  41. package/dist/views/index.js +22 -0
  42. package/docs/README.md +32 -0
  43. package/docs/concepts/activity.md +3 -3
  44. package/docs/concepts/artifacts.md +56 -0
  45. package/docs/concepts/entrypoints.md +73 -0
  46. package/docs/concepts/setup-requirements.md +23 -0
  47. package/docs/concepts/{bolt-runtime.md → transport-runtime.md} +9 -4
  48. package/docs/concepts/views.md +46 -0
  49. package/docs/recipes/generate-slack-manifest.md +16 -0
  50. package/docs/recipes/publish-artifact.md +45 -0
  51. package/docs/recipes/slash-command-and-shortcut.md +51 -0
  52. package/docs/recipes/socket-mode-app.md +1 -1
  53. package/docs/reference/channel-slack-boundary.md +10 -6
  54. package/docs/reference/exports.md +18 -12
  55. package/docs/reference/source-layout.md +36 -0
  56. package/package.json +68 -39
  57. package/dist/bolt.d.ts +0 -364
  58. package/dist/chunk-NE57BLLU.js +0 -0
  59. package/dist/diagnostics.d.ts +0 -22
  60. package/dist/shared.d.ts +0 -2
  61. package/dist/shared.js +0 -43
  62. /package/dist/{feedback.d.ts → feedback/index.d.ts} +0 -0
  63. /package/dist/{targets.d.ts → targets/index.d.ts} +0 -0
  64. /package/dist/{targets.js → targets/index.js} +0 -0
  65. /package/dist/{users.d.ts → users/index.d.ts} +0 -0
  66. /package/dist/{users.js → users/index.js} +0 -0
package/README.md CHANGED
@@ -1,16 +1,14 @@
1
1
  # @cuylabs/channel-slack
2
2
 
3
- Slack channel primitives for AI agents.
3
+ Agent-runtime-agnostic Slack channel primitives.
4
4
 
5
- This package contains reusable Slack mechanics: activity parsing, message
6
- formatting, message admission policy, supplemental history, visibility filters,
7
- Socket Mode runtime guards, OAuth installation storage, setup inspection, and
8
- Slack API helpers. It intentionally does not create or run an agent.
5
+ This package owns reusable Slack mechanics: event parsing, message admission,
6
+ history loading, formatting, setup inspection, auth helpers, entrypoint
7
+ normalization, artifact publishing, and HTTP or Socket Mode transport helpers.
8
+ It does not create or run an agent, and it does not depend on an agent SDK.
9
9
 
10
- It is not an agent runtime adapter. Use `@cuylabs/channel-slack-agent-core` for
11
- the runtime-specific adapter. See
12
- [Channel Slack Boundary](docs/reference/channel-slack-boundary.md) for the
13
- package boundary.
10
+ Runtime-specific adapters should compose these primitives with their own turn
11
+ types, event streams, tools, prompts, and deployment policy.
14
12
 
15
13
  ## Install
16
14
 
@@ -18,48 +16,18 @@ package boundary.
18
16
  npm install @cuylabs/channel-slack
19
17
  ```
20
18
 
21
- Slack SDK packages are optional peers. Install the peers for the components you
19
+ Slack SDK packages are optional peers. Install the peers for the features you
22
20
  use:
23
21
 
24
22
  ```bash
25
23
  npm install @slack/bolt @slack/web-api @slack/types express
26
24
  ```
27
25
 
28
- Postgres-backed helpers lazy-load `pg` when you pass a connection string. Install
29
- `pg` in applications that use those helpers without injecting their own client
30
- or pool.
26
+ Postgres-backed helpers lazy-load `pg` when you pass a connection string.
27
+ Install `pg` only when your application uses those helpers without injecting its
28
+ own client or pool.
31
29
 
32
- ## Import Map
33
-
34
- Prefer feature-specific imports so applications only couple to the Slack
35
- surface they need.
36
-
37
- | Import | Use for |
38
- | ------------------------------------ | ---------------------------------------------------------------------------------- |
39
- | `@cuylabs/channel-slack/core` | Activity parsing, formatting, sessions, turn context, shared types |
40
- | `@cuylabs/channel-slack/policy` | Message admission, duplicate suppression, mentioned-thread state |
41
- | `@cuylabs/channel-slack/history` | Slack history reading, prompt shaping, supplemental-history visibility |
42
- | `@cuylabs/channel-slack/bolt` | Bolt app factories, auth options, Socket Mode runtime helpers, installation stores |
43
- | `@cuylabs/channel-slack/setup` | Required scopes/events/settings, generated manifests, setup inspection |
44
- | `@cuylabs/channel-slack/diagnostics` | Slack token and scope checks |
45
- | `@cuylabs/channel-slack/users` | User profile lookup and mention enrichment |
46
- | `@cuylabs/channel-slack/targets` | Human-friendly Slack channel/user target parsing and resolution |
47
- | `@cuylabs/channel-slack/feedback` | Feedback Block Kit and action helpers |
48
-
49
- The package root re-exports `core` and `policy` as a lightweight convenience.
50
- Use feature-specific imports for peer-backed helpers such as `bolt`,
51
- `diagnostics`, `setup`, and `users`. `@cuylabs/channel-slack/shared` remains as
52
- an alias of `core`.
53
-
54
- ## Core Flow
55
-
56
- Most Slack agent adapters follow this flow:
57
-
58
- 1. Parse a Slack event into `SlackActivityInfo`.
59
- 2. Resolve whether the message should start or continue an agent turn.
60
- 3. Optionally load model-visible Slack history for the turn.
61
- 4. Run the product-owned agent.
62
- 5. Format the response back to Slack.
30
+ ## Quick Start
63
31
 
64
32
  ```typescript
65
33
  import {
@@ -77,100 +45,21 @@ const policy = createSlackMessagePolicyResolver({
77
45
  const decision = policy.resolve(activity);
78
46
  if (!decision.accepted) return;
79
47
 
80
- const responseText = markdownToSlackMrkdwn("**Ready**");
48
+ const modelInput = decision.text;
49
+ const slackText = markdownToSlackMrkdwn("**Ready**");
81
50
  ```
82
51
 
83
- ## Components
84
-
85
- ### Core
86
-
87
- `core` is transport-neutral. It parses raw Slack message and app mention
88
- payloads, extracts model-facing text from Slack text, Block Kit, rich text, and
89
- attachments, formats Markdown to Slack mrkdwn, derives thread-aware session IDs,
90
- and carries request context.
91
-
92
- See [Activity](docs/concepts/activity.md).
93
-
94
- ### Policy
95
-
96
- `policy` decides which Slack messages an adapter should process. It accepts DMs
97
- and direct mentions by default, can allow passive channel messages by channel or
98
- install scope, tracks mentioned threads, and suppresses duplicate Slack events.
99
- Use `createPostgresSlackMessagePolicyStateStore` when duplicate suppression and
100
- mentioned-thread state must survive restarts or coordinate across workers.
101
-
102
- See [Message Policy](docs/concepts/message-policy.md).
103
-
104
- ### History
105
-
106
- `history` reads Slack thread/channel history, normalizes messages, formats prompt
107
- sections, reports expected Slack history access failures, and filters
108
- supplemental context before it reaches a model.
109
-
110
- See [Supplemental History](docs/concepts/supplemental-history.md).
111
-
112
- ### Bolt
52
+ Most adapters follow the same shape:
113
53
 
114
- `bolt` contains app factories for HTTP and Socket Mode, direct auth resolution,
115
- OAuth installation-store types, development installation stores, and Socket Mode
116
- process/runtime guards. It also exposes a Postgres advisory-lock helper for
117
- distributed Socket Mode single-instance coordination. It does not register agent
118
- handlers.
54
+ 1. Normalize the Slack payload.
55
+ 2. Decide whether it should become a turn.
56
+ 3. Optionally load model-visible Slack context.
57
+ 4. Run the application-owned runtime.
58
+ 5. Format the response for Slack.
119
59
 
120
- See [Bolt Runtime](docs/concepts/bolt-runtime.md).
60
+ ## Documentation
121
61
 
122
- ### Setup
123
-
124
- `setup` turns feature selections into Slack scopes, bot events, settings,
125
- environment variables, and app manifests. It can also inspect a token against the
126
- requirements.
127
-
128
- See [Setup Requirements](docs/concepts/setup-requirements.md).
129
-
130
- ## Recipes
131
-
132
- - [App mention handler](docs/recipes/app-mention-handler.md)
133
- - [Assistant thread handler](docs/recipes/assistant-thread-handler.md)
134
- - [Socket Mode app](docs/recipes/socket-mode-app.md)
135
- - [Generate a Slack manifest](docs/recipes/generate-slack-manifest.md)
136
- - [History visibility filter](docs/recipes/history-visibility.md)
137
-
138
- ## Source Layout
139
-
140
- ```text
141
- src/
142
- core.ts public core entrypoint
143
- shared/ types, parsing, formatting, turn helpers
144
- assistant/ Slack Assistant API helpers
145
- bolt/ Bolt app/auth/runtime helpers
146
- diagnostics/ token and scope inspection
147
- feedback/ feedback blocks and action parsing
148
- history/
149
- context/ turn-history loading component
150
- reader.ts Slack history API reader and prompt formatter
151
- visibility-policy.ts model-visible history filters
152
- inclusion-policy.ts direct-message supplemental-history inclusion policy
153
- policy/
154
- message/ message admission and state-store component
155
- setup/ scopes, events, manifests, setup inspection
156
- targets/ channel/user target parsing and resolution
157
- users/ profile lookup and mention enrichment
158
- ```
159
-
160
- ## Development
161
-
162
- ```bash
163
- pnpm --filter @cuylabs/channel-slack typecheck
164
- pnpm --filter @cuylabs/channel-slack test
165
- pnpm --filter @cuylabs/channel-slack build
166
- ```
167
-
168
- Run workspace checks before publishing changes:
169
-
170
- ```bash
171
- pnpm lint
172
- pnpm typecheck
173
- pnpm build
174
- pnpm test
175
- pnpm format:check
176
- ```
62
+ - [Package boundary](docs/reference/channel-slack-boundary.md)
63
+ - [Exports and peer expectations](docs/reference/exports.md)
64
+ - [Source layout](docs/reference/source-layout.md)
65
+ - [Docs index](docs/README.md)
@@ -0,0 +1,23 @@
1
+ import { App } from '@slack/bolt';
2
+ import { HomeView } from '@slack/types';
3
+ import { L as Logger } from './logging-Bl3HfcC8.js';
4
+
5
+ interface SlackAppHomeOpenedEvent {
6
+ tab?: string;
7
+ user: string;
8
+ [key: string]: unknown;
9
+ }
10
+ interface SlackAppHomeOpenContext {
11
+ event: SlackAppHomeOpenedEvent;
12
+ }
13
+ interface InstallSlackAppHomeOptions {
14
+ boltApp: App;
15
+ buildView(context: SlackAppHomeOpenContext): HomeView | Promise<HomeView>;
16
+ logger?: Logger;
17
+ }
18
+ interface SlackAppHomeInstallation {
19
+ cancelAll(reason?: string): void;
20
+ }
21
+ declare function installSlackAppHome({ boltApp, buildView, logger, }: InstallSlackAppHomeOptions): SlackAppHomeInstallation;
22
+
23
+ export { type InstallSlackAppHomeOptions, type SlackAppHomeInstallation, type SlackAppHomeOpenContext, type SlackAppHomeOpenedEvent, installSlackAppHome };
@@ -0,0 +1,40 @@
1
+ import {
2
+ publishSlackHomeView
3
+ } from "./chunk-IRFKUPJN.js";
4
+
5
+ // src/app-home.ts
6
+ function installSlackAppHome({
7
+ boltApp,
8
+ buildView,
9
+ logger
10
+ }) {
11
+ boltApp.event("app_home_opened", async ({ event, client }) => {
12
+ const homeEvent = event;
13
+ try {
14
+ await publishSlackHomeView({
15
+ client,
16
+ userId: homeEvent.user,
17
+ view: await buildView({ event: homeEvent })
18
+ });
19
+ logger?.debug?.("Slack App Home published", {
20
+ tab: homeEvent.tab,
21
+ userId: homeEvent.user
22
+ });
23
+ } catch (error) {
24
+ logger?.warn?.("Failed to publish Slack App Home", {
25
+ error: formatAppHomeError(error),
26
+ userId: homeEvent.user
27
+ });
28
+ }
29
+ });
30
+ return {
31
+ cancelAll() {
32
+ }
33
+ };
34
+ }
35
+ function formatAppHomeError(error) {
36
+ return error instanceof Error ? error.stack ?? error.message : String(error);
37
+ }
38
+ export {
39
+ installSlackAppHome
40
+ };
@@ -0,0 +1,135 @@
1
+ type SlackArtifactPublishMethod = "message" | "file" | "canvas";
2
+ type SlackArtifactBinaryData = string | Uint8Array | ArrayBuffer;
3
+ interface SlackArtifactBase {
4
+ kind: string;
5
+ title: string;
6
+ summary?: string;
7
+ metadata?: Record<string, unknown>;
8
+ }
9
+ interface SlackTextArtifact extends SlackArtifactBase {
10
+ kind: "text";
11
+ text: string;
12
+ filename?: string;
13
+ mimeType?: string;
14
+ publishAs?: "message" | "file";
15
+ }
16
+ interface SlackFileArtifact extends SlackArtifactBase {
17
+ kind: "file";
18
+ filename: string;
19
+ data?: SlackArtifactBinaryData;
20
+ filePath?: string;
21
+ mimeType?: string;
22
+ initialComment?: string;
23
+ }
24
+ interface SlackImageArtifact extends SlackArtifactBase {
25
+ kind: "image";
26
+ filename: string;
27
+ altText: string;
28
+ data?: SlackArtifactBinaryData;
29
+ filePath?: string;
30
+ initialComment?: string;
31
+ }
32
+ interface SlackLinkArtifact extends SlackArtifactBase {
33
+ kind: "link";
34
+ url: string;
35
+ }
36
+ interface SlackCanvasArtifact extends SlackArtifactBase {
37
+ kind: "canvas";
38
+ markdown: string;
39
+ /**
40
+ * When set, updates an existing canvas instead of creating one.
41
+ */
42
+ canvasId?: string;
43
+ /**
44
+ * Create a channel canvas when a channel is available.
45
+ *
46
+ * @default true
47
+ */
48
+ channelCanvas?: boolean;
49
+ }
50
+ type SlackArtifact = SlackTextArtifact | SlackFileArtifact | SlackImageArtifact | SlackLinkArtifact | SlackCanvasArtifact;
51
+ interface SlackArtifactPostMessageResponse {
52
+ ok?: boolean;
53
+ channel?: string;
54
+ ts?: string;
55
+ [key: string]: unknown;
56
+ }
57
+ interface SlackArtifactFileUploadResponse {
58
+ ok?: boolean;
59
+ file?: {
60
+ id?: string;
61
+ [key: string]: unknown;
62
+ };
63
+ files?: Array<{
64
+ id?: string;
65
+ [key: string]: unknown;
66
+ }>;
67
+ [key: string]: unknown;
68
+ }
69
+ interface SlackArtifactCanvasResponse {
70
+ ok?: boolean;
71
+ canvas_id?: string;
72
+ [key: string]: unknown;
73
+ }
74
+ interface SlackArtifactClient {
75
+ chat?: {
76
+ postMessage(args: Record<string, unknown>): Promise<SlackArtifactPostMessageResponse>;
77
+ };
78
+ files?: {
79
+ uploadV2(args: Record<string, unknown>): Promise<SlackArtifactFileUploadResponse>;
80
+ };
81
+ canvases?: {
82
+ create(args?: Record<string, unknown>): Promise<SlackArtifactCanvasResponse>;
83
+ edit?(args: Record<string, unknown>): Promise<SlackArtifactCanvasResponse>;
84
+ };
85
+ conversations?: {
86
+ canvases?: {
87
+ create(args: Record<string, unknown>): Promise<SlackArtifactCanvasResponse>;
88
+ };
89
+ };
90
+ }
91
+ interface PublishSlackArtifactOptions {
92
+ client: SlackArtifactClient;
93
+ artifact: SlackArtifact;
94
+ channelId?: string;
95
+ threadTs?: string;
96
+ token?: string;
97
+ unfurlLinks?: boolean;
98
+ unfurlMedia?: boolean;
99
+ }
100
+ interface SlackArtifactPublication {
101
+ artifact: SlackArtifact;
102
+ method: SlackArtifactPublishMethod;
103
+ response: unknown;
104
+ channelId?: string;
105
+ threadTs?: string;
106
+ messageTs?: string;
107
+ fileId?: string;
108
+ canvasId?: string;
109
+ }
110
+
111
+ interface SlackArtifactBlockKitMessage {
112
+ text: string;
113
+ blocks: Array<Record<string, unknown>>;
114
+ }
115
+ declare function createSlackArtifactBlocks(artifact: SlackArtifact): SlackArtifactBlockKitMessage;
116
+ declare function createSlackLinkArtifactBlocks(artifact: SlackLinkArtifact): SlackArtifactBlockKitMessage;
117
+
118
+ declare function publishSlackArtifact(options: PublishSlackArtifactOptions): Promise<SlackArtifactPublication>;
119
+ declare function publishSlackTextArtifact(options: PublishSlackArtifactOptions & {
120
+ artifact: SlackTextArtifact;
121
+ }): Promise<SlackArtifactPublication>;
122
+ declare function publishSlackFileArtifact(options: PublishSlackArtifactOptions & {
123
+ artifact: SlackFileArtifact;
124
+ }): Promise<SlackArtifactPublication>;
125
+ declare function publishSlackImageArtifact(options: PublishSlackArtifactOptions & {
126
+ artifact: SlackImageArtifact;
127
+ }): Promise<SlackArtifactPublication>;
128
+ declare function publishSlackLinkArtifact(options: PublishSlackArtifactOptions & {
129
+ artifact: SlackLinkArtifact;
130
+ }): Promise<SlackArtifactPublication>;
131
+ declare function publishSlackCanvasArtifact(options: PublishSlackArtifactOptions & {
132
+ artifact: SlackCanvasArtifact;
133
+ }): Promise<SlackArtifactPublication>;
134
+
135
+ export { type PublishSlackArtifactOptions, type SlackArtifact, type SlackArtifactBase, type SlackArtifactBinaryData, type SlackArtifactBlockKitMessage, type SlackArtifactCanvasResponse, type SlackArtifactClient, type SlackArtifactFileUploadResponse, type SlackArtifactPostMessageResponse, type SlackArtifactPublication, type SlackArtifactPublishMethod, type SlackCanvasArtifact, type SlackFileArtifact, type SlackImageArtifact, type SlackLinkArtifact, type SlackTextArtifact, createSlackArtifactBlocks, createSlackLinkArtifactBlocks, publishSlackArtifact, publishSlackCanvasArtifact, publishSlackFileArtifact, publishSlackImageArtifact, publishSlackLinkArtifact, publishSlackTextArtifact };
@@ -0,0 +1,299 @@
1
+ import {
2
+ markdownToSlackMrkdwn
3
+ } from "../chunk-6WHFQUYQ.js";
4
+
5
+ // src/artifacts/blocks.ts
6
+ function createSlackArtifactBlocks(artifact) {
7
+ switch (artifact.kind) {
8
+ case "link":
9
+ return createSlackLinkArtifactBlocks(artifact);
10
+ case "canvas":
11
+ return createGenericArtifactBlocks({
12
+ title: artifact.title,
13
+ summary: artifact.summary ?? "Canvas created."
14
+ });
15
+ case "text":
16
+ case "file":
17
+ case "image":
18
+ return createGenericArtifactBlocks({
19
+ title: artifact.title,
20
+ summary: artifact.summary
21
+ });
22
+ }
23
+ }
24
+ function createSlackLinkArtifactBlocks(artifact) {
25
+ const title = normalizeText(artifact.title);
26
+ const summary = normalizeText(artifact.summary);
27
+ const link = `<${escapeSlackLinkUrl(artifact.url)}|Open link>`;
28
+ const body = [summary ? markdownToSlackMrkdwn(summary) : void 0, link].filter(Boolean).join("\n");
29
+ return {
30
+ text: [title, artifact.url].filter(Boolean).join(": "),
31
+ blocks: [
32
+ {
33
+ type: "section",
34
+ text: {
35
+ type: "mrkdwn",
36
+ text: [`*${title}*`, body].filter(Boolean).join("\n")
37
+ }
38
+ }
39
+ ]
40
+ };
41
+ }
42
+ function createGenericArtifactBlocks({
43
+ title,
44
+ summary
45
+ }) {
46
+ const normalizedTitle = normalizeText(title);
47
+ const normalizedSummary = normalizeText(summary);
48
+ return {
49
+ text: normalizedSummary ? `${normalizedTitle}: ${normalizedSummary}` : normalizedTitle,
50
+ blocks: [
51
+ {
52
+ type: "section",
53
+ text: {
54
+ type: "mrkdwn",
55
+ text: [
56
+ `*${normalizedTitle}*`,
57
+ markdownToSlackMrkdwn(normalizedSummary)
58
+ ].filter(Boolean).join("\n")
59
+ }
60
+ }
61
+ ]
62
+ };
63
+ }
64
+ function normalizeText(value) {
65
+ return value?.trim() || "Untitled artifact";
66
+ }
67
+ function escapeSlackLinkUrl(url) {
68
+ return url.trim().replace(/[>|]/g, encodeURIComponent);
69
+ }
70
+
71
+ // src/artifacts/publish.ts
72
+ async function publishSlackArtifact(options) {
73
+ switch (options.artifact.kind) {
74
+ case "link":
75
+ return publishSlackLinkArtifact({
76
+ ...options,
77
+ artifact: options.artifact
78
+ });
79
+ case "text":
80
+ return publishSlackTextArtifact({
81
+ ...options,
82
+ artifact: options.artifact
83
+ });
84
+ case "file":
85
+ return publishSlackFileArtifact({
86
+ ...options,
87
+ artifact: options.artifact
88
+ });
89
+ case "image":
90
+ return publishSlackImageArtifact({
91
+ ...options,
92
+ artifact: options.artifact
93
+ });
94
+ case "canvas":
95
+ return publishSlackCanvasArtifact({
96
+ ...options,
97
+ artifact: options.artifact
98
+ });
99
+ }
100
+ }
101
+ async function publishSlackTextArtifact(options) {
102
+ if (options.artifact.publishAs === "message") {
103
+ return publishArtifactMessage(
104
+ options,
105
+ createSlackArtifactBlocks({
106
+ ...options.artifact,
107
+ summary: options.artifact.summary ?? options.artifact.text
108
+ })
109
+ );
110
+ }
111
+ return uploadArtifactFile(options, {
112
+ filename: options.artifact.filename ?? filenameFromTitle(options.artifact.title, "txt"),
113
+ title: options.artifact.title,
114
+ content: options.artifact.text,
115
+ initialComment: options.artifact.summary
116
+ });
117
+ }
118
+ async function publishSlackFileArtifact(options) {
119
+ return uploadArtifactFile(options, {
120
+ filename: options.artifact.filename,
121
+ title: options.artifact.title,
122
+ data: options.artifact.data,
123
+ filePath: options.artifact.filePath,
124
+ initialComment: options.artifact.initialComment ?? options.artifact.summary
125
+ });
126
+ }
127
+ async function publishSlackImageArtifact(options) {
128
+ return uploadArtifactFile(options, {
129
+ filename: options.artifact.filename,
130
+ title: options.artifact.title,
131
+ data: options.artifact.data,
132
+ filePath: options.artifact.filePath,
133
+ initialComment: options.artifact.initialComment ?? options.artifact.summary,
134
+ altText: options.artifact.altText
135
+ });
136
+ }
137
+ async function publishSlackLinkArtifact(options) {
138
+ return publishArtifactMessage(
139
+ options,
140
+ createSlackArtifactBlocks(options.artifact)
141
+ );
142
+ }
143
+ async function publishSlackCanvasArtifact(options) {
144
+ const documentContent = {
145
+ type: "markdown",
146
+ markdown: options.artifact.markdown
147
+ };
148
+ const tokenArgs = options.token ? { token: options.token } : {};
149
+ let response;
150
+ if (options.artifact.canvasId) {
151
+ const edit = options.client.canvases?.edit;
152
+ if (typeof edit !== "function") {
153
+ throw new Error("Slack client does not expose canvases.edit.");
154
+ }
155
+ response = await edit({
156
+ ...tokenArgs,
157
+ canvas_id: options.artifact.canvasId,
158
+ changes: [
159
+ {
160
+ operation: "replace",
161
+ document_content: documentContent
162
+ }
163
+ ]
164
+ });
165
+ } else if (options.channelId && options.artifact.channelCanvas !== false && typeof options.client.conversations?.canvases?.create === "function") {
166
+ response = await options.client.conversations.canvases.create({
167
+ ...tokenArgs,
168
+ channel_id: options.channelId,
169
+ title: options.artifact.title,
170
+ document_content: documentContent
171
+ });
172
+ } else {
173
+ const create = options.client.canvases?.create;
174
+ if (typeof create !== "function") {
175
+ throw new Error(
176
+ "Slack client does not expose canvases.create or conversations.canvases.create."
177
+ );
178
+ }
179
+ response = await create({
180
+ ...tokenArgs,
181
+ ...options.channelId && options.artifact.channelCanvas !== false ? { channel_id: options.channelId } : {},
182
+ title: options.artifact.title,
183
+ document_content: documentContent
184
+ });
185
+ }
186
+ return {
187
+ artifact: options.artifact,
188
+ method: "canvas",
189
+ response,
190
+ ...options.channelId ? { channelId: options.channelId } : {},
191
+ ...options.threadTs ? { threadTs: options.threadTs } : {},
192
+ ...readString(response.canvas_id) ?? options.artifact.canvasId ? {
193
+ canvasId: readString(response.canvas_id) ?? options.artifact.canvasId
194
+ } : {}
195
+ };
196
+ }
197
+ async function publishArtifactMessage(options, message) {
198
+ const channelId = requireChannelId(options.channelId, options.artifact.kind);
199
+ const postMessage = options.client.chat?.postMessage;
200
+ if (typeof postMessage !== "function") {
201
+ throw new Error("Slack client does not expose chat.postMessage.");
202
+ }
203
+ const response = await postMessage({
204
+ ...options.token ? { token: options.token } : {},
205
+ channel: channelId,
206
+ text: message.text,
207
+ blocks: message.blocks,
208
+ ...options.threadTs ? { thread_ts: options.threadTs } : {},
209
+ ...options.unfurlLinks !== void 0 ? { unfurl_links: options.unfurlLinks } : {},
210
+ ...options.unfurlMedia !== void 0 ? { unfurl_media: options.unfurlMedia } : {}
211
+ });
212
+ return {
213
+ artifact: options.artifact,
214
+ method: "message",
215
+ response,
216
+ channelId,
217
+ ...options.threadTs ? { threadTs: options.threadTs } : {},
218
+ ...readString(response.ts) ? { messageTs: readString(response.ts) } : {}
219
+ };
220
+ }
221
+ async function uploadArtifactFile(options, file) {
222
+ const channelId = requireChannelId(options.channelId, options.artifact.kind);
223
+ const uploadV2 = options.client.files?.uploadV2;
224
+ if (typeof uploadV2 !== "function") {
225
+ throw new Error("Slack client does not expose files.uploadV2.");
226
+ }
227
+ const uploadArgs = {
228
+ ...options.token ? { token: options.token } : {},
229
+ channel_id: channelId,
230
+ ...options.threadTs ? { thread_ts: options.threadTs } : {},
231
+ filename: requireNonEmpty(file.filename, "artifact filename"),
232
+ title: requireNonEmpty(file.title, "artifact title"),
233
+ ...file.initialComment ? { initial_comment: file.initialComment } : {},
234
+ ...file.altText ? { alt_text: file.altText } : {},
235
+ ...resolveFilePayload(file)
236
+ };
237
+ const response = await uploadV2(uploadArgs);
238
+ return {
239
+ artifact: options.artifact,
240
+ method: "file",
241
+ response,
242
+ channelId,
243
+ ...options.threadTs ? { threadTs: options.threadTs } : {},
244
+ ...readUploadedFileId(response) ? { fileId: readUploadedFileId(response) } : {}
245
+ };
246
+ }
247
+ function resolveFilePayload(file) {
248
+ if (file.content !== void 0) {
249
+ return { content: file.content };
250
+ }
251
+ if (file.filePath) {
252
+ return { file: file.filePath };
253
+ }
254
+ if (file.data !== void 0) {
255
+ return typeof file.data === "string" ? { content: file.data } : { file: toBuffer(file.data) };
256
+ }
257
+ throw new Error(
258
+ "Slack file artifact requires `data`, `filePath`, or `content`."
259
+ );
260
+ }
261
+ function toBuffer(data) {
262
+ return data instanceof ArrayBuffer ? Buffer.from(new Uint8Array(data)) : Buffer.from(data);
263
+ }
264
+ function requireChannelId(channelId, artifactKind) {
265
+ const trimmed = channelId?.trim();
266
+ if (!trimmed) {
267
+ throw new Error(
268
+ `Slack ${artifactKind} artifact publication requires a channelId.`
269
+ );
270
+ }
271
+ return trimmed;
272
+ }
273
+ function requireNonEmpty(value, label) {
274
+ const trimmed = value.trim();
275
+ if (!trimmed) {
276
+ throw new Error(`Slack ${label} must not be empty.`);
277
+ }
278
+ return trimmed;
279
+ }
280
+ function filenameFromTitle(title, extension) {
281
+ const slug = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
282
+ return `${slug || "artifact"}.${extension}`;
283
+ }
284
+ function readUploadedFileId(response) {
285
+ return readString(response.file?.id) ?? readString(response.files?.[0]?.id);
286
+ }
287
+ function readString(value) {
288
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
289
+ }
290
+ export {
291
+ createSlackArtifactBlocks,
292
+ createSlackLinkArtifactBlocks,
293
+ publishSlackArtifact,
294
+ publishSlackCanvasArtifact,
295
+ publishSlackFileArtifact,
296
+ publishSlackImageArtifact,
297
+ publishSlackLinkArtifact,
298
+ publishSlackTextArtifact
299
+ };
@@ -1,4 +1,4 @@
1
- import { S as SlackActivityInfo } from './activity-ByrD9Ftr.js';
1
+ import { S as SlackActivityInfo } from '../activity-ByrD9Ftr.js';
2
2
 
3
3
  /**
4
4
  * Per-thread Assistant context store.