@band-ai/sdk 0.1.6 → 0.2.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 (85) hide show
  1. package/README.md +372 -0
  2. package/dist/{ClaudeSDKAdapter-CRq4R-WB.d.cts → ClaudeSDKAdapter-BY4zEbCl.d.cts} +14 -10
  3. package/dist/{ClaudeSDKAdapter-BHOkjN3X.d.ts → ClaudeSDKAdapter-Cna5P1dR.d.ts} +14 -10
  4. package/dist/{acp-server-B1Da7L6u.d.ts → acp-server-CiUqN3G3.d.ts} +2 -2
  5. package/dist/{acp-server-BdRz9_UN.d.cts → acp-server-Dlj7D563.d.cts} +2 -2
  6. package/dist/adapters.cjs +734 -279
  7. package/dist/adapters.d.cts +21 -19
  8. package/dist/adapters.d.ts +21 -19
  9. package/dist/adapters.js +65 -44
  10. package/dist/backends-D-dBdDm-.d.ts +27 -0
  11. package/dist/backends-ZLxmQrTZ.d.cts +27 -0
  12. package/dist/{chunk-MSL6CWHY.js → chunk-4IAXZBXX.js} +77 -37
  13. package/dist/{chunk-SG4WLD2H.js → chunk-EAI2M3WM.js} +38 -94
  14. package/dist/{chunk-YR3BOQNW.js → chunk-JY75VSQK.js} +7 -7
  15. package/dist/{chunk-INA6YZTZ.js → chunk-LBWKISBS.js} +51 -31
  16. package/dist/{chunk-I5EZG52P.js → chunk-N2QTUMGO.js} +532 -327
  17. package/dist/{chunk-RHVH2GZR.js → chunk-NMZLX7TP.js} +110 -56
  18. package/dist/{chunk-EDPKUUJL.js → chunk-NT7TBFX2.js} +9 -1
  19. package/dist/{chunk-GVEQ3RAH.js → chunk-RV76SKFT.js} +169 -54
  20. package/dist/{chunk-W5NDZSYE.js → chunk-TLBCKDQO.js} +23 -23
  21. package/dist/chunk-US226AS4.js +130 -0
  22. package/dist/{chunk-IZPV6QS6.js → chunk-WL2HNJZ6.js} +38 -11
  23. package/dist/chunk-WLCM2OXG.js +181 -0
  24. package/dist/config.cjs +40 -13
  25. package/dist/config.d.cts +7 -1
  26. package/dist/config.d.ts +7 -1
  27. package/dist/config.js +2 -2
  28. package/dist/converters.cjs +491 -35
  29. package/dist/converters.d.cts +5 -5
  30. package/dist/converters.d.ts +5 -5
  31. package/dist/converters.js +4 -3
  32. package/dist/core.cjs +53 -10
  33. package/dist/core.d.cts +10 -9
  34. package/dist/core.d.ts +10 -9
  35. package/dist/core.js +8 -4
  36. package/dist/disconnectReason-IuADl6TH.d.cts +34 -0
  37. package/dist/disconnectReason-IuADl6TH.d.ts +34 -0
  38. package/dist/{dtos-DUpbIu8k.d.ts → dtos-B8KU_q4d.d.cts} +26 -6
  39. package/dist/{dtos-DUpbIu8k.d.cts → dtos-B8KU_q4d.d.ts} +26 -6
  40. package/dist/index.cjs +1510 -735
  41. package/dist/index.d.cts +18 -16
  42. package/dist/index.d.ts +18 -16
  43. package/dist/index.js +21 -13
  44. package/dist/linear.cjs +1044 -112
  45. package/dist/linear.d.cts +146 -16
  46. package/dist/linear.d.ts +146 -16
  47. package/dist/linear.js +1031 -110
  48. package/dist/mcp-claude.cjs +338 -66
  49. package/dist/mcp-claude.d.cts +3 -3
  50. package/dist/mcp-claude.d.ts +3 -3
  51. package/dist/mcp-claude.js +215 -16
  52. package/dist/mcp.cjs +414 -105
  53. package/dist/mcp.d.cts +29 -16
  54. package/dist/mcp.d.ts +29 -16
  55. package/dist/mcp.js +14 -14
  56. package/dist/{opencode-BBcDchcN.d.cts → opencode-2YdscIc1.d.cts} +5 -5
  57. package/dist/{opencode-DthQQUsZ.d.ts → opencode-Bld62x5t.d.ts} +5 -5
  58. package/dist/{pagination-CcDkVFxK.d.ts → pagination-BgEx-HeL.d.ts} +2 -2
  59. package/dist/{pagination-BPiys10t.d.cts → pagination-DqdkQArT.d.cts} +2 -2
  60. package/dist/{protocols-DrhzOH6K.d.ts → protocols-Bwwcql0h.d.ts} +1 -1
  61. package/dist/{protocols-CInhtFpA.d.cts → protocols-Bz1rxcUg.d.cts} +1 -1
  62. package/dist/rest.cjs +41 -97
  63. package/dist/rest.d.cts +7 -7
  64. package/dist/rest.d.ts +7 -7
  65. package/dist/rest.js +2 -2
  66. package/dist/runtime.cjs +998 -620
  67. package/dist/runtime.d.cts +22 -29
  68. package/dist/runtime.d.ts +22 -29
  69. package/dist/runtime.js +19 -67
  70. package/dist/{schemas-BpEBkq5V.d.cts → schemas-BotL3ZLH.d.cts} +51 -56
  71. package/dist/{schemas-vos1AaBc.d.ts → schemas-DBsC4J1g.d.ts} +51 -56
  72. package/dist/{sdk-CwTAxhwI.d.cts → sdk-BTciSLRQ.d.cts} +35 -5
  73. package/dist/{sdk-CcnQ5OUC.d.ts → sdk-qKJtMma_.d.ts} +35 -5
  74. package/dist/{simpleAdapter-9OE_p6QW.d.ts → simpleAdapter--wznuoOw.d.ts} +1 -1
  75. package/dist/{simpleAdapter-DqhvjsGr.d.cts → simpleAdapter-BpT4XbZC.d.cts} +1 -1
  76. package/dist/testing.d.cts +3 -3
  77. package/dist/testing.d.ts +3 -3
  78. package/dist/{types-7jVzOeOP.d.ts → types-BTN_ZETM.d.ts} +2 -2
  79. package/dist/{types-CxII3XkA.d.ts → types-BgYFd_Yw.d.cts} +5 -5
  80. package/dist/{types-CSHFipIc.d.cts → types-BivGO7I9.d.ts} +5 -5
  81. package/dist/{types-CovcHpYf.d.cts → types-D958TC71.d.cts} +2 -2
  82. package/package.json +25 -23
  83. package/dist/backends-CzDbiQar.d.ts +0 -20
  84. package/dist/backends-SVMT-7l4.d.cts +0 -20
  85. package/dist/chunk-SFVKOEQH.js +0 -103
