@tstax/coding-tab 0.1.1 → 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.
package/dist/server.d.ts CHANGED
@@ -21,38 +21,108 @@ interface ModelOption {
21
21
  cursorModelId: string;
22
22
  displayName: string;
23
23
  }
24
+ interface PrInfo {
25
+ url: string;
26
+ number: number;
27
+ owner: string;
28
+ repo: string;
29
+ branch?: string;
30
+ state?: "open" | "closed" | "merged";
31
+ title?: string;
32
+ body?: string;
33
+ }
34
+ /**
35
+ * A chronological event inside an assistant turn. Either a paragraph of text
36
+ * (one per `block.text` from the SDK assistant message) or a tool invocation
37
+ * (one per `tool_use`/`tool_call` from the SDK).
38
+ */
39
+ type TimelineEvent = {
40
+ kind: "text";
41
+ id: string;
42
+ text: string;
43
+ } | {
44
+ kind: "tool";
45
+ id: string;
46
+ callId: string;
47
+ name: string;
48
+ status: "running" | "completed" | "error";
49
+ args?: unknown;
50
+ result?: unknown;
51
+ };
52
+ type TurnRole = "user" | "assistant";
53
+ type TurnStatus = "running" | "finished" | "error" | "cancelled";
54
+ /** A persisted turn (user prompt or assistant response) inside a chat. */
55
+ interface StoredTurn {
56
+ id: string;
57
+ chatId: string;
58
+ seq: number;
59
+ role: TurnRole;
60
+ isPlan: boolean;
61
+ status?: TurnStatus;
62
+ events: TimelineEvent[];
63
+ pr?: PrInfo;
64
+ createdAt: number;
65
+ /** For user turns: the raw prompt typed into the composer. */
66
+ prompt?: string;
67
+ /** For assistant turns: surfaced if the plan ended with `PLAN READY`. */
68
+ showExecute?: boolean;
69
+ }
70
+ /** The persisted metadata for a chat thread. */
71
+ interface StoredChat {
72
+ id: string;
73
+ githubLogin: string;
74
+ title: string;
75
+ mode: ChatMode;
76
+ model: ModelChoice;
77
+ repoUrl: string;
78
+ startingRef?: string;
79
+ /** Last cloud agentId used by this chat — re-attached via `Agent.resume`. */
80
+ agentId?: string;
81
+ createdAt: number;
82
+ updatedAt: number;
83
+ }
84
+ /** Lightweight chat row used to populate the sidebar. */
85
+ interface ChatListItem {
86
+ id: string;
87
+ title: string;
88
+ mode: ChatMode;
89
+ model: ModelChoice;
90
+ updatedAt: number;
91
+ createdAt: number;
92
+ }
93
+ interface FullChat extends StoredChat {
94
+ turns: StoredTurn[];
95
+ }
96
+ interface CreateChatRequest {
97
+ title?: string;
98
+ mode?: ChatMode;
99
+ model?: ModelChoice;
100
+ repoUrl?: string;
101
+ startingRef?: string;
102
+ }
103
+ interface CreateChatResponse {
104
+ chat: StoredChat;
105
+ }
106
+ interface PatchChatRequest {
107
+ title?: string;
108
+ mode?: ChatMode;
109
+ model?: ModelChoice;
110
+ }
24
111
  interface StartAgentRequest {
112
+ chatId: string;
25
113
  prompt: string;
26
114
  mode: ChatMode;
27
115
  model: ModelChoice;
28
116
  repoUrl?: string;
29
117
  startingRef?: string;
30
118
  }
31
- interface StartAgentResponse {
32
- sessionId: string;
33
- agentId: string;
34
- runId: string;
35
- }
36
119
  interface SendMessageRequest {
37
- sessionId: string;
120
+ chatId: string;
38
121
  prompt: string;
39
122
  mode: ChatMode;
40
123
  }
41
- interface SendMessageResponse {
42
- runId: string;
43
- }
44
124
  interface ExecuteRequest {
45
- sessionId: string;
46
- }
47
- interface PrInfo {
48
- url: string;
49
- number: number;
50
- owner: string;
51
- repo: string;
52
- branch?: string;
53
- state?: "open" | "closed" | "merged";
54
- title?: string;
55
- body?: string;
125
+ chatId: string;
56
126
  }
