@cuylabs/channel-slack 0.7.0 → 0.8.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.
@@ -0,0 +1,175 @@
1
+ // src/turn-controls/block.ts
2
+ var SLACK_TURN_CANCEL_ACTION_ID = "agent_turn_cancel";
3
+ function createSlackTurnCancelMessage(options) {
4
+ const actionId = resolveSlackTurnCancelActionId(options.actionId);
5
+ const controlId = options.controlId.trim();
6
+ if (!controlId) {
7
+ throw new Error(
8
+ "createSlackTurnCancelMessage: controlId must be a non-empty string"
9
+ );
10
+ }
11
+ const text = (options.messageText ?? "Request controls").trim();
12
+ if (!text) {
13
+ throw new Error(
14
+ "createSlackTurnCancelMessage: messageText must be a non-empty string"
15
+ );
16
+ }
17
+ const buttonText = (options.buttonText ?? "Cancel").trim();
18
+ if (!buttonText) {
19
+ throw new Error(
20
+ "createSlackTurnCancelMessage: buttonText must be a non-empty string"
21
+ );
22
+ }
23
+ const value = encodeSlackTurnCancelButtonValue({
24
+ action: "cancel",
25
+ controlId,
26
+ ...options.sessionId ? { sessionId: options.sessionId } : {},
27
+ ...options.turnId ? { turnId: options.turnId } : {}
28
+ });
29
+ return {
30
+ text,
31
+ blocks: [
32
+ {
33
+ type: "section",
34
+ text: { type: "mrkdwn", text }
35
+ },
36
+ {
37
+ type: "actions",
38
+ elements: [
39
+ {
40
+ type: "button",
41
+ action_id: actionId,
42
+ text: { type: "plain_text", text: buttonText },
43
+ accessibility_label: buttonText,
44
+ style: "danger",
45
+ value
46
+ }
47
+ ]
48
+ }
49
+ ]
50
+ };
51
+ }
52
+ function encodeSlackTurnCancelButtonValue(value) {
53
+ return JSON.stringify(value);
54
+ }
55
+ function decodeSlackTurnCancelButtonValue(rawValue) {
56
+ if (typeof rawValue !== "string" || !rawValue.trim()) {
57
+ return void 0;
58
+ }
59
+ try {
60
+ const parsed = JSON.parse(rawValue);
61
+ const controlId = parseOptionalString(parsed.controlId);
62
+ if (parsed.action !== "cancel" || !controlId) {
63
+ return void 0;
64
+ }
65
+ const sessionId = parseOptionalString(parsed.sessionId);
66
+ const turnId = parseOptionalString(parsed.turnId);
67
+ return {
68
+ action: "cancel",
69
+ controlId,
70
+ ...sessionId ? { sessionId } : {},
71
+ ...turnId ? { turnId } : {}
72
+ };
73
+ } catch {
74
+ return void 0;
75
+ }
76
+ }
77
+ function parseOptionalString(value) {
78
+ if (typeof value !== "string") {
79
+ return void 0;
80
+ }
81
+ const trimmed = value.trim();
82
+ return trimmed || void 0;
83
+ }
84
+ function resolveSlackTurnCancelActionId(actionId) {
85
+ const resolved = (actionId ?? SLACK_TURN_CANCEL_ACTION_ID).trim();
86
+ if (!resolved) {
87
+ throw new Error("Slack turn cancel action id cannot be empty.");
88
+ }
89
+ return resolved;
90
+ }
91
+
92
+ // src/turn-controls/action.ts
93
+ function registerSlackTurnCancelAction(app, options) {
94
+ const actionId = resolveSlackTurnCancelActionId(options.actionId);
95
+ app.action(
96
+ actionId,
97
+ // Bolt's action args are structurally stable, but not exported as one
98
+ // concise public type across all action element variants.
99
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
+ async ({ ack, body, client, logger }) => {
101
+ try {
102
+ const ackFn = ack;
103
+ await ackFn();
104
+ if (body?.type !== "block_actions" || !Array.isArray(body.actions) || body.actions.length === 0) {
105
+ return;
106
+ }
107
+ const action = body.actions[0];
108
+ if (action?.type !== "button") {
109
+ return;
110
+ }
111
+ const value = decodeSlackTurnCancelButtonValue(action.value);
112
+ if (!value) {
113
+ return;
114
+ }
115
+ const channelId = body.channel?.id ?? body.container?.channel_id;
116
+ const userId = body.user?.id;
117
+ const messageTs = body.message?.ts ?? body.container?.message_ts;
118
+ const threadTs = body.message?.thread_ts ?? body.container?.thread_ts;
119
+ const teamId = body.team?.id;
120
+ const triggerId = typeof body.trigger_id === "string" ? body.trigger_id : void 0;
121
+ if (!channelId || !userId || !messageTs) {
122
+ return;
123
+ }
124
+ const acknowledgeEphemeral = async (text) => {
125
+ await client.chat.postEphemeral({
126
+ channel: channelId,
127
+ user: userId,
128
+ ...threadTs ? { thread_ts: threadTs } : { thread_ts: messageTs },
129
+ text
130
+ });
131
+ };
132
+ const deleteMessage = async () => {
133
+ await client.chat.delete({
134
+ channel: channelId,
135
+ ts: messageTs
136
+ });
137
+ };
138
+ const updateMessage = async (message) => {
139
+ await client.chat.update({
140
+ channel: channelId,
141
+ ts: messageTs,
142
+ text: message.text,
143
+ ...message.blocks ? { blocks: message.blocks } : {}
144
+ });
145
+ };
146
+ await options.onCancel({
147
+ ...value,
148
+ channelId,
149
+ userId,
150
+ messageTs,
151
+ ...threadTs ? { threadTs } : {},
152
+ ...teamId ? { teamId } : {},
153
+ ...triggerId ? { triggerId } : {},
154
+ acknowledgeEphemeral,
155
+ deleteMessage,
156
+ updateMessage
157
+ });
158
+ } catch (error) {
159
+ logger?.error?.(
160
+ `[channel-slack] turn cancel action failed: ${error instanceof Error ? error.message : String(error)}`
161
+ );
162
+ }
163
+ }
164
+ );
165
+ return { actionId };
166
+ }
167
+
168
+ export {
169
+ SLACK_TURN_CANCEL_ACTION_ID,
170
+ createSlackTurnCancelMessage,
171
+ encodeSlackTurnCancelButtonValue,
172
+ decodeSlackTurnCancelButtonValue,
173
+ resolveSlackTurnCancelActionId,
174
+ registerSlackTurnCancelAction
175
+ };
package/dist/core.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  import { S as SlackActivityInfo, b as SlackUserIdentity, a as SlackChannelType } from './activity-ByrD9Ftr.js';
2
+ export { RegisterSlackTurnCancelActionOptions, SLACK_TURN_CANCEL_ACTION_ID, SlackTurnCancelActionContext, SlackTurnCancelActionHandler, SlackTurnCancelButtonValue, SlackTurnCancelMessage, SlackTurnCancelMessageOptions, createSlackTurnCancelMessage, decodeSlackTurnCancelButtonValue, encodeSlackTurnCancelButtonValue, registerSlackTurnCancelAction, resolveSlackTurnCancelActionId } from './turn-controls/index.js';
3
+ import '@slack/types';
4
+ import '@slack/bolt';
2
5
 
