@pinet/slack-bridge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +570 -0
  3. package/dist/activity-log.d.ts +62 -0
  4. package/dist/activity-log.js +293 -0
  5. package/dist/agent-completion-runtime.d.ts +17 -0
  6. package/dist/agent-completion-runtime.js +26 -0
  7. package/dist/agent-event-runtime.d.ts +13 -0
  8. package/dist/agent-event-runtime.js +27 -0
  9. package/dist/agent-prompt-guidance.d.ts +22 -0
  10. package/dist/agent-prompt-guidance.js +46 -0
  11. package/dist/broker/adapters/slack.d.ts +74 -0
  12. package/dist/broker/adapters/slack.js +563 -0
  13. package/dist/broker/adapters/types.d.ts +1 -0
  14. package/dist/broker/adapters/types.js +1 -0
  15. package/dist/broker/agent-messaging.d.ts +1 -0
  16. package/dist/broker/agent-messaging.js +1 -0
  17. package/dist/broker/auth.d.ts +1 -0
  18. package/dist/broker/auth.js +1 -0
  19. package/dist/broker/client.d.ts +167 -0
  20. package/dist/broker/client.js +624 -0
  21. package/dist/broker/control-plane-dashboard.d.ts +98 -0
  22. package/dist/broker/control-plane-dashboard.js +213 -0
  23. package/dist/broker/ghost-reaper.d.ts +49 -0
  24. package/dist/broker/ghost-reaper.js +209 -0
  25. package/dist/broker/index.d.ts +36 -0
  26. package/dist/broker/index.js +90 -0
  27. package/dist/broker/leader.d.ts +1 -0
  28. package/dist/broker/leader.js +1 -0
  29. package/dist/broker/maintenance.d.ts +1 -0
  30. package/dist/broker/maintenance.js +1 -0
  31. package/dist/broker/message-send.d.ts +1 -0
  32. package/dist/broker/message-send.js +1 -0
  33. package/dist/broker/paths.d.ts +1 -0
  34. package/dist/broker/paths.js +1 -0
  35. package/dist/broker/raw-tcp-loopback.d.ts +1 -0
  36. package/dist/broker/raw-tcp-loopback.js +1 -0
  37. package/dist/broker/router.d.ts +1 -0
  38. package/dist/broker/router.js +1 -0
  39. package/dist/broker/schema.d.ts +9 -0
  40. package/dist/broker/schema.js +63 -0
  41. package/dist/broker/socket-server.d.ts +120 -0
  42. package/dist/broker/socket-server.js +1087 -0
  43. package/dist/broker/types.d.ts +1 -0
  44. package/dist/broker/types.js +1 -0
  45. package/dist/broker-delivery.d.ts +10 -0
  46. package/dist/broker-delivery.js +26 -0
  47. package/dist/broker-inbound-persistence.d.ts +11 -0
  48. package/dist/broker-inbound-persistence.js +22 -0
  49. package/dist/broker-prompt-loader.d.ts +34 -0
  50. package/dist/broker-prompt-loader.js +185 -0
  51. package/dist/broker-runtime-access.d.ts +14 -0
  52. package/dist/broker-runtime-access.js +20 -0
  53. package/dist/broker-runtime.d.ts +100 -0
  54. package/dist/broker-runtime.js +533 -0
  55. package/dist/broker-thread-owner-hints.d.ts +10 -0
  56. package/dist/broker-thread-owner-hints.js +14 -0
  57. package/dist/canvases.d.ts +80 -0
  58. package/dist/canvases.js +221 -0
  59. package/dist/command-registration-runtime.d.ts +9 -0
  60. package/dist/command-registration-runtime.js +9 -0
  61. package/dist/core-tool-guardrails.d.ts +24 -0
  62. package/dist/core-tool-guardrails.js +66 -0
  63. package/dist/deploy-manifest.d.ts +27 -0
  64. package/dist/deploy-manifest.js +197 -0
  65. package/dist/follower-delivery.d.ts +16 -0
  66. package/dist/follower-delivery.js +70 -0
  67. package/dist/follower-runtime.d.ts +61 -0
  68. package/dist/follower-runtime.js +350 -0
  69. package/dist/git-metadata.d.ts +35 -0
  70. package/dist/git-metadata.js +88 -0
  71. package/dist/guardrails.d.ts +69 -0
  72. package/dist/guardrails.js +283 -0
  73. package/dist/helpers.d.ts +550 -0
  74. package/dist/helpers.js +2711 -0
  75. package/dist/home-tab.d.ts +27 -0
  76. package/dist/home-tab.js +242 -0
  77. package/dist/imessage-tools.d.ts +33 -0
  78. package/dist/imessage-tools.js +96 -0
  79. package/dist/inbox-drain-runtime.d.ts +30 -0
  80. package/dist/inbox-drain-runtime.js +71 -0
  81. package/dist/index.d.ts +2 -0
  82. package/dist/index.js +1330 -0
  83. package/dist/persisted-runtime-state.d.ts +52 -0
  84. package/dist/persisted-runtime-state.js +98 -0
  85. package/dist/pinet-activity-formatting.d.ts +20 -0
  86. package/dist/pinet-activity-formatting.js +43 -0
  87. package/dist/pinet-agent-status.d.ts +36 -0
  88. package/dist/pinet-agent-status.js +48 -0
  89. package/dist/pinet-commands.d.ts +70 -0
  90. package/dist/pinet-commands.js +402 -0
  91. package/dist/pinet-confirmation-replies.d.ts +7 -0
  92. package/dist/pinet-confirmation-replies.js +30 -0
  93. package/dist/pinet-control-plane-dashboard.d.ts +34 -0
  94. package/dist/pinet-control-plane-dashboard.js +86 -0
  95. package/dist/pinet-home-tabs.d.ts +36 -0
  96. package/dist/pinet-home-tabs.js +101 -0
  97. package/dist/pinet-maintenance-delivery.d.ts +22 -0
  98. package/dist/pinet-maintenance-delivery.js +45 -0
  99. package/dist/pinet-mesh-ops.d.ts +97 -0
  100. package/dist/pinet-mesh-ops.js +266 -0
  101. package/dist/pinet-registration-gate.d.ts +14 -0
  102. package/dist/pinet-registration-gate.js +42 -0
  103. package/dist/pinet-remote-control-acks.d.ts +16 -0
  104. package/dist/pinet-remote-control-acks.js +46 -0
  105. package/dist/pinet-remote-control.d.ts +17 -0
  106. package/dist/pinet-remote-control.js +74 -0
  107. package/dist/pinet-runtime-composition.d.ts +27 -0
  108. package/dist/pinet-runtime-composition.js +20 -0
  109. package/dist/pinet-tools.d.ts +67 -0
  110. package/dist/pinet-tools.js +1211 -0
  111. package/dist/prompts/broker/default.md +41 -0
  112. package/dist/prompts/broker/tmux.md +49 -0
  113. package/dist/ralph-loop.d.ts +76 -0
  114. package/dist/ralph-loop.js +524 -0
  115. package/dist/reaction-triggers.d.ts +25 -0
  116. package/dist/reaction-triggers.js +171 -0
  117. package/dist/repo-tool-guardrails.d.ts +20 -0
  118. package/dist/repo-tool-guardrails.js +81 -0
  119. package/dist/runtime-agent-context.d.ts +93 -0
  120. package/dist/runtime-agent-context.js +302 -0
  121. package/dist/runtime-mode.d.ts +10 -0
  122. package/dist/runtime-mode.js +39 -0
  123. package/dist/scheduled-wakeups.d.ts +1 -0
  124. package/dist/scheduled-wakeups.js +1 -0
  125. package/dist/session-ui-runtime.d.ts +20 -0
  126. package/dist/session-ui-runtime.js +163 -0
  127. package/dist/single-player-runtime.d.ts +71 -0
  128. package/dist/single-player-runtime.js +436 -0
  129. package/dist/skins/cosmere.json +1571 -0
  130. package/dist/skins/foundation.json +1304 -0
  131. package/dist/slack-access.d.ts +186 -0
  132. package/dist/slack-access.js +462 -0
  133. package/dist/slack-api.d.ts +2 -0
  134. package/dist/slack-api.js +1 -0
  135. package/dist/slack-block-kit.d.ts +36 -0
  136. package/dist/slack-block-kit.js +242 -0
  137. package/dist/slack-export.d.ts +31 -0
  138. package/dist/slack-export.js +206 -0
  139. package/dist/slack-message-context.d.ts +15 -0
  140. package/dist/slack-message-context.js +207 -0
  141. package/dist/slack-modals.d.ts +13 -0
  142. package/dist/slack-modals.js +79 -0
  143. package/dist/slack-pinet-runtime-adapter.d.ts +16 -0
  144. package/dist/slack-pinet-runtime-adapter.js +72 -0
  145. package/dist/slack-presence.d.ts +36 -0
  146. package/dist/slack-presence.js +89 -0
  147. package/dist/slack-request-runtime.d.ts +8 -0
  148. package/dist/slack-request-runtime.js +19 -0
  149. package/dist/slack-runtime-access.d.ts +28 -0
  150. package/dist/slack-runtime-access.js +107 -0
  151. package/dist/slack-scope-diagnostics.d.ts +31 -0
  152. package/dist/slack-scope-diagnostics.js +235 -0
  153. package/dist/slack-socket-dedup.d.ts +7 -0
  154. package/dist/slack-socket-dedup.js +135 -0
  155. package/dist/slack-thread-status.d.ts +41 -0
  156. package/dist/slack-thread-status.js +156 -0
  157. package/dist/slack-tool-policy-runtime.d.ts +36 -0
  158. package/dist/slack-tool-policy-runtime.js +96 -0
  159. package/dist/slack-tools.d.ts +52 -0
  160. package/dist/slack-tools.js +2688 -0
  161. package/dist/slack-turn-guardrails.d.ts +19 -0
  162. package/dist/slack-turn-guardrails.js +36 -0
  163. package/dist/slack-upload.d.ts +49 -0
  164. package/dist/slack-upload.js +224 -0
  165. package/dist/task-assignments.d.ts +45 -0
  166. package/dist/task-assignments.js +527 -0
  167. package/dist/thread-confirmations.d.ts +22 -0
  168. package/dist/thread-confirmations.js +139 -0
  169. package/dist/tool-registration-runtime.d.ts +13 -0
  170. package/dist/tool-registration-runtime.js +13 -0
  171. package/dist/ttl-cache.d.ts +47 -0
  172. package/dist/ttl-cache.js +105 -0
  173. package/manifest.yaml +57 -0
  174. package/package.json +60 -0
  175. package/skills/pinet-skin-creator/SKILL.md +109 -0
  176. package/skills/pinet-skin-creator/references/descriptor-format.md +99 -0
  177. package/skills/pinet-skin-creator/references/safety-checklist.md +56 -0
  178. package/skills/pinet-skin-creator/templates/pinet-skin-descriptor.json +77 -0
  179. package/skills/slack-bridge/SKILL.md +360 -0
