@band-ai/sdk 0.1.4 → 0.1.10

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 (73) hide show
  1. package/README.md +372 -0
  2. package/dist/{ClaudeSDKAdapter-CRq4R-WB.d.cts → ClaudeSDKAdapter-DfjaI5ke.d.cts} +9 -7
  3. package/dist/{ClaudeSDKAdapter-BHOkjN3X.d.ts → ClaudeSDKAdapter-DonPGJ43.d.ts} +9 -7
  4. package/dist/{acp-server-BdRz9_UN.d.cts → acp-server-CUBXIiG6.d.cts} +2 -2
  5. package/dist/{acp-server-B1Da7L6u.d.ts → acp-server-NZAeg-WO.d.ts} +2 -2
  6. package/dist/adapters.cjs +494 -106
  7. package/dist/adapters.d.cts +12 -12
  8. package/dist/adapters.d.ts +12 -12
  9. package/dist/adapters.js +7 -7
  10. package/dist/{backends-SVMT-7l4.d.cts → backends-DYtEhCZG.d.cts} +7 -2
  11. package/dist/{backends-CzDbiQar.d.ts → backends-oYAb7EU-.d.ts} +7 -2
  12. package/dist/{chunk-MSL6CWHY.js → chunk-2BHHR6YW.js} +17 -16
  13. package/dist/{chunk-EDPKUUJL.js → chunk-6RXWL6TC.js} +9 -1
  14. package/dist/{chunk-SFVKOEQH.js → chunk-DNPVCR3S.js} +92 -14
  15. package/dist/{chunk-I5EZG52P.js → chunk-FP237EAG.js} +424 -136
  16. package/dist/{chunk-RHVH2GZR.js → chunk-J3M3PFFY.js} +81 -31
  17. package/dist/{chunk-GVEQ3RAH.js → chunk-MLROFDKR.js} +132 -23
  18. package/dist/{chunk-INA6YZTZ.js → chunk-RDM4TE4B.js} +32 -30
  19. package/dist/chunk-US226AS4.js +130 -0
  20. package/dist/{chunk-W5NDZSYE.js → chunk-XA4N2JPH.js} +1 -1
  21. package/dist/converters.cjs +469 -13
  22. package/dist/converters.d.cts +5 -5
  23. package/dist/converters.d.ts +5 -5
  24. package/dist/converters.js +3 -2
  25. package/dist/core.cjs +45 -2
  26. package/dist/core.d.cts +4 -3
  27. package/dist/core.d.ts +4 -3
  28. package/dist/core.js +5 -1
  29. package/dist/disconnectReason-IuADl6TH.d.cts +34 -0
  30. package/dist/disconnectReason-IuADl6TH.d.ts +34 -0
  31. package/dist/{dtos-DUpbIu8k.d.cts → dtos-Dd_fTfLn.d.cts} +26 -6
  32. package/dist/{dtos-DUpbIu8k.d.ts → dtos-Dd_fTfLn.d.ts} +26 -6
  33. package/dist/index.cjs +1089 -269
  34. package/dist/index.d.cts +16 -15
  35. package/dist/index.d.ts +16 -15
  36. package/dist/index.js +14 -8
  37. package/dist/linear.cjs +985 -53
  38. package/dist/linear.d.cts +137 -7
  39. package/dist/linear.d.ts +137 -7
  40. package/dist/linear.js +974 -53
  41. package/dist/mcp-claude.cjs +303 -32
  42. package/dist/mcp-claude.d.cts +3 -3
  43. package/dist/mcp-claude.d.ts +3 -3
  44. package/dist/mcp-claude.js +210 -12
  45. package/dist/mcp.cjs +313 -45
  46. package/dist/mcp.d.cts +5 -5
  47. package/dist/mcp.d.ts +5 -5
  48. package/dist/mcp.js +3 -3
  49. package/dist/{opencode-BBcDchcN.d.cts → opencode--iA5-KYk.d.cts} +2 -2
  50. package/dist/{opencode-DthQQUsZ.d.ts → opencode-YNacv-eJ.d.ts} +2 -2
  51. package/dist/{pagination-CcDkVFxK.d.ts → pagination-BBLsYLhT.d.ts} +2 -2
  52. package/dist/{pagination-BPiys10t.d.cts → pagination-CqidD-L_.d.cts} +2 -2
  53. package/dist/{protocols-DrhzOH6K.d.ts → protocols-BF6jamIl.d.ts} +1 -1
  54. package/dist/{protocols-CInhtFpA.d.cts → protocols-D2bTrQ_t.d.cts} +1 -1
  55. package/dist/rest.d.cts +5 -5
  56. package/dist/rest.d.ts +5 -5
  57. package/dist/runtime.cjs +721 -172
  58. package/dist/runtime.d.cts +15 -10
  59. package/dist/runtime.d.ts +15 -10
  60. package/dist/runtime.js +11 -8
  61. package/dist/{schemas-vos1AaBc.d.ts → schemas-B1Fd3oUM.d.ts} +17 -8
  62. package/dist/{schemas-BpEBkq5V.d.cts → schemas-CI0qgcp_.d.cts} +17 -8
  63. package/dist/{sdk-CcnQ5OUC.d.ts → sdk-CyqN1W5g.d.ts} +32 -2
  64. package/dist/{sdk-CwTAxhwI.d.cts → sdk-D2rTDU_o.d.cts} +32 -2
  65. package/dist/{simpleAdapter-DqhvjsGr.d.cts → simpleAdapter-C_f-01Cu.d.cts} +1 -1
  66. package/dist/{simpleAdapter-9OE_p6QW.d.ts → simpleAdapter-qQt-tSz4.d.ts} +1 -1
  67. package/dist/testing.d.cts +3 -3
  68. package/dist/testing.d.ts +3 -3
  69. package/dist/{types-CovcHpYf.d.cts → types-CKqrhGB1.d.cts} +2 -2
  70. package/dist/{types-CxII3XkA.d.ts → types-D3AsUnd0.d.ts} +1 -1
  71. package/dist/{types-7jVzOeOP.d.ts → types-DNySTI_8.d.ts} +2 -2
  72. package/dist/{types-CSHFipIc.d.cts → types-DtMms5Fi.d.cts} +1 -1
  73. package/package.json +22 -21
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-DtMms5Fi.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-Dd_fTfLn.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,21 +33,80 @@ 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: LinearThenvoiBridgeDeps;
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";
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;
40
110
  interface LinearThenvoiBridgeConfig {
41
111
  linearAccessToken: string;
42
112
  linearWebhookSecret: string;
@@ -46,6 +116,7 @@ interface LinearThenvoiBridgeConfig {
46
116
  planningAgentHandles?: string[];
47
117
  implementationAgentHandles?: string[];
48
118
  recoveredRoomRetryBaseDelayMs?: number;
119
+ thenvoiAppBaseUrl?: string;
49
120
  }
50
121
  interface SessionRoomRecord {
51
122
  linearSessionId: string;
@@ -53,6 +124,8 @@ interface SessionRoomRecord {
53
124
  thenvoiRoomId: 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
  }
@@ -76,6 +149,8 @@ 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
156
  interface LinearThenvoiBridgeDeps {
@@ -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
282
  config: LinearThenvoiBridgeConfig;
154
283
  deps: LinearThenvoiBridgeDeps;
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 LinearBridgeDispatchJob, type LinearBridgeDispatcher, type LinearBridgeRuntime, type LinearSessionStatus, type LinearThenvoiBridgeConfig, type LinearThenvoiBridgeDeps, 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-D3AsUnd0.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-Dd_fTfLn.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,21 +33,80 @@ 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: LinearThenvoiBridgeDeps;
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";
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;
40
110
  interface LinearThenvoiBridgeConfig {
41
111
  linearAccessToken: string;
42
112
  linearWebhookSecret: string;
@@ -46,6 +116,7 @@ interface LinearThenvoiBridgeConfig {
46
116
  planningAgentHandles?: string[];
47
117
  implementationAgentHandles?: string[];
48
118
  recoveredRoomRetryBaseDelayMs?: number;
119
+ thenvoiAppBaseUrl?: string;
49
120
  }
50
121
  interface SessionRoomRecord {
51
122
  linearSessionId: string;
@@ -53,6 +124,8 @@ interface SessionRoomRecord {
53
124
  thenvoiRoomId: 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
  }
@@ -76,6 +149,8 @@ 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
156
  interface LinearThenvoiBridgeDeps {
@@ -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
282
  config: LinearThenvoiBridgeConfig;
154
283
  deps: LinearThenvoiBridgeDeps;
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 LinearBridgeDispatchJob, type LinearBridgeDispatcher, type LinearBridgeRuntime, type LinearSessionStatus, type LinearThenvoiBridgeConfig, type LinearThenvoiBridgeDeps, 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 };