package/dist/linear.d.cts CHANGED
@@ -1,12 +1,21 @@
1
1
  import { LinearClient, LinearDocument } from '@linear/sdk';
2
- import { R as RestApi } from './types-CSHFipIc.cjs';
3
- import { AgentSessionEventWebhookPayload } from '@linear/sdk/webhooks';
2
+ import { R as RestApi } from './types-BgYFd_Yw.cjs';
3
+ import { AppUserNotificationWebhookPayloadWithNotification, AgentSessionEventWebhookPayload, AppUserTeamAccessChangedWebhookPayload, OAuthAppWebhookPayload } from '@linear/sdk/webhooks';
4
4
  import { L as Logger } from './logger-CABQOnlR.cjs';
5
5
  import { C as CustomToolDef } from './customTools-BzF0IISO.cjs';
6
6
  import { IncomingMessage, ServerResponse } from 'node:http';
7
- import './dtos-DUpbIu8k.cjs';
7
+ import './dtos-B8KU_q4d.cjs';
8
8
  import 'zod';
9
9
 
10
+ interface CandidateRepositoryInput {
11
+ hostname: string;
12
+ repositoryFullName: string;
13
+ }
14
+ interface RepositorySuggestion {
15
+ repositoryFullName: string;
16
+ hostname?: string | null;
17
+ confidence: number;
18
+ }
10
19
  /**
11
20
  * Subset of `LinearClient` covering only the activity-reporting methods.
12
21
  */