3
6
  /**
4
7
  * Slack auth context — credentials and identifiers resolved from the inbound
package/dist/core.js CHANGED
@@ -3,7 +3,15 @@ import {
3
3
  formatSlackAttributedFollowUp,
4
4
  resolveThreadAwareSlackSessionId,
5
5
  runWithSlackTurnContext
6
- } from "./chunk-X4WBBBYM.js";
6
+ } from "./chunk-ISOMBQXE.js";
7
+ import {
8
+ SLACK_TURN_CANCEL_ACTION_ID,
9
+ createSlackTurnCancelMessage,
10
+ decodeSlackTurnCancelButtonValue,
11
+ encodeSlackTurnCancelButtonValue,
12
+ registerSlackTurnCancelAction,
13
+ resolveSlackTurnCancelActionId
14
+ } from "./chunk-3KP3CBCC.js";
7
15
  import {
8
16
  markdownToSlackMrkdwn,
9
17
  resolveSlackMessageFormatter
@@ -24,7 +32,11 @@ import {
24
32
  stripLeadingMentions
25
33
  } from "./chunk-FPCE5V5Y.js";
26
34
  export {
35
+ SLACK_TURN_CANCEL_ACTION_ID,
36
+ createSlackTurnCancelMessage,
27
37
  currentSlackTurnContext,
38
+ decodeSlackTurnCancelButtonValue,
39
+ encodeSlackTurnCancelButtonValue,
28
40
  extractSlackActionToken,
29
41
  extractSlackAttachmentsText,
30
42
  extractSlackAuthContext,
@@ -36,8 +48,10 @@ export {
36
48
  markdownToSlackMrkdwn,
37
49
  parseSlackMentionActivity,
38
50
  parseSlackMessageActivity,
51
+ registerSlackTurnCancelAction,
39
52
  resolveSlackChannelType,
40
53
  resolveSlackMessageFormatter,
54
+ resolveSlackTurnCancelActionId,
41
55
  resolveThreadAwareSlackSessionId,
42
56
  runWithSlackTurnContext,
43
57
  stripLeadingMentions
package/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  export { S as SlackActivityInfo, a as SlackChannelType, b as SlackUserIdentity } from './activity-ByrD9Ftr.js';
2
2
  export { ExtractSlackMessageTextOptions, RawSlackActionTokenPayload, RawSlackAppMentionPayload, RawSlackAssistantThreadPayload, RawSlackMessagePayload, SlackAmbientTurnContext, SlackApprovalRequest, SlackAssistantStatusUpdate, SlackAssistantSuggestedPrompt, SlackAssistantSuggestedPrompts, SlackAssistantTaskDisplayMode, SlackAssistantThreadContext, SlackAssistantUtilities, SlackAuthContext, SlackChatStreamStartArgs, SlackEventInteractiveRequestHandler, SlackHumanInputRequest, SlackInteractiveMessage, SlackInteractiveMessageRef, SlackInteractiveRequest, SlackInteractiveRequestBaseContext, SlackInteractiveRequestContext, SlackInteractiveRequestHandler, SlackInteractiveRequestKind, SlackInteractiveResponder, SlackMessageAuthorshipOptions, SlackMessageFormatter, SlackMessageFormattingOptions, SlackMessageTextPayload, SlackThreadStatusSetter, SlackTurnPreparation, SlackTurnRequestContext, currentSlackTurnContext, extractSlackActionToken, extractSlackAttachmentsText, extractSlackAuthContext, extractSlackBlocksText, extractSlackMessageText, extractSlackUserIdentity, formatSlackAttributedFollowUp, isProcessableMessage, markdownToSlackMrkdwn, parseSlackMentionActivity, parseSlackMessageActivity, resolveSlackChannelType, resolveSlackMessageFormatter, resolveThreadAwareSlackSessionId, runWithSlackTurnContext, stripLeadingMentions } from './core.js';
3
+ export { RegisterSlackTurnCancelActionOptions, SLACK_TURN_CANCEL_ACTION_ID, SlackTurnCancelActionContext, SlackTurnCancelActionHandler, SlackTurnCancelButtonValue, SlackTurnCancelMessage, SlackTurnCancelMessageOptions, createSlackTurnCancelMessage, decodeSlackTurnCancelButtonValue, encodeSlackTurnCancelButtonValue, registerSlackTurnCancelAction, resolveSlackTurnCancelActionId } from './turn-controls/index.js';
3
4
  export { InMemorySlackThreadParticipationStateStoreOptions, PostgresSlackMessagePolicyPruneResult, PostgresSlackMessagePolicyStateStore, PostgresSlackMessagePolicyStateStoreOptions, PostgresSlackThreadParticipationStateStore, PostgresSlackThreadParticipationStateStoreOptions, SlackAsyncMessagePolicyConfig, SlackAsyncMessagePolicyResolver, SlackChannelMessagePolicy, SlackMentionedThreadState, SlackMessagePolicyAcceptReason, SlackMessagePolicyAcceptedDecision, SlackMessagePolicyConfig, SlackMessagePolicyDecision, SlackMessagePolicyPostgresClient, SlackMessagePolicyRejectReason, SlackMessagePolicyRejectedDecision, SlackMessagePolicyResolver, SlackMessagePolicyStateContext, SlackMessagePolicyStateStore, SlackQuietThreadRejectedDecision, SlackSyncMessagePolicyStateStore, SlackThreadAwareMessagePolicyConfig, SlackThreadAwareMessagePolicyDecision, SlackThreadAwareMessagePolicyResolver, SlackThreadParticipationEligibility, SlackThreadParticipationEligibilityOptions, SlackThreadParticipationMode, SlackThreadParticipationPostgresClient, SlackThreadParticipationPruneResult, SlackThreadParticipationReactivation, SlackThreadParticipationState, SlackThreadParticipationStateContext, SlackThreadParticipationStateStore, SlackThreadReplyPolicy, createAsyncSlackMessagePolicyResolver, createAsyncSlackThreadAwareMessagePolicyResolver, createInMemorySlackMessagePolicyStateStore, createInMemorySlackThreadParticipationStateStore, createPostgresSlackMessagePolicyStateStore, createPostgresSlackThreadParticipationStateStore, createSlackMessagePolicyMessageKey, createSlackMessagePolicyResolver, createSlackMessagePolicyThreadKey, initializePostgresSlackMessagePolicyState, initializePostgresSlackThreadParticipationState, prunePostgresSlackMessagePolicyState, prunePostgresSlackThreadParticipationState, resolveSlackThreadParticipationEligibility, shouldRegisterSlackPassiveChannelMessages } from './policy/index.js';
4
5
  export { L as Logger } from './logging-Bl3HfcC8.js';
6
+ import '@slack/types';
7
+ import '@slack/bolt';
package/dist/index.js CHANGED
@@ -20,7 +20,15 @@ import {
20
20
  formatSlackAttributedFollowUp,
21
21
  resolveThreadAwareSlackSessionId,
22
22
  runWithSlackTurnContext
23
- } from "./chunk-X4WBBBYM.js";
23
+ } from "./chunk-ISOMBQXE.js";
24
+ import {
25
+ SLACK_TURN_CANCEL_ACTION_ID,
26
+ createSlackTurnCancelMessage,
27
+ decodeSlackTurnCancelButtonValue,
28
+ encodeSlackTurnCancelButtonValue,
29
+ registerSlackTurnCancelAction,
30
+ resolveSlackTurnCancelActionId
31
+ } from "./chunk-3KP3CBCC.js";
24
32
  import {
25
33
  markdownToSlackMrkdwn,
26
34
  resolveSlackMessageFormatter
@@ -41,6 +49,7 @@ import {
41
49
  stripLeadingMentions
42
50
  } from "./chunk-FPCE5V5Y.js";
43
51
  export {
52
+ SLACK_TURN_CANCEL_ACTION_ID,
44
53
  createAsyncSlackMessagePolicyResolver,
45
54
  createAsyncSlackThreadAwareMessagePolicyResolver,
46
55
  createInMemorySlackMessagePolicyStateStore,
@@ -50,7 +59,10 @@ export {
50
59
  createSlackMessagePolicyMessageKey,
51
60
  createSlackMessagePolicyResolver,
52
61
  createSlackMessagePolicyThreadKey,
62
+ createSlackTurnCancelMessage,
53
63
  currentSlackTurnContext,
64
+ decodeSlackTurnCancelButtonValue,
65
+ encodeSlackTurnCancelButtonValue,
54
66
  extractSlackActionToken,
55
67
  extractSlackAttachmentsText,
56
68
  extractSlackAuthContext,
@@ -66,9 +78,11 @@ export {
66
78
  parseSlackMessageActivity,
67
79
  prunePostgresSlackMessagePolicyState,
68
80
  prunePostgresSlackThreadParticipationState,
81
+ registerSlackTurnCancelAction,
69
82
  resolveSlackChannelType,
70
83
  resolveSlackMessageFormatter,
71
84
  resolveSlackThreadParticipationEligibility,
85
+ resolveSlackTurnCancelActionId,
72
86
  resolveThreadAwareSlackSessionId,
73
87
  runWithSlackTurnContext,
74
88
  shouldRegisterSlackPassiveChannelMessages,
@@ -0,0 +1,51 @@
1
+ import { SectionBlock, ActionsBlock, KnownBlock } from '@slack/types';
2
+ import { App } from '@slack/bolt';
3
+
4
+ declare const SLACK_TURN_CANCEL_ACTION_ID = "agent_turn_cancel";
5
+ interface SlackTurnCancelButtonValue {
6
+ action: "cancel";
7
+ controlId: string;
8
+ sessionId?: string;
9
+ turnId?: string;
10
+ }
11
+ interface SlackTurnCancelMessageOptions {
12
+ controlId: string;
13
+ actionId?: string;
14
+ buttonText?: string;
15
+ messageText?: string;
16
+ sessionId?: string;
17
+ turnId?: string;
18
+ }
19
+ interface SlackTurnCancelMessage {
20
+ text: string;
21
+ blocks: [SectionBlock, ActionsBlock];
22
+ }
23
+ declare function createSlackTurnCancelMessage(options: SlackTurnCancelMessageOptions): SlackTurnCancelMessage;
24
+ declare function encodeSlackTurnCancelButtonValue(value: SlackTurnCancelButtonValue): string;
25
+ declare function decodeSlackTurnCancelButtonValue(rawValue: unknown): SlackTurnCancelButtonValue | undefined;
26
+ declare function resolveSlackTurnCancelActionId(actionId?: string): string;
27
+
28
+ interface SlackTurnCancelActionContext extends SlackTurnCancelButtonValue {
29
+ channelId: string;
30
+ userId: string;
31
+ messageTs: string;
32
+ threadTs?: string;
33
+ teamId?: string;
34
+ triggerId?: string;
35
+ acknowledgeEphemeral: (text: string) => Promise<void>;
36
+ deleteMessage: () => Promise<void>;
37
+ updateMessage: (message: {
38
+ text: string;
39
+ blocks?: KnownBlock[];
40
+ }) => Promise<void>;
41
+ }
42
+ type SlackTurnCancelActionHandler = (context: SlackTurnCancelActionContext) => void | Promise<void>;
43
+ interface RegisterSlackTurnCancelActionOptions {
44
+ actionId?: string;
45
+ onCancel: SlackTurnCancelActionHandler;
46
+ }
47
+ declare function registerSlackTurnCancelAction(app: App, options: RegisterSlackTurnCancelActionOptions): {
48
+ actionId: string;
49
+ };
50
+
51
+ export { type RegisterSlackTurnCancelActionOptions, SLACK_TURN_CANCEL_ACTION_ID, type SlackTurnCancelActionContext, type SlackTurnCancelActionHandler, type SlackTurnCancelButtonValue, type SlackTurnCancelMessage, type SlackTurnCancelMessageOptions, createSlackTurnCancelMessage, decodeSlackTurnCancelButtonValue, encodeSlackTurnCancelButtonValue, registerSlackTurnCancelAction, resolveSlackTurnCancelActionId };
@@ -0,0 +1,16 @@
1
+ import {
2
+ SLACK_TURN_CANCEL_ACTION_ID,
3
+ createSlackTurnCancelMessage,
4
+ decodeSlackTurnCancelButtonValue,
5
+ encodeSlackTurnCancelButtonValue,
6
+ registerSlackTurnCancelAction,
7
+ resolveSlackTurnCancelActionId
8
+ } from "../chunk-3KP3CBCC.js";
9
+ export {
10
+ SLACK_TURN_CANCEL_ACTION_ID,
11
+ createSlackTurnCancelMessage,
12
+ decodeSlackTurnCancelButtonValue,
13
+ encodeSlackTurnCancelButtonValue,
14
+ registerSlackTurnCancelAction,
15
+ resolveSlackTurnCancelActionId
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cuylabs/channel-slack",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Agent-runtime-agnostic Slack channel primitives for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -71,6 +71,11 @@
71
71
  "import": "./dist/targets/index.js",
72
72
  "default": "./dist/targets/index.js"
73
73
  },
74
+ "./turn-controls": {
75
+ "types": "./dist/turn-controls/index.d.ts",
76
+ "import": "./dist/turn-controls/index.js",
77
+ "default": "./dist/turn-controls/index.js"
78
+ },
74
79
  "./transports": {
75
80
  "types": "./dist/transports/index.d.ts",
76
81
  "import": "./dist/transports/index.js",
@@ -148,9 +153,9 @@
148
153
  "node": ">=20"
149
154
  },
150
155
  "scripts": {
151
- "build": "tsup src/index.ts src/app-home.ts src/artifacts/index.ts src/core.ts src/assistant/index.ts src/auth/index.ts src/diagnostics/index.ts src/entrypoints/index.ts src/feedback/index.ts src/history/index.ts src/policy/index.ts src/setup/index.ts src/targets/index.ts src/transports/index.ts src/transports/http/index.ts src/transports/socket/index.ts src/users/index.ts src/views/index.ts --format esm --dts --clean",
156
+ "build": "tsup src/index.ts src/app-home.ts src/artifacts/index.ts src/core.ts src/assistant/index.ts src/auth/index.ts src/diagnostics/index.ts src/entrypoints/index.ts src/feedback/index.ts src/history/index.ts src/policy/index.ts src/setup/index.ts src/targets/index.ts src/turn-controls/index.ts src/transports/index.ts src/transports/http/index.ts src/transports/socket/index.ts src/users/index.ts src/views/index.ts --format esm --dts --clean",
152
157
  "clean": "rm -rf dist",
153
- "dev": "tsup src/index.ts src/app-home.ts src/artifacts/index.ts src/core.ts src/assistant/index.ts src/auth/index.ts src/diagnostics/index.ts src/entrypoints/index.ts src/feedback/index.ts src/history/index.ts src/policy/index.ts src/setup/index.ts src/targets/index.ts src/transports/index.ts src/transports/http/index.ts src/transports/socket/index.ts src/users/index.ts src/views/index.ts --format esm --dts --watch",
158
+ "dev": "tsup src/index.ts src/app-home.ts src/artifacts/index.ts src/core.ts src/assistant/index.ts src/auth/index.ts src/diagnostics/index.ts src/entrypoints/index.ts src/feedback/index.ts src/history/index.ts src/policy/index.ts src/setup/index.ts src/targets/index.ts src/turn-controls/index.ts src/transports/index.ts src/transports/http/index.ts src/transports/socket/index.ts src/users/index.ts src/views/index.ts --format esm --dts --watch",
154
159
  "lint": "eslint \"src/**/*.{ts,tsx}\" \"tests/**/*.{ts,tsx}\" --max-warnings=0",
155
160
  "test": "vitest run",
156
161
  "test:watch": "vitest",
File without changes