@@ -0,0 +1,39 @@
1
+ export function normalizeSlackBridgeRuntimeMode(value) {
2
+ const normalized = value?.trim().toLowerCase();
3
+ if (normalized === "off" ||
4
+ normalized === "single" ||
5
+ normalized === "broker" ||
6
+ normalized === "follower") {
7
+ return normalized;
8
+ }
9
+ return null;
10
+ }
11
+ export function isPinetRuntimeMode(mode) {
12
+ return mode === "broker" || mode === "follower";
13
+ }
14
+ export function isBrokerManagedFollowerLaunch(env = process.env) {
15
+ return env.PINET_BROKER_MANAGED === "1" && env.PINET_LAUNCH_SOURCE === "broker-tmux";
16
+ }
17
+ export function resolveSlackBridgeStartupRuntimeMode(settings, options = {}) {
18
+ const explicitMode = normalizeSlackBridgeRuntimeMode(settings.runtimeMode);
19
+ const brokerSocketExists = options.brokerSocketExists ?? true;
20
+ if (options.brokerManagedFollowerLaunch) {
21
+ if (explicitMode === "follower" || (!explicitMode && settings.autoFollow)) {
22
+ return brokerSocketExists ? "follower" : "off";
23
+ }
24
+ return "off";
25
+ }
26
+ if (explicitMode) {
27
+ if (explicitMode === "follower" && !brokerSocketExists) {
28
+ return "off";
29
+ }
30
+ return explicitMode;
31
+ }
32
+ if (settings.autoFollow) {
33
+ return brokerSocketExists ? "follower" : "off";
34
+ }
35
+ if (settings.autoConnect) {
36
+ return "single";
37
+ }
38
+ return "off";
39
+ }
@@ -0,0 +1 @@
1
+ export { buildScheduledWakeupThreadId, parseScheduledWakeupDelay, resolveScheduledWakeupFireAt, type ScheduledWakeupInput, } from "@pinet/pinet-core/scheduled-wakeups";
@@ -0,0 +1 @@
1
+ export { buildScheduledWakeupThreadId, parseScheduledWakeupDelay, resolveScheduledWakeupFireAt, } from "@pinet/pinet-core/scheduled-wakeups";
@@ -0,0 +1,20 @@
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ export type SessionUiStatusState = "ok" | "reconnecting" | "error" | "off";
3
+ export interface SessionUiRuntimeDeps {
4
+ getAgentName: () => string;
5
+ getAgentEmoji: () => string;
6
+ getInboxLength: () => number;
7
+ drainInbox: () => void;
8
+ }
9
+ export interface SessionUiRuntime {
10
+ getExtensionContext: () => ExtensionContext | null;
11
+ setExtCtx: (ctx: ExtensionContext) => void;
12
+ updateBadge: () => void;
13
+ setExtStatus: (ctx: ExtensionContext, state: SessionUiStatusState) => void;
14
+ notePotentialInterruptInput: (data: string) => void;
15
+ shouldSuppressAutomaticInboxDrain: (now?: number) => boolean;
16
+ maybeDrainInboxIfIdle: (ctx?: ExtensionContext) => boolean;
17
+ prepareForSessionStart: (ctx: ExtensionContext) => void;
18
+ cleanupForSessionShutdown: () => void;
19
+ }
20
+ export declare function createSessionUiRuntime(deps: SessionUiRuntimeDeps): SessionUiRuntime;
@@ -0,0 +1,163 @@
1
+ const AUTO_DRAIN_INTERRUPT_SUPPRESSION_MS = 1_500;
2
+ const AUTO_DRAIN_IDLE_RETRY_MS = 250;
3
+ const ESCAPE_SEQUENCE = "\u001b";
4
+ const ESCAPE_CODEPOINT = 27;
5
+ const KITTY_LOCK_MODIFIER_MASK = 64 + 128; // Caps Lock + Num Lock.
6
+ function isUnmodifiedEscapeInput(data) {
7
+ // Pi enables Kitty keyboard protocol or xterm modifyOtherKeys when available, so
8
+ // plain Escape may arrive as an encoded key event rather than a raw ESC byte.
9
+ if (data === ESCAPE_SEQUENCE) {
10
+ return true;
11
+ }
12
+ return isUnmodifiedKittyEscapeInput(data) || isUnmodifiedModifyOtherKeysEscapeInput(data);
13
+ }
14
+ function isUnmodifiedKittyEscapeInput(data) {
15
+ if (!data.startsWith(`${ESCAPE_SEQUENCE}[`) || !data.endsWith("u")) {
16
+ return false;
17
+ }
18
+ const body = data.slice(2, -1);
19
+ const [codepointWithAlternateKeys, modifierWithEventType, ...extraParts] = body.split(";");
20
+ if (!codepointWithAlternateKeys || extraParts.length > 0) {
21
+ return false;
22
+ }
23
+ const codepoint = Number.parseInt(codepointWithAlternateKeys.split(":")[0] ?? "", 10);
24
+ const modifierValue = Number.parseInt(modifierWithEventType?.split(":")[0] ?? "1", 10);
25
+ return (codepoint === ESCAPE_CODEPOINT &&
26
+ Number.isFinite(modifierValue) &&
27
+ ((modifierValue - 1) & ~KITTY_LOCK_MODIFIER_MASK) === 0);
28
+ }
29
+ function isUnmodifiedModifyOtherKeysEscapeInput(data) {
30
+ if (!data.startsWith(`${ESCAPE_SEQUENCE}[`) || !data.endsWith("~")) {
31
+ return false;
32
+ }
33
+ const body = data.slice(2, -1);
34
+ const [prefix, modifier, codepoint, ...extraParts] = body.split(";");
35
+ if (prefix !== "27" || codepoint !== "27" || extraParts.length > 0) {
36
+ return false;
37
+ }
38
+ const modifierValue = Number.parseInt(modifier ?? "", 10);
39
+ return Number.isFinite(modifierValue) && ((modifierValue - 1) & ~KITTY_LOCK_MODIFIER_MASK) === 0;
40
+ }
41
+ export function createSessionUiRuntime(deps) {
42
+ let suppressAutoDrainUntil = 0;
43
+ let terminalInputUnsubscribe = null;
44
+ let deferredDrainTimer = null;
45
+ let extCtx = null;
46
+ function getExtensionContext() {
47
+ return extCtx;
48
+ }
49
+ function setExtCtx(ctx) {
50
+ extCtx = ctx;
51
+ }
52
+ function updateBadge() {
53
+ if (!extCtx?.hasUI)
54
+ return;
55
+ const t = extCtx.ui.theme;
56
+ const n = deps.getInboxLength();
57
+ const label = n > 0
58
+ ? t.fg("accent", `${deps.getAgentEmoji()} ${deps.getAgentName()} ✦ ${n}`)
59
+ : t.fg("accent", `${deps.getAgentEmoji()} ${deps.getAgentName()} ✦`);
60
+ extCtx.ui.setStatus("slack-bridge", label);
61
+ }
62
+ function setExtStatus(ctx, state) {
63
+ if (!ctx.hasUI)
64
+ return;
65
+ extCtx = ctx;
66
+ const t = ctx.ui.theme;
67
+ if (state === "ok") {
68
+ updateBadge();
69
+ return;
70
+ }
71
+ const text = state === "reconnecting"
72
+ ? t.fg("warning", `${deps.getAgentEmoji()} ${deps.getAgentName()} ⟳`)
73
+ : state === "error"
74
+ ? t.fg("error", `${deps.getAgentEmoji()} ${deps.getAgentName()} ✗`)
75
+ : "";
76
+ ctx.ui.setStatus("slack-bridge", text);
77
+ }
78
+ function notePotentialInterruptInput(data) {
79
+ if (!isUnmodifiedEscapeInput(data)) {
80
+ return;
81
+ }
82
+ suppressAutoDrainUntil = Math.max(suppressAutoDrainUntil, Date.now() + AUTO_DRAIN_INTERRUPT_SUPPRESSION_MS);
83
+ }
84
+ function shouldSuppressAutomaticInboxDrain(now = Date.now()) {
85
+ if (suppressAutoDrainUntil === 0) {
86
+ return false;
87
+ }
88
+ if (now >= suppressAutoDrainUntil) {
89
+ suppressAutoDrainUntil = 0;
90
+ return false;
91
+ }
92
+ return true;
93
+ }
94
+ function clearDeferredDrainTimer() {
95
+ if (!deferredDrainTimer)
96
+ return;
97
+ clearTimeout(deferredDrainTimer);
98
+ deferredDrainTimer = null;
99
+ }
100
+ function scheduleDeferredDrain(ctx) {
101
+ extCtx = ctx;
102
+ if (deferredDrainTimer)
103
+ return;
104
+ deferredDrainTimer = setTimeout(() => {
105
+ deferredDrainTimer = null;
106
+ if (deps.getInboxLength() === 0)
107
+ return;
108
+ const latestCtx = extCtx;
109
+ if (!latestCtx)
110
+ return;
111
+ maybeDrainInboxIfIdle(latestCtx);
112
+ }, AUTO_DRAIN_IDLE_RETRY_MS);
113
+ deferredDrainTimer.unref?.();
114
+ }
115
+ function maybeDrainInboxIfIdle(ctx) {
116
+ if (ctx) {
117
+ extCtx = ctx;
118
+ }
119
+ const activeCtx = ctx ?? extCtx;
120
+ if (!(activeCtx?.isIdle?.() ?? false)) {
121
+ if (activeCtx && !shouldSuppressAutomaticInboxDrain() && deps.getInboxLength() > 0) {
122
+ scheduleDeferredDrain(activeCtx);
123
+ }
124
+ return false;
125
+ }
126
+ if (shouldSuppressAutomaticInboxDrain()) {
127
+ return false;
128
+ }
129
+ clearDeferredDrainTimer();
130
+ deps.drainInbox();
131
+ return true;
132
+ }
133
+ function prepareForSessionStart(ctx) {
134
+ suppressAutoDrainUntil = 0;
135
+ terminalInputUnsubscribe?.();
136
+ terminalInputUnsubscribe = null;
137
+ extCtx = ctx;
138
+ const uiWithTerminalInput = ctx.ui;
139
+ if (ctx.hasUI && typeof uiWithTerminalInput.onTerminalInput === "function") {
140
+ terminalInputUnsubscribe = uiWithTerminalInput.onTerminalInput((data) => {
141
+ notePotentialInterruptInput(data);
142
+ return undefined;
143
+ });
144
+ }
145
+ }
146
+ function cleanupForSessionShutdown() {
147
+ terminalInputUnsubscribe?.();
148
+ terminalInputUnsubscribe = null;
149
+ clearDeferredDrainTimer();
150
+ suppressAutoDrainUntil = 0;
151
+ }
152
+ return {
153
+ getExtensionContext,
154
+ setExtCtx,
155
+ updateBadge,
156
+ setExtStatus,
157
+ notePotentialInterruptInput,
158
+ shouldSuppressAutomaticInboxDrain,
159
+ maybeDrainInboxIfIdle,
160
+ prepareForSessionStart,
161
+ cleanupForSessionShutdown,
162
+ };
163
+ }
@@ -0,0 +1,71 @@
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import { type InboxMessage } from "./helpers.js";
3
+ import { type ReactionCommandTemplate } from "./reaction-triggers.js";
4
+ import type { SlackToolsThreadContextPort } from "./slack-tools.js";
5
+ import { type ParsedThreadStarted, type SlackAccessSet, type SlackCall } from "./slack-access.js";
6
+ export interface SinglePlayerThreadState {
7
+ channelId: string;
8
+ threadTs: string;
9
+ userId: string;
10
+ source?: string;
11
+ context?: ParsedThreadStarted["context"];
12
+ owner?: string;
13
+ }
14
+ export interface SinglePlayerPendingAttention {
15
+ channel: string;
16
+ messageTs: string;
17
+ }
18
+ export type SinglePlayerThreadInfo = SinglePlayerThreadState;
19
+ export type SinglePlayerPendingAttentionEntry = SinglePlayerPendingAttention;
20
+ export interface SinglePlayerUnclaimedThreads {
21
+ has: (threadTs: string) => boolean;
22
+ add: (threadTs: string) => void;
23
+ delete: (threadTs: string) => void;
24
+ }
25
+ export interface SinglePlayerRuntimeDeps {
26
+ slack: SlackCall;
27
+ getBotToken: () => string;
28
+ getAppToken: () => string;
29
+ dedup: SlackAccessSet<string>;
30
+ abortSlackRequests: () => Promise<void>;
31
+ isSingleRuntimeActive: () => boolean;
32
+ setExtStatus: (ctx: ExtensionContext, state: "ok" | "reconnecting" | "error" | "off") => void;
33
+ formatError: (error: unknown) => string;
34
+ getAgentName: () => string;
35
+ getAgentAliases: () => Iterable<string>;
36
+ getAgentOwnerToken: () => string;
37
+ getBotUserId: () => string | null;
38
+ getThreads: () => Map<string, SinglePlayerThreadState>;
39
+ getPendingEyes: () => Map<string, SinglePlayerPendingAttention[]>;
40
+ getUnclaimedThreads: () => SinglePlayerUnclaimedThreads;
41
+ pushInboxMessage: (message: InboxMessage) => void;
42
+ setLastDmChannel: (channelId: string | null) => void;
43
+ persistState: () => void;
44
+ updateBadge: () => void;
45
+ maybeDrainInboxIfIdle: (ctx: ExtensionContext) => boolean;
46
+ resolveThreadChannel: (threadTs: string | undefined) => Promise<string | null>;
47
+ setSuggestedPrompts: (channelId: string, threadTs: string) => Promise<void>;
48
+ publishCurrentPinetHomeTab: (userId: string, ctx: ExtensionContext) => Promise<void>;
49
+ fetchSlackMessageByTs: (channel: string, messageTs: string) => Promise<Record<string, unknown> | null>;
50
+ addReaction: (channel: string, ts: string, emoji: string) => Promise<void>;
51
+ removeReaction: (channel: string, ts: string, emoji: string) => Promise<void>;
52
+ resolveUser: (userId: string) => Promise<string>;
53
+ isUserAllowed: (userId: string) => boolean;
54
+ getReactionCommand: (reactionName: string) => ReactionCommandTemplate | undefined;
55
+ consumeConfirmationReply: (threadTs: string, text: string) => {
56
+ approved: boolean;
57
+ } | null;
58
+ claimOwnedThread: (threadTs: string, channelId: string, source?: string) => void;
59
+ beginThreadStatus?: (channelId: string, threadTs: string, status: string) => Promise<void>;
60
+ }
61
+ export interface SinglePlayerRuntime {
62
+ connect: (ctx: ExtensionContext) => Promise<void>;
63
+ disconnect: () => Promise<void>;
64
+ getBotUserId: () => string | null;
65
+ isConnected: () => boolean;
66
+ isShuttingDown: () => boolean;
67
+ resetShutdownState: () => void;
68
+ trackOwnedThread: (threadTs: string, channelId: string, source?: string) => void;
69
+ getThreadContextPort: () => SlackToolsThreadContextPort;
70
+ }
71
+ export declare function createSinglePlayerRuntime(deps: SinglePlayerRuntimeDeps): SinglePlayerRuntime;