cli-jaw 2.17.43 → 2.17.44
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.
- package/README.md +13 -2
- package/dist/bin/commands/slack.js +73 -7
- package/dist/bin/commands/slack.js.map +1 -1
- package/dist/server.js +46 -1
- package/dist/server.js.map +1 -1
- package/dist/src/agent/calendar-context.js +23 -0
- package/dist/src/agent/calendar-context.js.map +1 -0
- package/dist/src/agent/claude-runtime-run.js +10 -1
- package/dist/src/agent/claude-runtime-run.js.map +1 -1
- package/dist/src/agent/cursor-acp-models.js +139 -0
- package/dist/src/agent/cursor-acp-models.js.map +1 -0
- package/dist/src/agent/events/cursor.js +28 -4
- package/dist/src/agent/events/cursor.js.map +1 -1
- package/dist/src/agent/lifecycle-handler.js +8 -2
- package/dist/src/agent/lifecycle-handler.js.map +1 -1
- package/dist/src/agent/native-runtime-run.js +22 -1
- package/dist/src/agent/native-runtime-run.js.map +1 -1
- package/dist/src/agent/runtime/acp/config.js +76 -11
- package/dist/src/agent/runtime/acp/config.js.map +1 -1
- package/dist/src/agent/runtime/acp/cursor-session.js +6 -1
- package/dist/src/agent/runtime/acp/cursor-session.js.map +1 -1
- package/dist/src/agent/runtime/liveness.js +24 -0
- package/dist/src/agent/runtime/liveness.js.map +1 -0
- package/dist/src/agent/runtime/start-failure.js +61 -0
- package/dist/src/agent/runtime/start-failure.js.map +1 -0
- package/dist/src/agent/spawn/queue.js +11 -6
- package/dist/src/agent/spawn/queue.js.map +1 -1
- package/dist/src/agent/spawn.js +59 -17
- package/dist/src/agent/spawn.js.map +1 -1
- package/dist/src/cli/api-auth.js +6 -0
- package/dist/src/cli/api-auth.js.map +1 -1
- package/dist/src/manager/design/watcher.js +10 -2
- package/dist/src/manager/design/watcher.js.map +1 -1
- package/dist/src/memory/heartbeat.js +6 -0
- package/dist/src/memory/heartbeat.js.map +1 -1
- package/dist/src/messaging/channel-validate.js +5 -3
- package/dist/src/messaging/channel-validate.js.map +1 -1
- package/dist/src/messaging/redact.js +30 -8
- package/dist/src/messaging/redact.js.map +1 -1
- package/dist/src/messaging/send.js +7 -0
- package/dist/src/messaging/send.js.map +1 -1
- package/dist/src/orchestrator/collect.js +5 -3
- package/dist/src/orchestrator/collect.js.map +1 -1
- package/dist/src/orchestrator/gateway.js +10 -3
- package/dist/src/orchestrator/gateway.js.map +1 -1
- package/dist/src/orchestrator/pipeline.js +21 -9
- package/dist/src/orchestrator/pipeline.js.map +1 -1
- package/dist/src/orchestrator/request-registry.js +2 -0
- package/dist/src/orchestrator/request-registry.js.map +1 -1
- package/dist/src/prompt/builder.js +74 -6
- package/dist/src/prompt/builder.js.map +1 -1
- package/dist/src/prompt/templates/a1-system.md +22 -5
- package/dist/src/routes/messaging.js +105 -27
- package/dist/src/routes/messaging.js.map +1 -1
- package/dist/src/routes/settings.js +20 -8
- package/dist/src/routes/settings.js.map +1 -1
- package/dist/src/routes/slack-tools.js +176 -0
- package/dist/src/routes/slack-tools.js.map +1 -0
- package/dist/src/slack/action-rate.js +43 -0
- package/dist/src/slack/action-rate.js.map +1 -0
- package/dist/src/slack/action-runtime.js +243 -0
- package/dist/src/slack/action-runtime.js.map +1 -0
- package/dist/src/slack/action-store.js +84 -0
- package/dist/src/slack/action-store.js.map +1 -0
- package/dist/src/slack/action-types.js +6 -0
- package/dist/src/slack/action-types.js.map +1 -0
- package/dist/src/slack/actions-canvas.js +108 -0
- package/dist/src/slack/actions-canvas.js.map +1 -0
- package/dist/src/slack/actions-channel.js +88 -0
- package/dist/src/slack/actions-channel.js.map +1 -0
- package/dist/src/slack/actions-interactions.js +204 -0
- package/dist/src/slack/actions-interactions.js.map +1 -0
- package/dist/src/slack/actions-lists.js +308 -0
- package/dist/src/slack/actions-lists.js.map +1 -0
- package/dist/src/slack/actions-message.js +117 -0
- package/dist/src/slack/actions-message.js.map +1 -0
- package/dist/src/slack/actions-resources.js +62 -0
- package/dist/src/slack/actions-resources.js.map +1 -0
- package/dist/src/slack/actions-rts.js +88 -0
- package/dist/src/slack/actions-rts.js.map +1 -0
- package/dist/src/slack/actions-schedule.js +214 -0
- package/dist/src/slack/actions-schedule.js.map +1 -0
- package/dist/src/slack/actions.js +17 -0
- package/dist/src/slack/actions.js.map +1 -0
- package/dist/src/slack/api.js +56 -9
- package/dist/src/slack/api.js.map +1 -1
- package/dist/src/slack/blocks.js +162 -0
- package/dist/src/slack/blocks.js.map +1 -0
- package/dist/src/slack/bot.js +562 -378
- package/dist/src/slack/bot.js.map +1 -1
- package/dist/src/slack/commands.js +24 -5
- package/dist/src/slack/commands.js.map +1 -1
- package/dist/src/slack/context.js +15 -4
- package/dist/src/slack/context.js.map +1 -1
- package/dist/src/slack/conversation.js +135 -33
- package/dist/src/slack/conversation.js.map +1 -1
- package/dist/src/slack/events.js +41 -17
- package/dist/src/slack/events.js.map +1 -1
- package/dist/src/slack/format.js +181 -0
- package/dist/src/slack/format.js.map +1 -1
- package/dist/src/slack/history.js +133 -8
- package/dist/src/slack/history.js.map +1 -1
- package/dist/src/slack/ingress.js +26 -9
- package/dist/src/slack/ingress.js.map +1 -1
- package/dist/src/slack/interaction-store.js +56 -0
- package/dist/src/slack/interaction-store.js.map +1 -0
- package/dist/src/slack/manifest.js +3 -0
- package/dist/src/slack/manifest.js.map +1 -1
- package/dist/src/slack/message-content.js +132 -0
- package/dist/src/slack/message-content.js.map +1 -0
- package/dist/src/slack/message.js +58 -0
- package/dist/src/slack/message.js.map +1 -0
- package/dist/src/slack/notice-transport.js +49 -19
- package/dist/src/slack/notice-transport.js.map +1 -1
- package/dist/src/slack/operator-auth.js +62 -0
- package/dist/src/slack/operator-auth.js.map +1 -0
- package/dist/src/slack/progress-activity.js +210 -0
- package/dist/src/slack/progress-activity.js.map +1 -0
- package/dist/src/slack/progress-detail.js +473 -0
- package/dist/src/slack/progress-detail.js.map +1 -0
- package/dist/src/slack/progress-files.js +70 -0
- package/dist/src/slack/progress-files.js.map +1 -0
- package/dist/src/slack/progress-lifecycle.js +223 -0
- package/dist/src/slack/progress-lifecycle.js.map +1 -0
- package/dist/src/slack/progress-restore.js +81 -0
- package/dist/src/slack/progress-restore.js.map +1 -0
- package/dist/src/slack/progress.js +325 -143
- package/dist/src/slack/progress.js.map +1 -1
- package/dist/src/slack/quote.js +227 -0
- package/dist/src/slack/quote.js.map +1 -0
- package/dist/src/slack/render-features.js +105 -0
- package/dist/src/slack/render-features.js.map +1 -0
- package/dist/src/slack/reply-delivery.js +110 -0
- package/dist/src/slack/reply-delivery.js.map +1 -0
- package/dist/src/slack/rts-output-store.js +143 -0
- package/dist/src/slack/rts-output-store.js.map +1 -0
- package/dist/src/slack/scope-status.js +17 -3
- package/dist/src/slack/scope-status.js.map +1 -1
- package/dist/src/slack/search-quote.js +70 -0
- package/dist/src/slack/search-quote.js.map +1 -0
- package/dist/src/slack/search.js +54 -0
- package/dist/src/slack/search.js.map +1 -0
- package/dist/src/slack/send-handler.js +11 -7
- package/dist/src/slack/send-handler.js.map +1 -1
- package/dist/src/slack/send-only-client.js +116 -79
- package/dist/src/slack/send-only-client.js.map +1 -1
- package/dist/src/slack/table-content.js +253 -0
- package/dist/src/slack/table-content.js.map +1 -0
- package/dist/src/slack/table-verification.js +64 -0
- package/dist/src/slack/table-verification.js.map +1 -0
- package/dist/src/slack/task-input.js +55 -0
- package/dist/src/slack/task-input.js.map +1 -0
- package/dist/src/slack/tool-access.js +127 -0
- package/dist/src/slack/tool-access.js.map +1 -0
- package/dist/src/slack/tool-capabilities.js +47 -0
- package/dist/src/slack/tool-capabilities.js.map +1 -0
- package/dist/src/slack/tool-context.js +91 -0
- package/dist/src/slack/tool-context.js.map +1 -0
- package/dist/src/slack/verified-workspace.js +17 -6
- package/dist/src/slack/verified-workspace.js.map +1 -1
- package/dist/src/trace/redact.js +2 -1
- package/dist/src/trace/redact.js.map +1 -1
- package/package.json +1 -1
- package/public/dist/.vite/manifest.json +102 -102
- package/public/dist/assets/{Agent-CQ4EBgY8.js → Agent-CNad_A6t.js} +1 -1
- package/public/dist/assets/{ChannelEnablementControl-JsYvNMlM.js → ChannelEnablementControl-DwUDKjX9.js} +4 -4
- package/public/dist/assets/{ChannelSetupEntry-BpyRWEUE.js → ChannelSetupEntry-DH0AuNNX.js} +1 -1
- package/public/dist/assets/{ChannelsDiscord-DNfvz1jn.js → ChannelsDiscord-7NmoTjR7.js} +1 -1
- package/public/dist/assets/{ChannelsSlack-DzpxIdgW.js → ChannelsSlack-Ba0ax6iT.js} +1 -1
- package/public/dist/assets/{ChannelsTelegram-CUhFc5s6.js → ChannelsTelegram-DKA9atf2.js} +1 -1
- package/public/dist/assets/{app-Q0prKOFx.js → app-9OQNfmqw.js} +4 -4
- package/public/dist/assets/{bgtask-badge-DAcWaUfS.js → bgtask-badge-BvxHqMGi.js} +1 -1
- package/public/dist/assets/bgtask-badge-DeSZJGNN.js +1 -0
- package/public/dist/assets/{employees-CWS3Juca.js → employees-CkUqN4oh.js} +1 -1
- package/public/dist/assets/{iframe-renderer-DCDKBMb7.js → iframe-renderer-C2gchtOj.js} +2 -2
- package/public/dist/assets/iframe-renderer-DfvACXIn.js +1 -0
- package/public/dist/assets/{manager-v6GYfoPB.js → manager-rb5X-4DJ.js} +1 -1
- package/public/dist/assets/{memory-DhNdKZLO.js → memory-BiWzpoBq.js} +1 -1
- package/public/dist/assets/memory-Ckp1Eq5a.js +1 -0
- package/public/dist/assets/message-history-Bv0l_t7O.js +1 -0
- package/public/dist/assets/{message-history-DbRTl1P0.js → message-history-CuFefS02.js} +1 -1
- package/public/dist/assets/{render-DP8SJtdZ.js → render-DUGqq9Mu.js} +1 -1
- package/public/dist/assets/{settings-85n9NjvX.js → settings-BqUHavbH.js} +1 -1
- package/public/dist/assets/settings-C81Kf9uX.js +1 -0
- package/public/dist/assets/{settings-C9_D-pn0.js → settings-DQ1fLygB.js} +31 -30
- package/public/dist/assets/{settings-core-BcVD2FgV.js → settings-core-CzdXfoOK.js} +1 -1
- package/public/dist/assets/settings-core-DO_5M7Lv.js +1 -0
- package/public/dist/assets/{settings-embedding-BSpq785l.js → settings-embedding-BAKFrVLV.js} +1 -1
- package/public/dist/assets/{settings-types-B09BmpYe.js → settings-types-D3cd6SWy.js} +1 -1
- package/public/dist/assets/{sidebar-BVhLb5Ft.js → sidebar-CvGbp9x5.js} +3 -3
- package/public/dist/assets/skills-DFpPmMUR.js +1 -0
- package/public/dist/assets/{skills-X7qxmHka.js → skills-abLMqY5_.js} +1 -1
- package/public/dist/assets/slash-commands-BU58xYih.js +1 -0
- package/public/dist/assets/{slash-commands-BnDH4IU_.js → slash-commands-D8o9pqOS.js} +1 -1
- package/public/dist/assets/{trace-drawer-DasaS1z4.js → trace-drawer-C6RvkUAd.js} +1 -1
- package/public/dist/assets/{ui-BtiBTXng.js → ui-Bxapl_Eu.js} +1 -1
- package/public/dist/assets/ui-CUB4iwz3.js +1 -0
- package/public/dist/index.html +1 -1
- package/public/dist/manager/index.html +1 -1
- package/public/dist/settings/index.html +1 -1
- package/public/js/features/settings-cli-status.ts +11 -1
- package/public/js/features/settings-types.ts +21 -0
- package/public/locales/en.json +34 -1
- package/public/locales/ja.json +34 -1
- package/public/locales/ko.json +34 -1
- package/public/locales/zh.json +34 -1
- package/scripts/check-native-load.cjs +17 -4
- package/scripts/release-gates.mjs +84 -3
- package/scripts/service-artifact.mjs +157 -0
- package/scripts/service-shell/zsh/.zlogin +23 -0
- package/scripts/service-shell/zsh/.zlogout +23 -0
- package/scripts/service-shell/zsh/.zprofile +23 -0
- package/scripts/service-shell/zsh/.zshenv +23 -0
- package/scripts/service-shell/zsh/.zshrc +23 -0
- package/public/dist/assets/bgtask-badge-DHA2OQm8.js +0 -1
- package/public/dist/assets/iframe-renderer-RpvBly2x.js +0 -1
- package/public/dist/assets/memory-4YH8sz0L.js +0 -1
- package/public/dist/assets/message-history-lVcLpAw8.js +0 -1
- package/public/dist/assets/settings--EGy3_B9.js +0 -1
- package/public/dist/assets/settings-core-8wBl1mg-.js +0 -1
- package/public/dist/assets/skills-6GFkHTlQ.js +0 -1
- package/public/dist/assets/slash-commands-qu8fPAZ3.js +0 -1
- package/public/dist/assets/ui-BucJ1zMA.js +0 -1
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { slackDataForAgent } from './history.js';
|
|
2
|
+
import { getRtsOutputStore, isRtsOutput } from './rts-output-store.js';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { SlackActionRateLimiter } from './action-rate.js';
|
|
5
|
+
import { slackApi, addSlackReaction, removeSlackReaction, deleteSlackMessage, readBoundedResponse } from './api.js';
|
|
6
|
+
import { readSlackAuthSnapshot } from './verified-workspace.js';
|
|
7
|
+
import { slackCredentialKey } from './tool-context.js';
|
|
8
|
+
import { slackToolDenied, withSlackToolAccess } from './tool-access.js';
|
|
9
|
+
import { redactOutboundPayload } from '../messaging/redact.js';
|
|
10
|
+
import { validateSlackDownloadUrl } from './inbound-url.js';
|
|
11
|
+
const WRITE_METHODS = new Set(['reactions.add', 'reactions.remove', 'chat.update', 'chat.delete', 'chat.postMessage', 'chat.scheduleMessage', 'chat.deleteScheduledMessage', 'pins.add', 'pins.remove', 'bookmarks.add', 'bookmarks.edit', 'bookmarks.remove', 'canvases.create', 'canvases.edit', 'canvases.access.set', 'slackLists.create', 'slackLists.items.create', 'slackLists.items.update', 'slackLists.access.set']);
|
|
12
|
+
const SAFE_ERRORS = new Set(['missing_scope', 'invalid_auth', 'not_authed', 'not_in_channel', 'channel_not_found', 'message_not_found', 'invalid_scheduled_message_id', 'already_reacted', 'no_reaction', 'not_pinned', 'already_pinned', 'bookmark_not_found', 'invalid_arguments', 'invalid_name', 'permission_denied', 'restricted_action', 'list_not_found', 'row_not_found', 'canvas_not_found']);
|
|
13
|
+
export class SlackActionRuntime {
|
|
14
|
+
options;
|
|
15
|
+
rate;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.rate = options.rateLimiter ?? new SlackActionRateLimiter();
|
|
19
|
+
}
|
|
20
|
+
async execute(definition, raw, principal, requestSignal) {
|
|
21
|
+
if (principal.kind === 'turn' && definition.mutates) {
|
|
22
|
+
const thread = principal.grant.destination.threadId ?? '';
|
|
23
|
+
if (raw['threadTs'] !== undefined && raw['threadTs'] !== thread)
|
|
24
|
+
throw slackToolDenied('slack_destination_thread_mismatch');
|
|
25
|
+
if (['schedule.create', 'schedule.update', 'interaction.url', 'interaction.choice'].includes(definition.operation) && thread)
|
|
26
|
+
raw = { ...raw, threadTs: thread };
|
|
27
|
+
}
|
|
28
|
+
const prepared = definition.prepare(raw);
|
|
29
|
+
const args = prepared.args;
|
|
30
|
+
const token = this.options.getToken();
|
|
31
|
+
if (!token)
|
|
32
|
+
throw slackToolDenied('slack_unavailable', 503);
|
|
33
|
+
if (definition.requiresInbound && !this.options.inboundReady?.())
|
|
34
|
+
throw slackToolDenied('slack_interaction_inbound_unavailable', 409);
|
|
35
|
+
if (definition.mutates && !args.invocationId)
|
|
36
|
+
throw slackToolDenied('slack_invocation_required', 400);
|
|
37
|
+
if (definition.mutates && principal.kind === 'turn' && args.channel !== principal.grant.destination.targetId)
|
|
38
|
+
throw slackToolDenied('slack_destination_mismatch');
|
|
39
|
+
const identity = await readSlackAuthSnapshot(token, { ...(this.options.fetchImpl ? { fetchImpl: this.options.fetchImpl } : {}), ...(requestSignal ? { signal: requestSignal } : {}) });
|
|
40
|
+
if (!identity?.userId)
|
|
41
|
+
throw slackToolDenied('slack_bot_identity_unverified', 409);
|
|
42
|
+
if (definition.scopes.length && identity.scopes === null)
|
|
43
|
+
throw slackToolDenied('slack_action_scopes_unverified', 403);
|
|
44
|
+
if (definition.scopes.some(scope => !identity.scopes?.includes(scope)))
|
|
45
|
+
throw slackToolDenied('slack_action_scopes_missing', 403);
|
|
46
|
+
const workspace = identity.teamId;
|
|
47
|
+
const actor = principal.kind === 'turn' ? principal.grant.actorId : 'operator';
|
|
48
|
+
const credentialKey = slackCredentialKey(token);
|
|
49
|
+
const store = this.options.store;
|
|
50
|
+
const hash = createHash('sha256').update(JSON.stringify({ credentialKey, operation: definition.operation, args: prepared.canonical })).digest('hex');
|
|
51
|
+
const existing = definition.mutates ? store.invocation(workspace, actor, args.invocationId) : undefined;
|
|
52
|
+
const ids = new Set();
|
|
53
|
+
let dispatched = false;
|
|
54
|
+
const base = (verification, data, resourceIds = [...ids]) => {
|
|
55
|
+
const projected = data === undefined ? undefined : slackDataForAgent(data);
|
|
56
|
+
const state = projected?.truncated && verification === 'verified' ? 'partial' : verification;
|
|
57
|
+
return { ok: state === 'verified', operation: definition.operation, verification: state, retryable: false, resourceIds,
|
|
58
|
+
...(projected ? { data: projected.value } : {}), ...(state === 'partial' ? { partial: true } : {}) };
|
|
59
|
+
};
|
|
60
|
+
return withSlackToolAccess(token, principal, args.channel, async (grantSignal) => {
|
|
61
|
+
const signal = requestSignal ? (grantSignal ? AbortSignal.any([requestSignal, grantSignal]) : requestSignal) : grantSignal;
|
|
62
|
+
const checkCurrent = () => {
|
|
63
|
+
if (signal?.aborted)
|
|
64
|
+
throw slackToolDenied('slack_action_cancelled', 499);
|
|
65
|
+
if (this.options.getToken() !== token)
|
|
66
|
+
throw slackToolDenied('slack_credential_changed', 409);
|
|
67
|
+
};
|
|
68
|
+
checkCurrent();
|
|
69
|
+
if (principal.kind === 'turn' && /^(canvas|list)\./.test(definition.operation)) {
|
|
70
|
+
// File ACLs describe the requester, not every recipient in a group.
|
|
71
|
+
// Until a complete audience ACL proof is available, resource tools
|
|
72
|
+
// run only in the freshly verified requester/bot DM.
|
|
73
|
+
const conversation = await slackApi(token, 'conversations.info', { channel: args.channel }, {
|
|
74
|
+
...(this.options.fetchImpl ? { fetchImpl: this.options.fetchImpl } : {}), ...(signal ? { signal } : {}), sensitiveResponse: true, form: true,
|
|
75
|
+
});
|
|
76
|
+
checkCurrent();
|
|
77
|
+
if (!conversation.ok || conversation.data?.channel?.id !== args.channel || conversation.data.channel.is_im !== true
|
|
78
|
+
|| conversation.data.channel.user !== actor)
|
|
79
|
+
throw slackToolDenied('slack_resource_requester_dm_required');
|
|
80
|
+
}
|
|
81
|
+
if (existing) {
|
|
82
|
+
if (existing.request_hash !== hash || !['completed', 'failed'].includes(existing.status) || !existing.receipt_json)
|
|
83
|
+
throw slackToolDenied('slack_invocation_conflict_or_unknown', 409);
|
|
84
|
+
const receipt = JSON.parse(existing.receipt_json);
|
|
85
|
+
if (!receipt || typeof receipt !== 'object' || Array.isArray(receipt))
|
|
86
|
+
throw slackToolDenied('slack_invocation_receipt_invalid', 409);
|
|
87
|
+
return receipt;
|
|
88
|
+
}
|
|
89
|
+
if (definition.mutates && !store.reserve(workspace, actor, args.invocationId, hash))
|
|
90
|
+
throw slackToolDenied('slack_invocation_capacity_or_conflict', 409);
|
|
91
|
+
let calls = 0;
|
|
92
|
+
const context = {
|
|
93
|
+
token, workspace, botUserId: identity.userId, actor, channel: args.channel, credentialKey, operator: principal.kind === 'operator', ...(signal ? { signal } : {}),
|
|
94
|
+
checkCurrent, now: this.options.now ?? (() => Date.now()),
|
|
95
|
+
api: async (method, body, beforeDispatch) => {
|
|
96
|
+
checkCurrent();
|
|
97
|
+
if (!definition.methods.includes(method) || ++calls > 100 || (WRITE_METHODS.has(method) && !definition.mutates))
|
|
98
|
+
throw slackToolDenied('slack_action_method_contract', 500);
|
|
99
|
+
for (const key of ['channel', 'channel_id'])
|
|
100
|
+
if (body[key] !== undefined && body[key] !== args.channel)
|
|
101
|
+
throw slackToolDenied('slack_action_target_contract', 400);
|
|
102
|
+
if (Array.isArray(body['channel_ids']) && body['channel_ids'].some(value => value !== args.channel))
|
|
103
|
+
throw slackToolDenied('slack_action_target_contract', 400);
|
|
104
|
+
await this.rate.admit(workspace, method, signal);
|
|
105
|
+
checkCurrent();
|
|
106
|
+
if (WRITE_METHODS.has(method)) {
|
|
107
|
+
if (principal.kind === 'turn') {
|
|
108
|
+
const thread = principal.grant.destination.threadId ?? '';
|
|
109
|
+
if (['chat.postMessage', 'chat.scheduleMessage'].includes(method)) {
|
|
110
|
+
if (body['thread_ts'] !== undefined && body['thread_ts'] !== thread)
|
|
111
|
+
throw slackToolDenied('slack_destination_thread_mismatch');
|
|
112
|
+
body = { ...body, ...(thread ? { thread_ts: thread } : {}) };
|
|
113
|
+
}
|
|
114
|
+
const protectedResource = method === 'chat.update' || method === 'chat.delete' ? ['message', body['ts']]
|
|
115
|
+
: method === 'bookmarks.edit' || method === 'bookmarks.remove' ? ['bookmark', body['bookmark_id']]
|
|
116
|
+
: method === 'pins.remove' ? ['pin', body['timestamp']] : undefined;
|
|
117
|
+
if (protectedResource) {
|
|
118
|
+
const owned = context.resource(protectedResource[0], String(protectedResource[1]));
|
|
119
|
+
if (!owned || owned.status !== 'active' || owned.credentialKey !== credentialKey)
|
|
120
|
+
throw slackToolDenied('slack_resource_ownership_unverified');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
await withSlackToolAccess(token, principal, args.channel, async () => true, this.options.fetchImpl, undefined, true);
|
|
124
|
+
if (beforeDispatch)
|
|
125
|
+
await beforeDispatch();
|
|
126
|
+
checkCurrent();
|
|
127
|
+
store.dispatched(workspace, actor, args.invocationId);
|
|
128
|
+
dispatched = true;
|
|
129
|
+
}
|
|
130
|
+
if (!WRITE_METHODS.has(method) && beforeDispatch) {
|
|
131
|
+
await beforeDispatch();
|
|
132
|
+
checkCurrent();
|
|
133
|
+
}
|
|
134
|
+
const options = { ...(this.options.fetchImpl ? { fetchImpl: this.options.fetchImpl } : {}), ...(signal ? { signal } : {}), sensitiveResponse: true, maxResponseBytes: 1048576, timeoutMs: 10000 };
|
|
135
|
+
const result = method === 'reactions.add' ? await addSlackReaction(token, String(body['channel']), String(body['timestamp']), String(body['name']), options)
|
|
136
|
+
: method === 'reactions.remove' ? await removeSlackReaction(token, String(body['channel']), String(body['timestamp']), String(body['name']), options)
|
|
137
|
+
: method === 'chat.delete' ? await deleteSlackMessage(token, String(body['channel']), String(body['ts']), options)
|
|
138
|
+
: await slackApi(token, method, body, { ...options, form: !WRITE_METHODS.has(method) && !method.startsWith('slackLists.') });
|
|
139
|
+
if (result.ok && WRITE_METHODS.has(method) && result.data && typeof result.data === 'object') {
|
|
140
|
+
const data = result.data;
|
|
141
|
+
const nestedId = (value) => value && typeof value === 'object' ? value['id'] : undefined;
|
|
142
|
+
for (const id of [data['ts'], data['scheduled_message_id'], data['canvas_id'], data['list_id'], nestedId(data['bookmark']), nestedId(data['item'])]) {
|
|
143
|
+
if ((typeof id === 'string' || typeof id === 'number') && /^[A-Za-z0-9_.:-]{1,128}$/.test(String(id)))
|
|
144
|
+
ids.add(String(id));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (result.ok && principal.kind === 'turn') {
|
|
148
|
+
const data = result.data;
|
|
149
|
+
if (method === 'chat.postMessage' && typeof data?.['ts'] === 'string')
|
|
150
|
+
context.remember('message', data['ts']);
|
|
151
|
+
if (method === 'pins.add' && typeof body['timestamp'] === 'string')
|
|
152
|
+
context.remember('pin', body['timestamp']);
|
|
153
|
+
}
|
|
154
|
+
if (!WRITE_METHODS.has(method))
|
|
155
|
+
checkCurrent();
|
|
156
|
+
if (result.error === 'ratelimited' || result.error === 'rate_limited')
|
|
157
|
+
throw Object.assign(slackToolDenied('slack_action_rate_limited', 429), { retryAfterMs: result.retryAfterMs });
|
|
158
|
+
if (!WRITE_METHODS.has(method) && definition.operation !== 'rts.reconcile' && result.data !== undefined)
|
|
159
|
+
return { ...result, data: maskRtsActionMessages(workspace, args.channel, result.data) };
|
|
160
|
+
return result;
|
|
161
|
+
},
|
|
162
|
+
remember(kind, id, metadata = {}) {
|
|
163
|
+
ids.add(id);
|
|
164
|
+
store.remember({ workspace, kind, id, actor, channel: args.channel, botUserId: identity.userId, credentialKey, metadata: redactOutboundPayload({ ...metadata, ...(principal.kind === 'turn' ? { threadTs: principal.grant.destination.threadId ?? '' } : {}) }) });
|
|
165
|
+
},
|
|
166
|
+
resource(kind, id) {
|
|
167
|
+
const row = store.resource(workspace, kind, id);
|
|
168
|
+
if (!row || row.channel !== args.channel || row.botUserId !== identity.userId || (principal.kind !== 'operator' && row.actor !== actor))
|
|
169
|
+
return undefined;
|
|
170
|
+
if (principal.kind === 'turn' && (row.metadata['threadTs'] ?? '') !== (principal.grant.destination.threadId ?? ''))
|
|
171
|
+
return undefined;
|
|
172
|
+
if (kind === 'schedule' && row.credentialKey !== credentialKey)
|
|
173
|
+
throw slackToolDenied('slack_schedule_credential_changed', 409);
|
|
174
|
+
return row;
|
|
175
|
+
},
|
|
176
|
+
resources: kind => store.resources(workspace, kind, args.channel, principal.kind === 'operator' ? undefined : actor).filter(row => row.botUserId === identity.userId),
|
|
177
|
+
retire(kind, id) { if (!context.resource(kind, id))
|
|
178
|
+
throw slackToolDenied('slack_resource_ownership_unverified'); store.retire(workspace, kind, id); ids.add(id); },
|
|
179
|
+
download: async (url) => {
|
|
180
|
+
let next = url;
|
|
181
|
+
for (let hop = 0; hop <= 3; hop++) {
|
|
182
|
+
checkCurrent();
|
|
183
|
+
const safe = await validateSlackDownloadUrl(next, this.options.resolveHost ? { resolveHost: this.options.resolveHost } : {});
|
|
184
|
+
checkCurrent();
|
|
185
|
+
const downloadSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(10000)]) : AbortSignal.timeout(10000);
|
|
186
|
+
const response = await (this.options.fetchImpl ?? fetch)(safe, { headers: { Authorization: `Bearer ${token}` }, redirect: 'manual', signal: downloadSignal });
|
|
187
|
+
if (response.status >= 300 && response.status < 400) {
|
|
188
|
+
const location = response.headers.get('location');
|
|
189
|
+
void response.body?.cancel().catch(() => { });
|
|
190
|
+
if (!location)
|
|
191
|
+
throw slackToolDenied('slack_download_redirect_invalid', 502);
|
|
192
|
+
next = new URL(location, safe).href;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (!response.ok)
|
|
196
|
+
throw slackToolDenied('slack_download_failed', 502);
|
|
197
|
+
const content = await readBoundedResponse(response, 1048576, downloadSignal);
|
|
198
|
+
checkCurrent();
|
|
199
|
+
return { content: redactOutboundPayload(content), contentType: response.headers.get('content-type') ?? '' };
|
|
200
|
+
}
|
|
201
|
+
throw slackToolDenied('slack_download_redirect_limit', 502);
|
|
202
|
+
},
|
|
203
|
+
result: base,
|
|
204
|
+
fail: (code, status = 409, resourceIds = [...ids]) => ({ ...base(dispatched ? 'unknown' : 'failed', undefined, resourceIds), error: code, status: status >= 400 && status <= 599 ? status : 502 }),
|
|
205
|
+
};
|
|
206
|
+
let result;
|
|
207
|
+
try {
|
|
208
|
+
result = await prepared.execute(context);
|
|
209
|
+
checkCurrent();
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
const code = error.code;
|
|
213
|
+
result = { ...base(dispatched ? 'unknown' : 'failed'), error: typeof code === 'string' && (code.startsWith('slack_') || SAFE_ERRORS.has(code)) ? code : 'slack_action_failed', status: error.statusCode ?? 502 };
|
|
214
|
+
}
|
|
215
|
+
if (definition.mutates && Buffer.byteLength(JSON.stringify(result)) > 15000) {
|
|
216
|
+
// Durable replay must retain acknowledged addresses even when a
|
|
217
|
+
// provider's readback is larger than the receipt budget.
|
|
218
|
+
result = { ...result, ok: false, verification: result.verification === 'verified' ? 'partial' : result.verification,
|
|
219
|
+
partial: true, data: { omitted: true, reason: 'receipt_byte_limit' } };
|
|
220
|
+
}
|
|
221
|
+
if (result.verification === 'verified' && this.options.evidenceSource === 'slack_api')
|
|
222
|
+
store.recordVerified(workspace, credentialKey, definition.operation);
|
|
223
|
+
if (definition.mutates)
|
|
224
|
+
store.finish(workspace, actor, args.invocationId, result.verification === 'unknown' || result.verification === 'partial' ? 'unknown' : result.ok ? 'completed' : 'failed', result);
|
|
225
|
+
return result;
|
|
226
|
+
}, this.options.fetchImpl, result => ({ ...result, ok: false, verification: 'unknown', error: 'slack_action_cancelled_after_dispatch' }), true);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function maskRtsActionMessages(workspace, channel, value, depth = 0) {
|
|
230
|
+
if (depth > 16)
|
|
231
|
+
throw slackToolDenied('slack_action_response_depth', 502);
|
|
232
|
+
if (Array.isArray(value))
|
|
233
|
+
return value.map(item => maskRtsActionMessages(workspace, channel, item, depth + 1));
|
|
234
|
+
if (!value || typeof value !== 'object')
|
|
235
|
+
return value;
|
|
236
|
+
const item = value;
|
|
237
|
+
const store = getRtsOutputStore();
|
|
238
|
+
if (typeof item['ts'] === 'string' && (!store || isRtsOutput(item['blocks']) || store.held(workspace, channel) || store.contains(workspace, channel, item['ts']))) {
|
|
239
|
+
return { ts: item['ts'], user: item['user'], bot_id: item['bot_id'], reactions: item['reactions'], contentExcluded: true, text: '[검색 응답 내용 제외]', blocks: [] };
|
|
240
|
+
}
|
|
241
|
+
return Object.fromEntries(Object.entries(item).filter(([key]) => !['__proto__', 'constructor', 'prototype'].includes(key)).map(([key, child]) => [key, maskRtsActionMessages(workspace, channel, child, depth + 1)]));
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=action-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-runtime.js","sourceRoot":"","sources":["../../../src/slack/action-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const INVOCATION_CAP = 100000;
|
|
2
|
+
const RESOURCE_CAP = 10000;
|
|
3
|
+
export class SlackActionStore {
|
|
4
|
+
database;
|
|
5
|
+
constructor(database) {
|
|
6
|
+
this.database = database;
|
|
7
|
+
database.exec(`CREATE TABLE IF NOT EXISTS slack_tool_invocations (
|
|
8
|
+
workspace TEXT NOT NULL, actor TEXT NOT NULL, invocation_id TEXT NOT NULL,
|
|
9
|
+
request_hash TEXT NOT NULL, status TEXT NOT NULL, receipt_json TEXT,
|
|
10
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL,
|
|
11
|
+
PRIMARY KEY(workspace,actor,invocation_id));
|
|
12
|
+
CREATE TABLE IF NOT EXISTS slack_tool_resources (
|
|
13
|
+
workspace TEXT NOT NULL, kind TEXT NOT NULL, resource_id TEXT NOT NULL,
|
|
14
|
+
actor TEXT NOT NULL, channel TEXT NOT NULL, bot_user_id TEXT NOT NULL,
|
|
15
|
+
credential_key TEXT NOT NULL, status TEXT NOT NULL, metadata_json TEXT NOT NULL,
|
|
16
|
+
PRIMARY KEY(workspace,kind,resource_id));
|
|
17
|
+
CREATE TABLE IF NOT EXISTS slack_tool_verified (
|
|
18
|
+
workspace TEXT NOT NULL, credential_key TEXT NOT NULL, operation TEXT NOT NULL,
|
|
19
|
+
verified_at INTEGER NOT NULL, PRIMARY KEY(workspace,credential_key,operation));`);
|
|
20
|
+
}
|
|
21
|
+
invocation(workspace, actor, id) {
|
|
22
|
+
return this.database.prepare('SELECT request_hash,status,receipt_json FROM slack_tool_invocations WHERE workspace=? AND actor=? AND invocation_id=?').get(workspace, actor, id);
|
|
23
|
+
}
|
|
24
|
+
reserve(workspace, actor, id, hash) {
|
|
25
|
+
return this.database.transaction(() => {
|
|
26
|
+
const count = this.database.prepare('SELECT count(*) AS n FROM slack_tool_invocations').get();
|
|
27
|
+
if (count.n >= INVOCATION_CAP)
|
|
28
|
+
return false;
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
return this.database.prepare('INSERT OR IGNORE INTO slack_tool_invocations VALUES (?,?,?,?,?,?,?,?)').run(workspace, actor, id, hash, 'reserved', null, now, now).changes === 1;
|
|
31
|
+
})();
|
|
32
|
+
}
|
|
33
|
+
dispatched(workspace, actor, id) {
|
|
34
|
+
this.database.prepare("UPDATE slack_tool_invocations SET status='dispatched',updated_at=? WHERE workspace=? AND actor=? AND invocation_id=? AND status IN ('reserved','dispatched')").run(Date.now(), workspace, actor, id);
|
|
35
|
+
}
|
|
36
|
+
finish(workspace, actor, id, status, receipt) {
|
|
37
|
+
const json = JSON.stringify(receipt);
|
|
38
|
+
if (Buffer.byteLength(json) > 16384)
|
|
39
|
+
throw new Error('slack_action_receipt_too_large');
|
|
40
|
+
this.database.prepare('UPDATE slack_tool_invocations SET status=?,receipt_json=?,updated_at=? WHERE workspace=? AND actor=? AND invocation_id=?').run(status, json, Date.now(), workspace, actor, id);
|
|
41
|
+
}
|
|
42
|
+
resource(workspace, kind, id) {
|
|
43
|
+
const row = this.database.prepare('SELECT workspace,kind,resource_id,actor,channel,bot_user_id,credential_key,status,metadata_json FROM slack_tool_resources WHERE workspace=? AND kind=? AND resource_id=?').get(workspace, kind, id);
|
|
44
|
+
if (!row)
|
|
45
|
+
return undefined;
|
|
46
|
+
const metadata = JSON.parse(String(row['metadata_json']));
|
|
47
|
+
if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata) || !['active', 'retired'].includes(String(row['status'])))
|
|
48
|
+
throw new Error('slack_action_resource_invalid');
|
|
49
|
+
return { workspace: String(row['workspace']), kind: String(row['kind']), id: String(row['resource_id']), actor: String(row['actor']), channel: String(row['channel']), botUserId: String(row['bot_user_id']), credentialKey: String(row['credential_key']), status: row['status'], metadata: metadata };
|
|
50
|
+
}
|
|
51
|
+
resources(workspace, kind, channel, actor) {
|
|
52
|
+
const rows = (actor === undefined
|
|
53
|
+
? this.database.prepare('SELECT resource_id FROM slack_tool_resources WHERE workspace=? AND kind=? AND channel=? LIMIT 1001').all(workspace, kind, channel)
|
|
54
|
+
: this.database.prepare('SELECT resource_id FROM slack_tool_resources WHERE workspace=? AND kind=? AND channel=? AND actor=? LIMIT 1001').all(workspace, kind, channel, actor));
|
|
55
|
+
if (rows.length > 1000)
|
|
56
|
+
throw new Error('slack_action_resource_list_incomplete');
|
|
57
|
+
return rows.map(row => this.resource(workspace, kind, row.resource_id));
|
|
58
|
+
}
|
|
59
|
+
remember(value) {
|
|
60
|
+
const metadata = JSON.stringify(value.metadata);
|
|
61
|
+
if (Buffer.byteLength(metadata) > 262144)
|
|
62
|
+
throw new Error('slack_action_resource_too_large');
|
|
63
|
+
const existing = this.resource(value.workspace, value.kind, value.id);
|
|
64
|
+
if (existing && (existing.actor !== value.actor || existing.channel !== value.channel || existing.botUserId !== value.botUserId
|
|
65
|
+
|| (value.kind === 'schedule' && existing.credentialKey !== value.credentialKey)))
|
|
66
|
+
throw new Error('slack_action_resource_collision');
|
|
67
|
+
const count = this.database.prepare('SELECT count(*) AS n FROM slack_tool_resources').get();
|
|
68
|
+
if (!existing && count.n >= RESOURCE_CAP)
|
|
69
|
+
throw new Error('slack_action_resource_capacity');
|
|
70
|
+
this.database.prepare(`INSERT INTO slack_tool_resources VALUES (?,?,?,?,?,?,?,?,?)
|
|
71
|
+
ON CONFLICT(workspace,kind,resource_id) DO UPDATE SET metadata_json=excluded.metadata_json,status='active'`).run(value.workspace, value.kind, value.id, value.actor, value.channel, value.botUserId, value.credentialKey, 'active', metadata);
|
|
72
|
+
}
|
|
73
|
+
retire(workspace, kind, id) {
|
|
74
|
+
this.database.prepare("UPDATE slack_tool_resources SET status='retired',metadata_json='{}' WHERE workspace=? AND kind=? AND resource_id=?").run(workspace, kind, id);
|
|
75
|
+
}
|
|
76
|
+
verified(workspace, credentialKey, operation) {
|
|
77
|
+
const row = this.database.prepare('SELECT verified_at FROM slack_tool_verified WHERE workspace=? AND credential_key=? AND operation=?').get(workspace, credentialKey, operation);
|
|
78
|
+
return row?.verified_at ?? null;
|
|
79
|
+
}
|
|
80
|
+
recordVerified(workspace, credentialKey, operation) {
|
|
81
|
+
this.database.prepare('INSERT INTO slack_tool_verified VALUES (?,?,?,?) ON CONFLICT(workspace,credential_key,operation) DO UPDATE SET verified_at=excluded.verified_at').run(workspace, credentialKey, operation, Date.now());
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=action-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-store.js","sourceRoot":"","sources":["../../../src/slack/action-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function defineAction(definition) {
|
|
2
|
+
return { operation: definition.operation, scopes: definition.scopes, methods: definition.methods, mutates: definition.mutates,
|
|
3
|
+
...(definition.requiresInbound ? { requiresInbound: true } : {}),
|
|
4
|
+
prepare(raw) { const args = definition.parse(raw); return { args, canonical: args, execute: ctx => definition.execute(ctx, args) }; } };
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=action-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-types.js","sourceRoot":"","sources":["../../../src/slack/action-types.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,YAAY,CAAuB,UAGlD;IACG,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO;QACzH,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,OAAO,CAAC,GAAG,IAAI,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAChJ,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { defineAction } from './action-types.js';
|
|
2
|
+
import { baseAction, enumValue, opaqueId, requiredText } from './task-input.js';
|
|
3
|
+
import { acknowledgedFailure, fileAccess, preserve, responseId } from './actions-resources.js';
|
|
4
|
+
import { redactOutboundText } from '../messaging/redact.js';
|
|
5
|
+
import { slackToolDenied } from './tool-access.js';
|
|
6
|
+
const aclMethods = ['files.info', 'users.info'];
|
|
7
|
+
const aclScopes = ['files:read', 'users:read'];
|
|
8
|
+
async function readCanvas(ctx, id, expected) {
|
|
9
|
+
const file = await fileAccess(ctx, 'canvas', id, false);
|
|
10
|
+
if (!file)
|
|
11
|
+
return ctx.fail('resource_requester_access_denied', 403, [id]);
|
|
12
|
+
const url = file['url_private_download'] ?? file['url_private'];
|
|
13
|
+
const metadata = { id, title: typeof file['title'] === 'string' ? redactOutboundText(file['title']).slice(0, 512) : undefined };
|
|
14
|
+
if (typeof url !== 'string')
|
|
15
|
+
return ctx.result('partial', { ...metadata, content: 'not_checked', requesterView: 'not_checked' }, [id]);
|
|
16
|
+
const exported = await ctx.download(url);
|
|
17
|
+
ctx.checkCurrent();
|
|
18
|
+
if (!await fileAccess(ctx, 'canvas', id, false))
|
|
19
|
+
return ctx.fail('resource_requester_access_denied', 403, [id]);
|
|
20
|
+
// The file endpoint supplies no documented completeness/version receipt for Canvas.
|
|
21
|
+
// A bounded supported export may be displayed, but is never labelled a full snapshot.
|
|
22
|
+
const mime = exported.contentType.split(';')[0]?.trim().toLowerCase();
|
|
23
|
+
if (!['text/markdown', 'text/plain'].includes(mime ?? '') || Buffer.byteLength(exported.content) > 1048576) {
|
|
24
|
+
return ctx.result('partial', { ...metadata, content: 'not_checked', export: 'unsupported_format', requesterView: 'not_checked' }, [id]);
|
|
25
|
+
}
|
|
26
|
+
return ctx.result('partial', { ...metadata, content: 'partial', exportText: redactOutboundText(exported.content).slice(0, 8000),
|
|
27
|
+
exportTruncated: exported.content.length > 8000, ...(expected !== undefined ? { exportMatchesRequested: exported.content === expected } : {}), requesterView: 'not_checked' }, [id]);
|
|
28
|
+
}
|
|
29
|
+
export const canvasActions = [
|
|
30
|
+
defineAction({ operation: 'canvas.create', scopes: ['canvases:write', ...aclScopes], methods: ['canvases.create', 'canvases.access.set', ...aclMethods], mutates: true,
|
|
31
|
+
parse(raw) { return { ...baseAction(raw, ['title', 'markdown'], true), title: requiredText(raw['title'], 256), markdown: redactOutboundText(requiredText(raw['markdown'], 64000)) }; },
|
|
32
|
+
async execute(ctx, args) {
|
|
33
|
+
const ids = [];
|
|
34
|
+
return preserve(ctx, ids, async () => {
|
|
35
|
+
const direct = args.channel.startsWith('D');
|
|
36
|
+
if (args.channel !== ctx.channel)
|
|
37
|
+
return ctx.fail('canvas_destination_mismatch', 403);
|
|
38
|
+
if (direct && (ctx.operator || !/^[UW][A-Z0-9]+$/.test(ctx.actor)))
|
|
39
|
+
return ctx.fail('canvas_requester_identity_required', 403);
|
|
40
|
+
ctx.checkCurrent();
|
|
41
|
+
const created = await ctx.api('canvases.create', { title: redactOutboundText(args.title), document_content: { type: 'markdown', markdown: args.markdown }, ...(direct ? {} : { channel_id: args.channel }) });
|
|
42
|
+
const id = responseId(created.data?.['canvas_id']);
|
|
43
|
+
if (id) {
|
|
44
|
+
ids.push(id);
|
|
45
|
+
ctx.remember('canvas', id);
|
|
46
|
+
}
|
|
47
|
+
ctx.checkCurrent();
|
|
48
|
+
if (!created.ok || !id) {
|
|
49
|
+
if (ids.length)
|
|
50
|
+
return acknowledgedFailure(ctx, ids, 'create_unconfirmed');
|
|
51
|
+
if (['free_teams_cannot_create_standalone_canvases', 'free_teams_cannot_create_non_tabbed_canvases', 'invalid_arguments', 'canvas_disabled_user_team', 'missing_scope'].includes(created.error ?? ''))
|
|
52
|
+
return ctx.fail(created.error, created.status ?? 400);
|
|
53
|
+
return ctx.result('unknown', { creation: 'unconfirmed' });
|
|
54
|
+
}
|
|
55
|
+
let sharing = 'not_requested';
|
|
56
|
+
if (direct) {
|
|
57
|
+
// Slack may require prior direct sharing; failure remains partial, never a wider share fallback.
|
|
58
|
+
const shared = await ctx.api('canvases.access.set', { canvas_id: id, access_level: 'write', user_ids: [ctx.actor] });
|
|
59
|
+
ctx.checkCurrent();
|
|
60
|
+
if (!shared.ok)
|
|
61
|
+
return acknowledgedFailure(ctx, ids, 'canvas_sharing_unconfirmed');
|
|
62
|
+
sharing = 'acknowledged';
|
|
63
|
+
if (!await fileAccess(ctx, 'canvas', id, true))
|
|
64
|
+
return acknowledgedFailure(ctx, ids, 'requester_write_unverified');
|
|
65
|
+
}
|
|
66
|
+
const read = await readCanvas(ctx, id, args.markdown);
|
|
67
|
+
if (!read.ok)
|
|
68
|
+
return acknowledgedFailure(ctx, ids, 'requester_visibility_unverified');
|
|
69
|
+
return ctx.result('partial', { creation: 'acknowledged', sharing, readback: read.data, requesterView: 'not_checked' }, ids);
|
|
70
|
+
});
|
|
71
|
+
} }),
|
|
72
|
+
defineAction({ operation: 'canvas.read', scopes: aclScopes, methods: aclMethods, mutates: false,
|
|
73
|
+
parse(raw) { return { ...baseAction(raw, ['canvasId'], false), canvasId: opaqueId(raw['canvasId']) }; },
|
|
74
|
+
execute(ctx, args) { return preserve(ctx, [], () => readCanvas(ctx, args.canvasId)); } }),
|
|
75
|
+
defineAction({ operation: 'canvas.edit', scopes: ['canvases:write', ...aclScopes], methods: ['canvases.edit', ...aclMethods], mutates: true,
|
|
76
|
+
parse(raw) {
|
|
77
|
+
const base = baseAction(raw, ['canvasId', 'mode', 'markdown', 'sectionId', 'replaceAll'], true);
|
|
78
|
+
const mode = enumValue(raw['mode'], ['append', 'replace']);
|
|
79
|
+
const sectionId = raw['sectionId'] === undefined ? undefined : opaqueId(raw['sectionId']);
|
|
80
|
+
const replaceAll = raw['replaceAll'] === undefined ? false : raw['replaceAll'];
|
|
81
|
+
if (typeof replaceAll !== 'boolean' || (mode === 'append' && (sectionId || replaceAll))
|
|
82
|
+
|| (mode === 'replace' && (!!sectionId === replaceAll))) {
|
|
83
|
+
throw slackToolDenied('invalid_canvas_edit', 400);
|
|
84
|
+
}
|
|
85
|
+
return { ...base, canvasId: opaqueId(raw['canvasId']), mode, sectionId, replaceAll, markdown: redactOutboundText(requiredText(raw['markdown'], 64000)) };
|
|
86
|
+
},
|
|
87
|
+
async execute(ctx, args) {
|
|
88
|
+
const ids = [];
|
|
89
|
+
return preserve(ctx, ids, async () => {
|
|
90
|
+
if (!await fileAccess(ctx, 'canvas', args.canvasId, true))
|
|
91
|
+
return ctx.fail('resource_requester_write_denied', 403);
|
|
92
|
+
ctx.checkCurrent();
|
|
93
|
+
ids.push(args.canvasId);
|
|
94
|
+
const edited = await ctx.api('canvases.edit', { canvas_id: args.canvasId, changes: [{ operation: args.mode === 'append' ? 'insert_at_end' : 'replace',
|
|
95
|
+
document_content: { type: 'markdown', markdown: args.markdown }, ...(args.sectionId ? { section_id: args.sectionId } : {}) }] }, async () => {
|
|
96
|
+
if (!await fileAccess(ctx, 'canvas', args.canvasId, true))
|
|
97
|
+
throw slackToolDenied('resource_requester_write_denied', 403);
|
|
98
|
+
ctx.checkCurrent();
|
|
99
|
+
});
|
|
100
|
+
ctx.checkCurrent();
|
|
101
|
+
if (!edited.ok)
|
|
102
|
+
return ctx.result('unknown', { edit: 'unconfirmed' }, ids);
|
|
103
|
+
const read = await readCanvas(ctx, args.canvasId, args.replaceAll ? args.markdown : undefined);
|
|
104
|
+
return read.ok ? ctx.result('partial', { edit: 'acknowledged', readback: read.data, requesterView: 'not_checked' }, ids) : acknowledgedFailure(ctx, ids, 'readback_unavailable');
|
|
105
|
+
});
|
|
106
|
+
} }),
|
|
107
|
+
];
|
|
108
|
+
//# sourceMappingURL=actions-canvas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions-canvas.js","sourceRoot":"","sources":["../../../src/slack/actions-canvas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { defineAction } from './action-types.js';
|
|
2
|
+
import { baseAction, messageTs, opaqueId, requiredText, optionalText } from './task-input.js';
|
|
3
|
+
import { redactChannelSecrets } from '../messaging/redact.js';
|
|
4
|
+
import { slackToolDenied } from './tool-access.js';
|
|
5
|
+
function safeLink(value) {
|
|
6
|
+
const link = requiredText(value, 2048);
|
|
7
|
+
let url;
|
|
8
|
+
try {
|
|
9
|
+
url = new URL(link);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw slackToolDenied('slack_link_invalid', 400);
|
|
13
|
+
}
|
|
14
|
+
if (url.protocol !== 'https:' || url.username || url.password || redactChannelSecrets(link) !== link)
|
|
15
|
+
throw slackToolDenied('slack_link_unsafe', 400);
|
|
16
|
+
return link;
|
|
17
|
+
}
|
|
18
|
+
export const channelActions = [];
|
|
19
|
+
for (const operation of ['pin.add', 'pin.remove', 'pin.list']) {
|
|
20
|
+
const mutates = operation !== 'pin.list';
|
|
21
|
+
channelActions.push(defineAction({ operation, scopes: mutates ? ['pins:write', 'pins:read'] : ['pins:read'],
|
|
22
|
+
methods: mutates ? [operation === 'pin.add' ? 'pins.add' : 'pins.remove', 'pins.list'] : ['pins.list'], mutates,
|
|
23
|
+
parse(raw) { return { ...baseAction(raw, mutates ? ['ts'] : [], mutates), ...(mutates ? { ts: messageTs(raw['ts']) } : {}) }; },
|
|
24
|
+
async execute(ctx, args) {
|
|
25
|
+
if (mutates) {
|
|
26
|
+
const changed = await ctx.api(operation === 'pin.add' ? 'pins.add' : 'pins.remove', { channel: args.channel, timestamp: args.ts });
|
|
27
|
+
const converged = operation === 'pin.add' ? changed.error === 'already_pinned' : changed.error === 'not_pinned';
|
|
28
|
+
if (!changed.ok && !converged)
|
|
29
|
+
return ctx.fail(changed.error ?? 'slack_pin_failed', changed.status);
|
|
30
|
+
}
|
|
31
|
+
const read = await ctx.api('pins.list', { channel: args.channel });
|
|
32
|
+
if (!read.ok || !Array.isArray(read.data?.items) || read.data.items.length > 1000)
|
|
33
|
+
return ctx.fail('slack_pins_readback_failed', 502, mutates ? [args.ts] : []);
|
|
34
|
+
if (read.data.items.some(item => item.channel && item.channel !== args.channel))
|
|
35
|
+
return ctx.fail('slack_pins_target_mismatch', 502, mutates ? [args.ts] : []);
|
|
36
|
+
const items = read.data.items.filter(item => item.type === 'message' && typeof item.message?.ts === 'string').map(item => ({ ts: item.message.ts, text: item.message?.text ?? '', contentExcluded: item.message?.contentExcluded === true }));
|
|
37
|
+
if (mutates && items.some(item => item.ts === args.ts) !== (operation === 'pin.add'))
|
|
38
|
+
return ctx.fail('slack_pin_state_mismatch', 409, [args.ts]);
|
|
39
|
+
return ctx.result(read.data.items.length !== items.length ? 'partial' : 'verified', { items, scope: 'conversation' }, mutates ? [args.ts] : []);
|
|
40
|
+
},
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
for (const operation of ['bookmark.add', 'bookmark.edit', 'bookmark.remove', 'bookmark.list']) {
|
|
44
|
+
const mutates = operation !== 'bookmark.list';
|
|
45
|
+
channelActions.push(defineAction({ operation, scopes: mutates ? ['bookmarks:write', 'bookmarks:read'] : ['bookmarks:read'],
|
|
46
|
+
methods: mutates ? [operation.replace('bookmark.', 'bookmarks.'), 'bookmarks.list'] : ['bookmarks.list'], mutates,
|
|
47
|
+
parse(raw) {
|
|
48
|
+
const allowed = operation === 'bookmark.add' ? ['title', 'link', 'emoji'] : operation === 'bookmark.edit' ? ['bookmarkId', 'title', 'link', 'emoji'] : operation === 'bookmark.remove' ? ['bookmarkId'] : [];
|
|
49
|
+
const base = baseAction(raw, allowed, mutates);
|
|
50
|
+
const title = operation === 'bookmark.add' ? requiredText(raw['title'], 100) : optionalText(raw['title'], 100);
|
|
51
|
+
const link = raw['link'] !== undefined || operation === 'bookmark.add' ? safeLink(raw['link']) : undefined;
|
|
52
|
+
const emoji = optionalText(raw['emoji'], 100);
|
|
53
|
+
if (operation === 'bookmark.edit' && title === undefined && link === undefined && emoji === undefined)
|
|
54
|
+
throw slackToolDenied('slack_bookmark_edit_empty', 400);
|
|
55
|
+
return { ...base, ...(title !== undefined ? { title: redactChannelSecrets(title) } : {}), ...(link ? { link } : {}), ...(emoji ? { emoji } : {}),
|
|
56
|
+
...(['bookmark.edit', 'bookmark.remove'].includes(operation) ? { bookmarkId: opaqueId(raw['bookmarkId']) } : {}) };
|
|
57
|
+
},
|
|
58
|
+
async execute(ctx, args) {
|
|
59
|
+
let id = args.bookmarkId;
|
|
60
|
+
if (mutates) {
|
|
61
|
+
const changed = await ctx.api(operation.replace('bookmark.', 'bookmarks.'), { channel_id: args.channel,
|
|
62
|
+
...(id ? { bookmark_id: id } : {}), ...(operation === 'bookmark.add' ? { type: 'link' } : {}),
|
|
63
|
+
...(args.title !== undefined ? { title: args.title } : {}), ...(args.link ? { link: args.link } : {}), ...(args.emoji ? { emoji: args.emoji } : {}) });
|
|
64
|
+
if (!changed.ok)
|
|
65
|
+
return ctx.fail(changed.error ?? 'slack_bookmark_failed', changed.status, id ? [id] : []);
|
|
66
|
+
if (operation === 'bookmark.add') {
|
|
67
|
+
id = changed.data?.bookmark?.id;
|
|
68
|
+
if (!id || changed.data?.bookmark?.channel_id !== args.channel)
|
|
69
|
+
return ctx.fail('slack_bookmark_id_unverified');
|
|
70
|
+
ctx.remember('bookmark', id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const read = await ctx.api('bookmarks.list', { channel_id: args.channel });
|
|
74
|
+
if (!read.ok || !Array.isArray(read.data?.bookmarks) || read.data.bookmarks.length > 100)
|
|
75
|
+
return ctx.fail('slack_bookmark_readback_failed', 502, id ? [id] : []);
|
|
76
|
+
if (read.data.bookmarks.some(bookmark => bookmark.channel_id !== args.channel || typeof bookmark.id !== 'string')
|
|
77
|
+
|| new Set(read.data.bookmarks.map(bookmark => bookmark.id)).size !== read.data.bookmarks.length)
|
|
78
|
+
return ctx.fail('slack_bookmark_response_invalid', 502, id ? [id] : []);
|
|
79
|
+
const bookmark = read.data.bookmarks.find(item => item.id === id);
|
|
80
|
+
if (operation === 'bookmark.remove' && bookmark)
|
|
81
|
+
return ctx.fail('slack_bookmark_still_present', 409, [id]);
|
|
82
|
+
if ((operation === 'bookmark.add' || operation === 'bookmark.edit') && (!bookmark || bookmark.type !== 'link' || (args.title !== undefined && bookmark.title !== args.title) || (args.link !== undefined && bookmark.link !== args.link) || (args.emoji !== undefined && bookmark.emoji !== args.emoji)))
|
|
83
|
+
return ctx.fail('slack_bookmark_content_mismatch', 409, id ? [id] : []);
|
|
84
|
+
return ctx.result('verified', { bookmarks: read.data.bookmarks.map(item => ({ id: item.id, title: item.title, link: item.link, type: item.type })) }, id ? [id] : []);
|
|
85
|
+
},
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=actions-channel.js.map
|