57
127
  interface MergeRequest {
58
128
  prUrl: string;
@@ -90,11 +160,61 @@ type StreamEvent = {
90
160
  retryable?: boolean;
91
161
  } | {
92
162
  kind: "ready";
93
- sessionId: string;
163
+ chatId: string;
164
+ turnId: string;
94
165
  agentId: string;
95
166
  runId: string;
96
167
  };
97
168
 
169
+ /**
170
+ * Pluggable persistence layer for chats + turns. The default
171
+ * `FileChatStorage` writes JSON files under a data directory; host apps can
172
+ * swap in their own implementation (e.g. Postgres / Supabase) by passing
173
+ * `storage` to `mountCodingTab`.
174
+ */
175
+ interface ChatStorage {
176
+ listChats(login: string): Promise<ChatListItem[]>;
177
+ loadChat(id: string, login: string): Promise<FullChat | null>;
178
+ createChat(chat: StoredChat): Promise<void>;
179
+ patchChat(id: string, login: string, patch: Partial<Omit<StoredChat, "id" | "githubLogin" | "createdAt">>): Promise<StoredChat | null>;
180
+ appendTurn(turn: StoredTurn): Promise<void>;
181
+ patchTurn(chatId: string, turnId: string, patch: Partial<Omit<StoredTurn, "id" | "chatId" | "createdAt">>): Promise<void>;
182
+ deleteChat(id: string, login: string): Promise<boolean>;
183
+ }
184
+ interface FileChatStorageOptions {
185
+ dataDir: string;
186
+ }
187
+ declare class FileChatStorage implements ChatStorage {
188
+ private readonly dataDir;
189
+ /** Per-chat write mutex chain to keep concurrent appends consistent. */
190
+ private readonly chains;
191
+ constructor(opts: FileChatStorageOptions);
192
+ private chatPath;
193
+ private indexPath;
194
+ /** Serialize all reads/writes for a single chat through a chained promise. */
195
+ private withChat;
196
+ private readChat;
197
+ private writeChat;
198
+ private readIndex;
199
+ private writeIndex;
200
+ /**
201
+ * Rebuild the index for a user by scanning every chat file. Used as a
202
+ * self-heal path when the index gets out of sync (e.g. crash mid-write).
203
+ */
204
+ private rebuildIndex;
205
+ private toListItem;
206
+ private upsertIndex;
207
+ private removeFromIndex;
208
+ listChats(login: string): Promise<ChatListItem[]>;
209
+ loadChat(id: string, login: string): Promise<FullChat | null>;
210
+ createChat(chat: StoredChat): Promise<void>;
211
+ patchChat(id: string, login: string, patch: Partial<Omit<StoredChat, "id" | "githubLogin" | "createdAt">>): Promise<StoredChat | null>;
212
+ appendTurn(turn: StoredTurn): Promise<void>;
213
+ patchTurn(chatId: string, turnId: string, patch: Partial<Omit<StoredTurn, "id" | "chatId" | "createdAt">>): Promise<void>;
214
+ deleteChat(id: string, login: string): Promise<boolean>;
215
+ }
216
+ declare function createDefaultStorage(dataDir?: string): ChatStorage;
217
+
98
218
  interface MountCodingTabOptions {
99
219
  cursorApiKey: string;
100
220
  githubOAuth: GitHubOAuthOptions;
@@ -107,7 +227,15 @@ interface MountCodingTabOptions {
107
227
  secure?: boolean;
108
228
  envName?: string;
109
229
  skipReviewerRequest?: boolean;
230
+ /**
231
+ * Optional pluggable persistence layer. Defaults to a JSON file store
232
+ * rooted at `dataDir` (or `<cwd>/.coding-tab-data`). Override to plug in
233
+ * Postgres, Supabase, Redis, etc. on hosts with ephemeral filesystems.
234
+ */
235
+ storage?: ChatStorage;
236
+ /** Directory used by the default file storage. Ignored when `storage` is set. */
237
+ dataDir?: string;
110
238
  }
111
239
  declare function mountCodingTab(app: Express, options: MountCodingTabOptions): Router;
112
240
 
113
- export { type ChatMode, type ExecuteRequest, type GitHubOAuthOptions, type MeResponse, type MergeRequest, type MergeResponse, type ModelChoice, type ModelOption, type MountCodingTabOptions, type PrInfo, type SendMessageRequest, type SendMessageResponse, type StartAgentRequest, type StartAgentResponse, type StreamEvent, mountCodingTab };
241
+ export { type ChatListItem, type ChatMode, type ChatStorage, type CreateChatRequest, type CreateChatResponse, type ExecuteRequest, FileChatStorage, type FullChat, type GitHubOAuthOptions, type MeResponse, type MergeRequest, type MergeResponse, type ModelChoice, type ModelOption, type MountCodingTabOptions, type PatchChatRequest, type PrInfo, type SendMessageRequest, type StartAgentRequest, type StoredChat, type StoredTurn, type StreamEvent, type TimelineEvent, type TurnRole, type TurnStatus, createDefaultStorage, mountCodingTab };