@@ -14,7 +23,9 @@ interface LinearActivityClient {
14
23
  createAgentActivity(input: {
15
24
  agentSessionId: string;
16
25
  content: Record<string, unknown>;
26
+ ephemeral?: boolean;
17
27
  }): Promise<unknown>;
28
+ updateAgentSession?: (id: string, input: Record<string, unknown>) => Promise<unknown>;
18
29
  updateIssue?: (issueId: string, input: Record<string, unknown>) => Promise<unknown>;
19
30
  createComment?: (input: {
20
31
  issueId: string;
@@ -22,22 +33,81 @@ interface LinearActivityClient {
22
33
  }) => Promise<unknown>;
23
34
  issue?: (issueId: string) => Promise<unknown>;
24
35
  workflowStates?: (variables?: Record<string, unknown>) => Promise<unknown>;
36
+ issueRepositorySuggestions?: (candidateRepositories: CandidateRepositoryInput[], issueId: string, variables?: {
37
+ agentSessionId?: string | null;
38
+ }) => Promise<unknown>;
39
+ agentSessionUpdateExternalUrl?: (id: string, input: Record<string, unknown>) => Promise<unknown>;
40
+ /** Create an agent session on an existing Linear issue (proactive initiation). */
41
+ agentSessionCreateOnIssue?: (input: {
42
+ issueId: string;
43
+ externalLink?: string;
44
+ }) => Promise<unknown>;
45
+ /** Create an agent session on a specific comment thread (proactive initiation). */
46
+ agentSessionCreateOnComment?: (input: {
47
+ commentId: string;
48
+ externalLink?: string;
49
+ }) => Promise<unknown>;
50
+ /** Create a new Linear issue from scratch. */
51
+ createIssue?: (input: {
52
+ teamId: string;
53
+ title: string;
54
+ description?: string;
55
+ priority?: number;
56
+ assigneeId?: string;
57
+ stateId?: string;
58
+ labelIds?: string[];
59
+ }) => Promise<unknown>;
25
60
  }
26
61
  interface PlanStep {
27
62
  title: string;
28
63
  status: "pending" | "in_progress" | "completed" | "failed";
29
64
  }
30
- declare function postThought(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
31
- declare function postError(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
65
+ interface SelectOption {
66
+ label: string;
67
+ value: string;
68
+ }
69
+ /** Longest body string allowed in an elicitation activity. */
70
+ declare const ELICITATION_BODY_MAX_LENGTH = 10000;
71
+ /** Longest label or value string allowed in a select option. */
72
+ declare const SELECT_OPTION_MAX_LENGTH = 200;
73
+ /** Longest provider name string allowed in an auth elicitation. */
74
+ declare const PROVIDER_MAX_LENGTH = 100;
75
+ declare function postThought(client: LinearActivityClient, sessionId: string, body: string, options?: {
76
+ ephemeral?: boolean;
77
+ }): Promise<void>;
78
+ declare function postError(client: LinearActivityClient, sessionId: string, body: string, options?: {
79
+ ephemeral?: boolean;
80
+ }): Promise<void>;
32
81
  declare function postResponse(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
33
82
  declare function postElicitation(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
34
- declare function postAction(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
83
+ declare function postSelectElicitation(client: LinearActivityClient, sessionId: string, body: string, options: SelectOption[]): Promise<void>;
84
+ declare function postAuthElicitation(client: LinearActivityClient, sessionId: string, body: string, url: string, provider?: string): Promise<void>;
85
+ declare function postAction(client: LinearActivityClient, sessionId: string, body: string, options?: {
86
+ ephemeral?: boolean;
87
+ }): Promise<void>;
35
88
  declare function updatePlan(client: LinearActivityClient, sessionId: string, steps: PlanStep[]): Promise<void>;
36
89
 
90
+ interface HandleAppUserNotificationInput {
91
+ payload: AppUserNotificationWebhookPayloadWithNotification;
92
+ deps: LinearBandBridgeDeps;
93
+ logger: Logger;
94
+ /** The Linear app-user id from the webhook envelope; used to skip self-notifications. */
95
+ appUserId?: string;
96
+ }
97
+ declare function handleAppUserNotification(input: HandleAppUserNotificationInput): Promise<void>;
98
+
37
99
  type RoomStrategy = "issue" | "session";
38
100
  type WritebackMode = "final_only" | "activity_stream";
39
101
  type SessionStatus = "active" | "waiting" | "completed" | "canceled" | "errored";
40
- interface LinearThenvoiBridgeConfig {
102
+ /** Default interval (ms) between stale-session keepalive checks. */
103
+ declare const STALE_SESSION_CHECK_INTERVAL_MS: number;
104
+ /**
105
+ * Maximum age (ms) of the last Linear activity before a session is considered
106
+ * at risk of going stale. Linear marks sessions stale after 30 minutes of
107
+ * inactivity; we send a keepalive well before that threshold.
108
+ */
109
+ declare const STALE_SESSION_THRESHOLD_MS: number;
110
+ interface LinearBandBridgeConfig {
41
111
  linearAccessToken: string;
42
112
  linearWebhookSecret: string;
43
113
  roomStrategy?: RoomStrategy;
@@ -46,20 +116,23 @@ interface LinearThenvoiBridgeConfig {
46
116
  planningAgentHandles?: string[];
47
117
  implementationAgentHandles?: string[];
48
118
  recoveredRoomRetryBaseDelayMs?: number;
119
+ bandAppBaseUrl?: string;
49
120
  }
50
121
  interface SessionRoomRecord {
51
122
  linearSessionId: string;
52
123
  linearIssueId: string | null;
53
- thenvoiRoomId: string;
124
+ bandRoomId: string;
54
125
  status: SessionStatus;
55
126
  lastEventKey?: string | null;
127
+ /** ISO-8601 timestamp of the last activity sent to Linear for this session. */
128
+ lastLinearActivityAt?: string | null;
56
129
  createdAt: string;
57
130
  updatedAt: string;
58
131
  }
59
132
  interface PendingBootstrapRequest {
60
133
  eventKey: string;
61
134
  linearSessionId: string;
62
- thenvoiRoomId: string;
135
+ bandRoomId: string;
63
136
  expectedContent: string;
64
137
  messageType: string;
65
138
  senderId?: string | null;
@@ -76,18 +149,20 @@ interface SessionRoomStore {
76
149
  enqueueBootstrapRequest(request: PendingBootstrapRequest): Promise<void>;
77
150
  listPendingBootstrapRequests(limit?: number): Promise<PendingBootstrapRequest[]>;
78
151
  markBootstrapRequestProcessed(eventKey: string): Promise<void>;
152
+ /** List sessions with active or waiting status (used by stale-session keepalive). */
153
+ listActiveSessions?(): Promise<SessionRoomRecord[]>;
79
154
  close?(): Promise<void>;
80
155
  }
81
- interface LinearThenvoiBridgeDeps {
82
- thenvoiRest: RestApi;
156
+ interface LinearBandBridgeDeps {
157
+ bandRest: RestApi;
83
158
  linearClient: LinearClient;
84
159
  store: SessionRoomStore;
85
160
  logger?: Logger;
86
161
  }
87
162
  interface HandleAgentSessionEventInput {
88
163
  payload: AgentSessionEventWebhookPayload;
89
- config: LinearThenvoiBridgeConfig;
90
- deps: LinearThenvoiBridgeDeps;
164
+ config: LinearBandBridgeConfig;
165
+ deps: LinearBandBridgeDeps;
91
166
  }
92
167
 
93
168
  type LinearSessionStatus = SessionStatus;
@@ -120,6 +195,55 @@ declare function completeLinearSession(input: {
120
195
  lastEventKey?: string | null;
121
196
  }): Promise<void>;
122
197
 
198
+ interface StaleSessionGuardOptions {
199
+ store: SessionRoomStore;
200
+ linearClient: LinearActivityClient;
201
+ logger?: Logger;
202
+ /** Interval (ms) between keepalive checks. Defaults to 20 minutes. */
203
+ checkIntervalMs?: number;
204
+ /** Max age (ms) of last activity before sending a keepalive. Defaults to 25 minutes. */
205
+ staleThresholdMs?: number;
206
+ /** Message sent as a keepalive thought. */
207
+ keepAliveMessage?: string;
208
+ }
209
+ /**
210
+ * Periodically checks active Linear sessions and sends a keepalive activity
211
+ * to prevent Linear from marking them as stale (30-minute inactivity timeout).
212
+ */
213
+ declare class StaleSessionGuard {
214
+ private readonly store;
215
+ private readonly linearClient;
216
+ private readonly logger;
217
+ private readonly checkIntervalMs;
218
+ private readonly staleThresholdMs;
219
+ private readonly keepAliveMessage;
220
+ private timer;
221
+ constructor(options: StaleSessionGuardOptions);
222
+ /** Start the periodic keepalive check. Safe to call multiple times. */
223
+ start(): void;
224
+ /** Stop the periodic keepalive check. */
225
+ stop(): void;
226
+ /** Run a single keepalive check. Exposed for testing and manual invocation. */
227
+ tick(): Promise<number>;
228
+ }
229
+ /**
230
+ * Returns `true` when the session's last Linear activity is older than
231
+ * `thresholdMs`, meaning it risks being marked stale by Linear.
232
+ */
233
+ declare function isSessionStale(session: SessionRoomRecord, nowMs: number, thresholdMs: number): boolean;
234
+ /**
235
+ * Checks whether a session may have gone stale and sends a recovery activity
236
+ * before the main update. Call this before posting significant activities to
237
+ * a session that may have been idle for a long time.
238
+ */
239
+ declare function sendRecoveryActivityIfStale(input: {
240
+ session: SessionRoomRecord;
241
+ linearClient: LinearActivityClient;
242
+ store: SessionRoomStore;
243
+ logger: Logger;
244
+ staleThresholdMs?: number;
245
+ }): Promise<boolean>;
246
+
123
247
  declare function isLinearApiKey(token: string): boolean;
124
248
  declare function createLinearClient(token: string): LinearClient;
125
249
  declare function buildLinearAuthorizationHeader(token: string): string;
@@ -133,6 +257,7 @@ interface CreateLinearToolsOptions {
133
257
  client: LinearActivityClient;
134
258
  store?: SessionRoomStore;
135
259
  enableElicitation?: boolean;
260
+ logger?: Logger;
136
261
  }
137
262
  /**
138
263
  * Create Linear activity tools usable by any adapter via `customTools`.
@@ -149,10 +274,15 @@ interface LinearBridgeDispatcher {
149
274
  isQueued?(eventKey: string): boolean;
150
275
  waitForIdle?(): Promise<void>;
151
276
  }
277
+ interface PermissionChangeCallbacks {
278
+ onTeamAccessChanged?: (payload: AppUserTeamAccessChangedWebhookPayload) => void | Promise<void>;
279
+ onOAuthAppRevoked?: (payload: OAuthAppWebhookPayload) => void | Promise<void>;
280
+ }
152
281
  interface CreateLinearWebhookHandlerOptions {
153
- config: LinearThenvoiBridgeConfig;
154
- deps: LinearThenvoiBridgeDeps;
282
+ config: LinearBandBridgeConfig;
283
+ deps: LinearBandBridgeDeps;
155
284
  dispatcher?: LinearBridgeDispatcher;
285
+ permissionCallbacks?: PermissionChangeCallbacks;
156
286
  }
157
287
  declare function createInlineLinearBridgeDispatcher(options?: {
158
288
  logger?: Logger;
@@ -164,4 +294,4 @@ declare function createLinearWebhookHandler(options: CreateLinearWebhookHandlerO
164
294
 
165
295
  declare const DEFAULT_STATUS_MAPPING: Record<SessionStatus, LinearSessionStatus>;
166
296
 
167
- export { type CreateLinearWebhookHandlerOptions, DEFAULT_STATUS_MAPPING, type HandleAgentSessionEventInput, type LinearActivityClient, type LinearBridgeDispatchJob, type LinearBridgeDispatcher, type LinearBridgeRuntime, type LinearSessionStatus, type LinearThenvoiBridgeConfig, type LinearThenvoiBridgeDeps, type PendingBootstrapRequest, type PlanStep, type RoomStrategy, type SessionRoomRecord, type SessionRoomStore, type SessionStatus, type WritebackMode, buildLinearAuthorizationHeader, completeLinearSession, createInProcessLinearBridgeDispatcher, createInlineLinearBridgeDispatcher, createLinearBridgeRuntime, createLinearClient, createLinearTools, createLinearWebhookHandler, createSqliteSessionRoomStore, dedupeHandles, handleAgentSessionEvent, isLinearApiKey, postAction, postElicitation, postError, postResponse, postThought, stripHandlePrefix, updatePlan };
297
+ export { type CandidateRepositoryInput, type CreateLinearWebhookHandlerOptions, DEFAULT_STATUS_MAPPING, ELICITATION_BODY_MAX_LENGTH, type HandleAgentSessionEventInput, type HandleAppUserNotificationInput, type LinearActivityClient, type LinearBandBridgeConfig, type LinearBandBridgeDeps, type LinearBridgeDispatchJob, type LinearBridgeDispatcher, type LinearBridgeRuntime, type LinearSessionStatus, PROVIDER_MAX_LENGTH, type PendingBootstrapRequest, type PermissionChangeCallbacks, type PlanStep, type RepositorySuggestion, type RoomStrategy, SELECT_OPTION_MAX_LENGTH, STALE_SESSION_CHECK_INTERVAL_MS, STALE_SESSION_THRESHOLD_MS, type SelectOption, type SessionRoomRecord, type SessionRoomStore, type SessionStatus, StaleSessionGuard, type StaleSessionGuardOptions, type WritebackMode, buildLinearAuthorizationHeader, completeLinearSession, createInProcessLinearBridgeDispatcher, createInlineLinearBridgeDispatcher, createLinearBridgeRuntime, createLinearClient, createLinearTools, createLinearWebhookHandler, createSqliteSessionRoomStore, dedupeHandles, handleAgentSessionEvent, handleAppUserNotification, isLinearApiKey, isSessionStale, postAction, postAuthElicitation, postElicitation, postError, postResponse, postSelectElicitation, postThought, sendRecoveryActivityIfStale, stripHandlePrefix, updatePlan };
package/dist/linear.d.ts CHANGED
@@ -1,12 +1,21 @@
1
1
  import { LinearClient, LinearDocument } from '@linear/sdk';
2
- import { R as RestApi } from './types-CxII3XkA.js';
3
- import { AgentSessionEventWebhookPayload } from '@linear/sdk/webhooks';
2
+ import { R as RestApi } from './types-BivGO7I9.js';
3
+ import { AppUserNotificationWebhookPayloadWithNotification, AgentSessionEventWebhookPayload, AppUserTeamAccessChangedWebhookPayload, OAuthAppWebhookPayload } from '@linear/sdk/webhooks';
4
4
  import { L as Logger } from './logger-CABQOnlR.js';
5
5
  import { C as CustomToolDef } from './customTools-BzF0IISO.js';
6
6
  import { IncomingMessage, ServerResponse } from 'node:http';
7
- import './dtos-DUpbIu8k.js';
7
+ import './dtos-B8KU_q4d.js';
8
8
  import 'zod';
9
9
 
10
+ interface CandidateRepositoryInput {
11
+ hostname: string;
12
+ repositoryFullName: string;
13
+ }
14
+ interface RepositorySuggestion {
15
+ repositoryFullName: string;
16
+ hostname?: string | null;
17
+ confidence: number;
18
+ }
10
19
  /**
11
20
  * Subset of `LinearClient` covering only the activity-reporting methods.
12
21
  */
@@ -14,7 +23,9 @@ interface LinearActivityClient {
14
23
  createAgentActivity(input: {
15
24
  agentSessionId: string;
16
25
  content: Record<string, unknown>;
26
+ ephemeral?: boolean;
17
27
  }): Promise<unknown>;
28
+ updateAgentSession?: (id: string, input: Record<string, unknown>) => Promise<unknown>;
18
29
  updateIssue?: (issueId: string, input: Record<string, unknown>) => Promise<unknown>;
19
30
  createComment?: (input: {
20
31
  issueId: string;
@@ -22,22 +33,81 @@ interface LinearActivityClient {
22
33
  }) => Promise<unknown>;
23
34
  issue?: (issueId: string) => Promise<unknown>;
24
35
  workflowStates?: (variables?: Record<string, unknown>) => Promise<unknown>;
36
+ issueRepositorySuggestions?: (candidateRepositories: CandidateRepositoryInput[], issueId: string, variables?: {
37
+ agentSessionId?: string | null;
38
+ }) => Promise<unknown>;
39
+ agentSessionUpdateExternalUrl?: (id: string, input: Record<string, unknown>) => Promise<unknown>;
40
+ /** Create an agent session on an existing Linear issue (proactive initiation). */
41
+ agentSessionCreateOnIssue?: (input: {
42
+ issueId: string;
43
+ externalLink?: string;
44
+ }) => Promise<unknown>;
45
+ /** Create an agent session on a specific comment thread (proactive initiation). */
46
+ agentSessionCreateOnComment?: (input: {
47
+ commentId: string;
48
+ externalLink?: string;
49
+ }) => Promise<unknown>;
50
+ /** Create a new Linear issue from scratch. */
51
+ createIssue?: (input: {
52
+ teamId: string;
53
+ title: string;
54
+ description?: string;
55
+ priority?: number;
56
+ assigneeId?: string;
57
+ stateId?: string;
58
+ labelIds?: string[];
59
+ }) => Promise<unknown>;
25
60
  }
26
61
  interface PlanStep {
27
62
  title: string;
28
63
  status: "pending" | "in_progress" | "completed" | "failed";
29
64
  }
30
- declare function postThought(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
31
- declare function postError(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
65
+ interface SelectOption {
66
+ label: string;
67
+ value: string;
68
+ }
69
+ /** Longest body string allowed in an elicitation activity. */
70
+ declare const ELICITATION_BODY_MAX_LENGTH = 10000;
71
+ /** Longest label or value string allowed in a select option. */
72
+ declare const SELECT_OPTION_MAX_LENGTH = 200;
73
+ /** Longest provider name string allowed in an auth elicitation. */
74
+ declare const PROVIDER_MAX_LENGTH = 100;
75
+ declare function postThought(client: LinearActivityClient, sessionId: string, body: string, options?: {
76
+ ephemeral?: boolean;
77
+ }): Promise<void>;
78
+ declare function postError(client: LinearActivityClient, sessionId: string, body: string, options?: {
79
+ ephemeral?: boolean;
80
+ }): Promise<void>;
32
81
  declare function postResponse(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
33
82
  declare function postElicitation(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
34
- declare function postAction(client: LinearActivityClient, sessionId: string, body: string): Promise<void>;
83
+ declare function postSelectElicitation(client: LinearActivityClient, sessionId: string, body: string, options: SelectOption[]): Promise<void>;
84
+ declare function postAuthElicitation(client: LinearActivityClient, sessionId: string, body: string, url: string, provider?: string): Promise<void>;
85
+ declare function postAction(client: LinearActivityClient, sessionId: string, body: string, options?: {
86
+ ephemeral?: boolean;
87
+ }): Promise<void>;
35
88
  declare function updatePlan(client: LinearActivityClient, sessionId: string, steps: PlanStep[]): Promise<void>;
36
89
 
90
+ interface HandleAppUserNotificationInput {
91
+ payload: AppUserNotificationWebhookPayloadWithNotification;
92
+ deps: LinearBandBridgeDeps;
93
+ logger: Logger;
94
+ /** The Linear app-user id from the webhook envelope; used to skip self-notifications. */
95
+ appUserId?: string;
96
+ }
97
+ declare function handleAppUserNotification(input: HandleAppUserNotificationInput): Promise<void>;
98
+
37
99
  type RoomStrategy = "issue" | "session";
38
100
  type WritebackMode = "final_only" | "activity_stream";
39
101
  type SessionStatus = "active" | "waiting" | "completed" | "canceled" | "errored";
40
- interface LinearThenvoiBridgeConfig {
102
+ /** Default interval (ms) between stale-session keepalive checks. */
103
+ declare const STALE_SESSION_CHECK_INTERVAL_MS: number;
104
+ /**
105
+ * Maximum age (ms) of the last Linear activity before a session is considered
106
+ * at risk of going stale. Linear marks sessions stale after 30 minutes of
107
+ * inactivity; we send a keepalive well before that threshold.
108
+ */
109
+ declare const STALE_SESSION_THRESHOLD_MS: number;
110
+ interface LinearBandBridgeConfig {
41
111
  linearAccessToken: string;
42
112
  linearWebhookSecret: string;
43
113
  roomStrategy?: RoomStrategy;
@@ -46,20 +116,23 @@ interface LinearThenvoiBridgeConfig {
46
116
  planningAgentHandles?: string[];
47
117
  implementationAgentHandles?: string[];
48
118
  recoveredRoomRetryBaseDelayMs?: number;
119
+ bandAppBaseUrl?: string;
49
120
  }
50
121
  interface SessionRoomRecord {
51
122
  linearSessionId: string;
52
123
  linearIssueId: string | null;
53
- thenvoiRoomId: string;
124
+ bandRoomId: string;
54
125
  status: SessionStatus;
55
126
  lastEventKey?: string | null;
127
+ /** ISO-8601 timestamp of the last activity sent to Linear for this session. */
128
+ lastLinearActivityAt?: string | null;
56
129
  createdAt: string;
57
130
  updatedAt: string;
58
131
  }
59
132
  interface PendingBootstrapRequest {
60
133
  eventKey: string;
61
134
  linearSessionId: string;
62
- thenvoiRoomId: string;
135
+ bandRoomId: string;
63
136
  expectedContent: string;
64
137
  messageType: string;
65
138
  senderId?: string | null;
@@ -76,18 +149,20 @@ interface SessionRoomStore {
76
149
  enqueueBootstrapRequest(request: PendingBootstrapRequest): Promise<void>;
77
150
  listPendingBootstrapRequests(limit?: number): Promise<PendingBootstrapRequest[]>;
78
151
  markBootstrapRequestProcessed(eventKey: string): Promise<void>;
152
+ /** List sessions with active or waiting status (used by stale-session keepalive). */
153
+ listActiveSessions?(): Promise<SessionRoomRecord[]>;
79
154
  close?(): Promise<void>;
80
155
  }
81
- interface LinearThenvoiBridgeDeps {
82
- thenvoiRest: RestApi;
156
+ interface LinearBandBridgeDeps {
157
+ bandRest: RestApi;
83
158
  linearClient: LinearClient;
84
159
  store: SessionRoomStore;
85
160
  logger?: Logger;
86
161
  }
87
162
  interface HandleAgentSessionEventInput {
88
163
  payload: AgentSessionEventWebhookPayload;
89
- config: LinearThenvoiBridgeConfig;
90
- deps: LinearThenvoiBridgeDeps;
164
+ config: LinearBandBridgeConfig;
165
+ deps: LinearBandBridgeDeps;
91
166
  }
92
167
 
93
168
  type LinearSessionStatus = SessionStatus;
@@ -120,6 +195,55 @@ declare function completeLinearSession(input: {
120
195
  lastEventKey?: string | null;
121
196
  }): Promise<void>;
122
197
 
198
+ interface StaleSessionGuardOptions {
199
+ store: SessionRoomStore;
200
+ linearClient: LinearActivityClient;
201
+ logger?: Logger;
202
+ /** Interval (ms) between keepalive checks. Defaults to 20 minutes. */
203
+ checkIntervalMs?: number;
204
+ /** Max age (ms) of last activity before sending a keepalive. Defaults to 25 minutes. */
205
+ staleThresholdMs?: number;
206
+ /** Message sent as a keepalive thought. */
207
+ keepAliveMessage?: string;
208
+ }
209
+ /**
210
+ * Periodically checks active Linear sessions and sends a keepalive activity
211
+ * to prevent Linear from marking them as stale (30-minute inactivity timeout).
212
+ */
213
+ declare class StaleSessionGuard {
214
+ private readonly store;
215
+ private readonly linearClient;
216
+ private readonly logger;
217
+ private readonly checkIntervalMs;
218
+ private readonly staleThresholdMs;
219
+ private readonly keepAliveMessage;
220
+ private timer;
221
+ constructor(options: StaleSessionGuardOptions);
222
+ /** Start the periodic keepalive check. Safe to call multiple times. */
223
+ start(): void;
224
+ /** Stop the periodic keepalive check. */
225
+ stop(): void;
226
+ /** Run a single keepalive check. Exposed for testing and manual invocation. */
227
+ tick(): Promise<number>;
228
+ }
229
+ /**
230
+ * Returns `true` when the session's last Linear activity is older than
231
+ * `thresholdMs`, meaning it risks being marked stale by Linear.
232
+ */
233
+ declare function isSessionStale(session: SessionRoomRecord, nowMs: number, thresholdMs: number): boolean;
234
+ /**
235
+ * Checks whether a session may have gone stale and sends a recovery activity
236
+ * before the main update. Call this before posting significant activities to
237
+ * a session that may have been idle for a long time.
238
+ */
239
+ declare function sendRecoveryActivityIfStale(input: {
240
+ session: SessionRoomRecord;
241
+ linearClient: LinearActivityClient;
242
+ store: SessionRoomStore;
243
+ logger: Logger;
244
+ staleThresholdMs?: number;
245
+ }): Promise<boolean>;
246
+
123
247
  declare function isLinearApiKey(token: string): boolean;
124
248
  declare function createLinearClient(token: string): LinearClient;
125
249
  declare function buildLinearAuthorizationHeader(token: string): string;
@@ -133,6 +257,7 @@ interface CreateLinearToolsOptions {
133
257
  client: LinearActivityClient;
134
258
  store?: SessionRoomStore;
135
259
  enableElicitation?: boolean;
260
+ logger?: Logger;
136
261
  }
137
262
  /**
138
263
  * Create Linear activity tools usable by any adapter via `customTools`.
@@ -149,10 +274,15 @@ interface LinearBridgeDispatcher {
149
274
  isQueued?(eventKey: string): boolean;
150
275
  waitForIdle?(): Promise<void>;
151
276
  }
277
+ interface PermissionChangeCallbacks {
278
+ onTeamAccessChanged?: (payload: AppUserTeamAccessChangedWebhookPayload) => void | Promise<void>;
279
+ onOAuthAppRevoked?: (payload: OAuthAppWebhookPayload) => void | Promise<void>;
280
+ }
152
281
  interface CreateLinearWebhookHandlerOptions {
153
- config: LinearThenvoiBridgeConfig;
154
- deps: LinearThenvoiBridgeDeps;
282
+ config: LinearBandBridgeConfig;
283
+ deps: LinearBandBridgeDeps;
155
284
  dispatcher?: LinearBridgeDispatcher;
285
+ permissionCallbacks?: PermissionChangeCallbacks;
156
286
  }
157
287
  declare function createInlineLinearBridgeDispatcher(options?: {
158
288
  logger?: Logger;
@@ -164,4 +294,4 @@ declare function createLinearWebhookHandler(options: CreateLinearWebhookHandlerO
164
294
 
165
295
  declare const DEFAULT_STATUS_MAPPING: Record<SessionStatus, LinearSessionStatus>;
166
296
 
167
- export { type CreateLinearWebhookHandlerOptions, DEFAULT_STATUS_MAPPING, type HandleAgentSessionEventInput, type LinearActivityClient, type LinearBridgeDispatchJob, type LinearBridgeDispatcher, type LinearBridgeRuntime, type LinearSessionStatus, type LinearThenvoiBridgeConfig, type LinearThenvoiBridgeDeps, type PendingBootstrapRequest, type PlanStep, type RoomStrategy, type SessionRoomRecord, type SessionRoomStore, type SessionStatus, type WritebackMode, buildLinearAuthorizationHeader, completeLinearSession, createInProcessLinearBridgeDispatcher, createInlineLinearBridgeDispatcher, createLinearBridgeRuntime, createLinearClient, createLinearTools, createLinearWebhookHandler, createSqliteSessionRoomStore, dedupeHandles, handleAgentSessionEvent, isLinearApiKey, postAction, postElicitation, postError, postResponse, postThought, stripHandlePrefix, updatePlan };
297
+ export { type CandidateRepositoryInput, type CreateLinearWebhookHandlerOptions, DEFAULT_STATUS_MAPPING, ELICITATION_BODY_MAX_LENGTH, type HandleAgentSessionEventInput, type HandleAppUserNotificationInput, type LinearActivityClient, type LinearBandBridgeConfig, type LinearBandBridgeDeps, type LinearBridgeDispatchJob, type LinearBridgeDispatcher, type LinearBridgeRuntime, type LinearSessionStatus, PROVIDER_MAX_LENGTH, type PendingBootstrapRequest, type PermissionChangeCallbacks, type PlanStep, type RepositorySuggestion, type RoomStrategy, SELECT_OPTION_MAX_LENGTH, STALE_SESSION_CHECK_INTERVAL_MS, STALE_SESSION_THRESHOLD_MS, type SelectOption, type SessionRoomRecord, type SessionRoomStore, type SessionStatus, StaleSessionGuard, type StaleSessionGuardOptions, type WritebackMode, buildLinearAuthorizationHeader, completeLinearSession, createInProcessLinearBridgeDispatcher, createInlineLinearBridgeDispatcher, createLinearBridgeRuntime, createLinearClient, createLinearTools, createLinearWebhookHandler, createSqliteSessionRoomStore, dedupeHandles, handleAgentSessionEvent, handleAppUserNotification, isLinearApiKey, isSessionStale, postAction, postAuthElicitation, postElicitation, postError, postResponse, postSelectElicitation, postThought, sendRecoveryActivityIfStale, stripHandlePrefix, updatePlan };