@schoolai/shipyard-mcp 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.
@@ -0,0 +1,273 @@
1
+ import {
2
+ InputRequestSchema,
3
+ YDOC_KEYS,
4
+ createInputRequest,
5
+ logPlanEvent
6
+ } from "./chunk-LTC26IRQ.js";
7
+ import {
8
+ logger
9
+ } from "./chunk-GSGLHRWX.js";
10
+
11
+ // src/services/input-request-manager.ts
12
+ var InputRequestManager = class {
13
+ /**
14
+ * Create a new input request in the Y.Doc.
15
+ * Request is added to the INPUT_REQUESTS array and becomes visible in browser UI.
16
+ *
17
+ * @param ydoc - The Y.Doc to add the request to
18
+ * @param params - Request parameters (message, type, options, etc.)
19
+ * @returns The generated request ID
20
+ */
21
+ createRequest(ydoc, params) {
22
+ const request = createInputRequest(params);
23
+ ydoc.transact(() => {
24
+ const requestsArray = ydoc.getArray(YDOC_KEYS.INPUT_REQUESTS);
25
+ requestsArray.push([request]);
26
+ logPlanEvent(ydoc, "input_request_created", "Agent", {
27
+ requestId: request.id,
28
+ requestType: request.type,
29
+ requestMessage: request.message
30
+ });
31
+ });
32
+ logger.info(
33
+ { requestId: request.id, type: request.type, timeout: request.timeout },
34
+ "Created input request in Y.Doc"
35
+ );
36
+ return request.id;
37
+ }
38
+ /**
39
+ * Wait for a user to respond to an input request.
40
+ * Blocks until the request is answered, cancelled, or times out.
41
+ *
42
+ * Pattern: Based on waitForReviewDecision from review-status.ts
43
+ * - Observes Y.Doc changes via Y.Array observer
44
+ * - Polls for status changes to the specific request
45
+ * - Unsubscribes and cleans up on completion
46
+ *
47
+ * @param ydoc - The Y.Doc containing the request
48
+ * @param requestId - The ID of the request to wait for
49
+ * @param timeoutSeconds - Max time to wait (0 = no timeout, uses request.timeout if not specified)
50
+ * @returns Promise that resolves when request is answered/cancelled
51
+ */
52
+ async waitForResponse(ydoc, requestId, timeoutSeconds) {
53
+ return new Promise((resolve) => {
54
+ const requestsArray = ydoc.getArray(YDOC_KEYS.INPUT_REQUESTS);
55
+ let resolved = false;
56
+ let timeoutHandle;
57
+ let observerFn;
58
+ const findRequest = () => {
59
+ const requests = requestsArray.toJSON();
60
+ return requests.find((r) => r.id === requestId);
61
+ };
62
+ const cleanup = () => {
63
+ if (observerFn) {
64
+ requestsArray.unobserve(observerFn);
65
+ observerFn = void 0;
66
+ }
67
+ if (timeoutHandle) {
68
+ clearTimeout(timeoutHandle);
69
+ timeoutHandle = void 0;
70
+ }
71
+ if (!resolved) {
72
+ resolved = true;
73
+ }
74
+ };
75
+ const checkStatus = () => {
76
+ if (resolved) return;
77
+ const request2 = findRequest();
78
+ if (!request2) {
79
+ handleRequestNotFound();
80
+ return;
81
+ }
82
+ logger.debug({ requestId, status: request2.status }, "Checking input request status");
83
+ if (request2.status === "answered") {
84
+ handleAnsweredStatus(request2);
85
+ } else if (request2.status === "declined") {
86
+ handleDeclinedStatus();
87
+ } else if (request2.status === "cancelled") {
88
+ handleCancelledStatus();
89
+ }
90
+ };
91
+ const handleRequestNotFound = () => {
92
+ logger.warn({ requestId }, "Request not found, treating as cancelled");
93
+ resolved = true;
94
+ cleanup();
95
+ resolve({
96
+ success: false,
97
+ status: "cancelled",
98
+ reason: "Request not found in Y.Doc"
99
+ });
100
+ };
101
+ const handleAnsweredStatus = (request2) => {
102
+ logger.info({ requestId, answeredBy: request2.answeredBy }, "Input request answered");
103
+ resolved = true;
104
+ cleanup();
105
+ resolve({
106
+ success: true,
107
+ response: request2.response,
108
+ status: "answered",
109
+ answeredBy: request2.answeredBy ?? "unknown",
110
+ answeredAt: request2.answeredAt ?? Date.now()
111
+ });
112
+ };
113
+ const handleDeclinedStatus = () => {
114
+ logger.info({ requestId }, "Input request declined by user");
115
+ resolved = true;
116
+ cleanup();
117
+ resolve({
118
+ success: true,
119
+ status: "declined",
120
+ reason: "User declined to answer"
121
+ });
122
+ };
123
+ const handleCancelledStatus = () => {
124
+ logger.info({ requestId }, "Input request cancelled (timeout)");
125
+ resolved = true;
126
+ cleanup();
127
+ resolve({
128
+ success: false,
129
+ status: "cancelled",
130
+ reason: "Request timed out"
131
+ });
132
+ };
133
+ observerFn = () => {
134
+ checkStatus();
135
+ };
136
+ checkStatus();
137
+ if (resolved) {
138
+ return;
139
+ }
140
+ requestsArray.observe(observerFn);
141
+ const request = findRequest();
142
+ const effectiveTimeout = timeoutSeconds !== void 0 ? timeoutSeconds : request?.timeout !== void 0 ? request.timeout : 0;
143
+ const handleTimeout = () => {
144
+ if (resolved) return;
145
+ logger.warn({ requestId, timeout: effectiveTimeout }, "Input request timed out");
146
+ markRequestAsCancelled();
147
+ if (resolved) return;
148
+ resolved = true;
149
+ cleanup();
150
+ const minutes = Math.floor(effectiveTimeout / 60);
151
+ const seconds = effectiveTimeout % 60;
152
+ const timeStr = minutes > 0 ? `${minutes} minute${minutes === 1 ? "" : "s"}${seconds > 0 ? ` ${seconds} second${seconds === 1 ? "" : "s"}` : ""}` : `${seconds} second${seconds === 1 ? "" : "s"}`;
153
+ resolve({
154
+ success: false,
155
+ status: "cancelled",
156
+ reason: `Request timed out after ${timeStr}. The user likely didn't see the request in time. Please try again.`
157
+ });
158
+ };
159
+ const markRequestAsCancelled = () => {
160
+ ydoc.transact(() => {
161
+ if (resolved) return;
162
+ const currentRequest = findRequest();
163
+ if (!currentRequest || currentRequest.status !== "pending") {
164
+ return;
165
+ }
166
+ const requests = requestsArray.toJSON();
167
+ const index = requests.findIndex((r) => r.id === requestId);
168
+ if (index !== -1) {
169
+ requestsArray.delete(index, 1);
170
+ requestsArray.insert(index, [{ ...currentRequest, status: "cancelled" }]);
171
+ }
172
+ });
173
+ };
174
+ if (effectiveTimeout > 0) {
175
+ timeoutHandle = setTimeout(handleTimeout, effectiveTimeout * 1e3);
176
+ }
177
+ });
178
+ }
179
+ /**
180
+ * Cancel a pending input request.
181
+ * Marks the request as cancelled in the Y.Doc.
182
+ *
183
+ * @param ydoc - The Y.Doc containing the request
184
+ * @param requestId - The ID of the request to cancel
185
+ * @returns True if request was found and cancelled, false otherwise
186
+ */
187
+ cancelRequest(ydoc, requestId) {
188
+ let cancelled = false;
189
+ ydoc.transact(() => {
190
+ const requestsArray = ydoc.getArray(YDOC_KEYS.INPUT_REQUESTS);
191
+ const requests = requestsArray.toJSON();
192
+ const index = requests.findIndex((r) => r.id === requestId);
193
+ if (index !== -1) {
194
+ const request = requests[index];
195
+ if (request.status === "pending") {
196
+ requestsArray.delete(index, 1);
197
+ requestsArray.insert(index, [{ ...request, status: "cancelled" }]);
198
+ cancelled = true;
199
+ logger.info({ requestId }, "Cancelled input request");
200
+ } else {
201
+ logger.debug({ requestId, status: request.status }, "Request not pending, cannot cancel");
202
+ }
203
+ } else {
204
+ logger.warn({ requestId }, "Request not found for cancellation");
205
+ }
206
+ });
207
+ return cancelled;
208
+ }
209
+ /**
210
+ * Get the current state of an input request.
211
+ * Returns undefined if the request doesn't exist.
212
+ *
213
+ * @param ydoc - The Y.Doc containing the request
214
+ * @param requestId - The ID of the request to retrieve
215
+ * @returns The request object, or undefined if not found
216
+ */
217
+ getRequest(ydoc, requestId) {
218
+ const requestsArray = ydoc.getArray(YDOC_KEYS.INPUT_REQUESTS);
219
+ const requests = requestsArray.toJSON();
220
+ const request = requests.find((r) => r.id === requestId);
221
+ if (request) {
222
+ const parseResult = InputRequestSchema.safeParse(request);
223
+ if (parseResult.success) {
224
+ return parseResult.data;
225
+ }
226
+ logger.warn({ requestId, error: parseResult.error }, "Invalid request data in Y.Doc");
227
+ }
228
+ return void 0;
229
+ }
230
+ /**
231
+ * Get all pending input requests for a Y.Doc.
232
+ * Useful for UI to display all active requests.
233
+ *
234
+ * @param ydoc - The Y.Doc to query
235
+ * @returns Array of pending requests
236
+ */
237
+ getPendingRequests(ydoc) {
238
+ const requestsArray = ydoc.getArray(YDOC_KEYS.INPUT_REQUESTS);
239
+ const requests = requestsArray.toJSON();
240
+ return requests.filter((r) => r.status === "pending");
241
+ }
242
+ /**
243
+ * Clean up old completed/cancelled requests from Y.Doc.
244
+ * Removes requests older than the specified age to prevent unbounded growth.
245
+ *
246
+ * @param ydoc - The Y.Doc to clean up
247
+ * @param maxAgeMs - Maximum age in milliseconds (default: 24 hours)
248
+ * @returns Number of requests removed
249
+ */
250
+ cleanupOldRequests(ydoc, maxAgeMs = 24 * 60 * 60 * 1e3) {
251
+ let removed = 0;
252
+ const cutoff = Date.now() - maxAgeMs;
253
+ ydoc.transact(() => {
254
+ const requestsArray = ydoc.getArray(YDOC_KEYS.INPUT_REQUESTS);
255
+ const requests = requestsArray.toJSON();
256
+ for (let i = requests.length - 1; i >= 0; i--) {
257
+ const request = requests[i];
258
+ if (request.status !== "pending" && (request.answeredAt ?? request.createdAt) < cutoff) {
259
+ requestsArray.delete(i, 1);
260
+ removed++;
261
+ }
262
+ }
263
+ });
264
+ if (removed > 0) {
265
+ logger.info({ removed, maxAgeMs }, "Cleaned up old input requests");
266
+ }
267
+ return removed;
268
+ }
269
+ };
270
+
271
+ export {
272
+ InputRequestManager
273
+ };
@@ -0,0 +1,409 @@
1
+ import {
2
+ A2ADataPartSchema,
3
+ A2AFilePartSchema,
4
+ A2AMessageSchema,
5
+ A2APartSchema,
6
+ A2ATextPartSchema,
7
+ AgentActivityDataSchema,
8
+ AgentActivityTypes,
9
+ AgentPresenceSchema,
10
+ ArtifactSchema,
11
+ ChangeSchema,
12
+ ChangeTypeSchema,
13
+ ChangesResponseSchema,
14
+ ChunkMessageSchema,
15
+ ClaudeCodeMessageSchema,
16
+ ClaudeCodeOriginMetadataSchema,
17
+ ConversationExportEndSchema,
18
+ ConversationExportMetaSchema,
19
+ ConversationExportStartMetaSchema,
20
+ ConversationVersionSchema,
21
+ CreateHookSessionRequestSchema,
22
+ CreateHookSessionResponseSchema,
23
+ CreateSubscriptionRequestSchema,
24
+ CreateSubscriptionResponseSchema,
25
+ CursorOriginMetadataSchema,
26
+ DeleteSubscriptionResponseSchema,
27
+ DeliverableSchema,
28
+ DevinOriginMetadataSchema,
29
+ GetReviewStatusResponseSchema,
30
+ GitHubPRResponseSchema,
31
+ HasConnectionsResponseSchema,
32
+ HookApiErrorSchema,
33
+ ImportConversationRequestSchema,
34
+ ImportConversationResponseSchema,
35
+ InputRequestSchema,
36
+ InputRequestStatusValues,
37
+ InputRequestTypeValues,
38
+ InviteRedemptionSchema,
39
+ InviteTokenSchema,
40
+ LinkedPRSchema,
41
+ LinkedPRStatusValues,
42
+ NON_PLAN_DB_NAMES,
43
+ OriginMetadataSchema,
44
+ OriginPlatformValues,
45
+ P2PMessageType,
46
+ PLAN_INDEX_DOC_NAME,
47
+ PLAN_INDEX_EVENT_VIEWED_BY_KEY,
48
+ PLAN_INDEX_VIEWED_BY_KEY,
49
+ PRReviewCommentSchema,
50
+ PlanEventSchema,
51
+ PlanEventTypes,
52
+ PlanIdSchema,
53
+ PlanIndexEntrySchema,
54
+ PlanMetadataSchema,
55
+ PlanSnapshotSchema,
56
+ PlanStatusResponseSchema,
57
+ PlanStatusValues,
58
+ PlanViewTabValues,
59
+ ROUTES,
60
+ RegisterServerRequestSchema,
61
+ RegisterServerResponseSchema,
62
+ ReviewCommentSchema,
63
+ ReviewFeedbackSchema,
64
+ SetSessionTokenRequestSchema,
65
+ SetSessionTokenResponseSchema,
66
+ SubscriptionClientIdSchema,
67
+ ThreadCommentSchema,
68
+ ThreadSchema,
69
+ UnregisterServerRequestSchema,
70
+ UnregisterServerResponseSchema,
71
+ UpdatePlanContentRequestSchema,
72
+ UpdatePlanContentResponseSchema,
73
+ UpdatePresenceRequestSchema,
74
+ UpdatePresenceResponseSchema,
75
+ VALID_STATUS_TRANSITIONS,
76
+ YDOC_KEYS,
77
+ a2aToClaudeCode,
78
+ addArtifact,
79
+ addConversationVersion,
80
+ addDeliverable,
81
+ addPRReviewComment,
82
+ addPlanTag,
83
+ addSnapshot,
84
+ answerInputRequest,
85
+ appRouter,
86
+ approveUser,
87
+ archivePlan,
88
+ asAwarenessClientId,
89
+ asGitHubUsername,
90
+ asPlanId,
91
+ asWebRTCPeerId,
92
+ assertNever,
93
+ assertNeverP2PMessage,
94
+ buildInviteUrl,
95
+ cancelInputRequest,
96
+ claudeCodeToA2A,
97
+ clearAgentPresence,
98
+ clearEventViewedBy,
99
+ clearPlanIndexViewedBy,
100
+ conversationRouter,
101
+ createGitHubArtifact,
102
+ createHandedOffConversationVersion,
103
+ createInitialConversationVersion,
104
+ createInputRequest,
105
+ createLinkedPR,
106
+ createLocalArtifact,
107
+ createPlanSnapshot,
108
+ createPlanUrl,
109
+ createPlanUrlWithHistory,
110
+ createUserResolver,
111
+ decodeChunkMessage,
112
+ decodeExportEndMessage,
113
+ decodeExportStartMessage,
114
+ decodeP2PMessage,
115
+ decodePlan,
116
+ encodeChunkMessage,
117
+ encodeExportEndMessage,
118
+ encodeExportStartMessage,
119
+ encodePlan,
120
+ extractDeliverables,
121
+ extractMentions,
122
+ extractTextFromCommentBody,
123
+ formatAsClaudeCodeJSONL,
124
+ formatDeliverablesForLLM,
125
+ formatThreadsForLLM,
126
+ getAgentPresence,
127
+ getAgentPresences,
128
+ getAllEventViewedByForPlan,
129
+ getAllTagsFromIndex,
130
+ getAllViewedByFromIndex,
131
+ getApprovedUsers,
132
+ getArtifactUrl,
133
+ getArtifacts,
134
+ getConversationVersions,
135
+ getDeliverables,
136
+ getLatestSnapshot,
137
+ getLinkedPR,
138
+ getLinkedPRs,
139
+ getPRReviewComments,
140
+ getPRReviewCommentsForPR,
141
+ getPlanEvents,
142
+ getPlanFromUrl,
143
+ getPlanIndex,
144
+ getPlanIndexEntry,
145
+ getPlanMetadata,
146
+ getPlanMetadataWithValidation,
147
+ getPlanOwnerId,
148
+ getRejectedUsers,
149
+ getSnapshots,
150
+ getStepCompletions,
151
+ getTokenTimeRemaining,
152
+ getViewedBy,
153
+ getViewedByFromIndex,
154
+ hookRouter,
155
+ initPlanMetadata,
156
+ isApprovalRequired,
157
+ isConversationChunk,
158
+ isConversationExportEnd,
159
+ isConversationExportStart,
160
+ isEventUnread,
161
+ isInboxWorthy,
162
+ isP2PConversationMessage,
163
+ isPlanUnread,
164
+ isStepCompleted,
165
+ isThread,
166
+ isUrlEncodedPlanV1,
167
+ isUrlEncodedPlanV2,
168
+ isUserApproved,
169
+ isUserRejected,
170
+ isValidYDocKey,
171
+ linkArtifactToDeliverable,
172
+ linkPR,
173
+ logPlanEvent,
174
+ markEventAsViewed,
175
+ markPlanAsViewed,
176
+ markVersionHandedOff,
177
+ parseClaudeCodeOrigin,
178
+ parseClaudeCodeTranscriptString,
179
+ parseInviteFromUrl,
180
+ parseThreads,
181
+ planRouter,
182
+ rejectUser,
183
+ removeArtifact,
184
+ removePRReviewComment,
185
+ removePlanIndexEntry,
186
+ removePlanTag,
187
+ removeViewedByFromIndex,
188
+ resolvePRReviewComment,
189
+ revokeUser,
190
+ setAgentPresence,
191
+ setPlanIndexEntry,
192
+ setPlanMetadata,
193
+ subscriptionRouter,
194
+ summarizeA2AConversation,
195
+ toggleStepCompletion,
196
+ touchPlanIndexEntry,
197
+ transitionPlanStatus,
198
+ unarchivePlan,
199
+ unlinkPR,
200
+ unrejectUser,
201
+ updateLinkedPRStatus,
202
+ updatePlanIndexViewedBy,
203
+ validateA2AMessages
204
+ } from "./chunk-LTC26IRQ.js";
205
+ import "./chunk-JSBRDJBE.js";
206
+ export {
207
+ A2ADataPartSchema,
208
+ A2AFilePartSchema,
209
+ A2AMessageSchema,
210
+ A2APartSchema,
211
+ A2ATextPartSchema,
212
+ AgentActivityDataSchema,
213
+ AgentActivityTypes,
214
+ AgentPresenceSchema,
215
+ ArtifactSchema,
216
+ ChangeSchema,
217
+ ChangeTypeSchema,
218
+ ChangesResponseSchema,
219
+ ChunkMessageSchema,
220
+ ClaudeCodeMessageSchema,
221
+ ClaudeCodeOriginMetadataSchema,
222
+ ConversationExportEndSchema,
223
+ ConversationExportMetaSchema,
224
+ ConversationExportStartMetaSchema,
225
+ ConversationVersionSchema,
226
+ CreateHookSessionRequestSchema,
227
+ CreateHookSessionResponseSchema,
228
+ CreateSubscriptionRequestSchema,
229
+ CreateSubscriptionResponseSchema,
230
+ CursorOriginMetadataSchema,
231
+ DeleteSubscriptionResponseSchema,
232
+ DeliverableSchema,
233
+ DevinOriginMetadataSchema,
234
+ GetReviewStatusResponseSchema,
235
+ GitHubPRResponseSchema,
236
+ HasConnectionsResponseSchema,
237
+ HookApiErrorSchema,
238
+ ImportConversationRequestSchema,
239
+ ImportConversationResponseSchema,
240
+ InputRequestSchema,
241
+ InputRequestStatusValues,
242
+ InputRequestTypeValues,
243
+ InviteRedemptionSchema,
244
+ InviteTokenSchema,
245
+ LinkedPRSchema,
246
+ LinkedPRStatusValues,
247
+ NON_PLAN_DB_NAMES,
248
+ OriginMetadataSchema,
249
+ OriginPlatformValues,
250
+ P2PMessageType,
251
+ PLAN_INDEX_DOC_NAME,
252
+ PLAN_INDEX_EVENT_VIEWED_BY_KEY,
253
+ PLAN_INDEX_VIEWED_BY_KEY,
254
+ PRReviewCommentSchema,
255
+ PlanEventSchema,
256
+ PlanEventTypes,
257
+ PlanIdSchema,
258
+ PlanIndexEntrySchema,
259
+ PlanMetadataSchema,
260
+ PlanSnapshotSchema,
261
+ PlanStatusResponseSchema,
262
+ PlanStatusValues,
263
+ PlanViewTabValues,
264
+ ROUTES,
265
+ RegisterServerRequestSchema,
266
+ RegisterServerResponseSchema,
267
+ ReviewCommentSchema,
268
+ ReviewFeedbackSchema,
269
+ SetSessionTokenRequestSchema,
270
+ SetSessionTokenResponseSchema,
271
+ SubscriptionClientIdSchema,
272
+ ThreadCommentSchema,
273
+ ThreadSchema,
274
+ UnregisterServerRequestSchema,
275
+ UnregisterServerResponseSchema,
276
+ UpdatePlanContentRequestSchema,
277
+ UpdatePlanContentResponseSchema,
278
+ UpdatePresenceRequestSchema,
279
+ UpdatePresenceResponseSchema,
280
+ VALID_STATUS_TRANSITIONS,
281
+ YDOC_KEYS,
282
+ a2aToClaudeCode,
283
+ addArtifact,
284
+ addConversationVersion,
285
+ addDeliverable,
286
+ addPRReviewComment,
287
+ addPlanTag,
288
+ addSnapshot,
289
+ answerInputRequest,
290
+ appRouter,
291
+ approveUser,
292
+ archivePlan,
293
+ asAwarenessClientId,
294
+ asGitHubUsername,
295
+ asPlanId,
296
+ asWebRTCPeerId,
297
+ assertNever,
298
+ assertNeverP2PMessage,
299
+ buildInviteUrl,
300
+ cancelInputRequest,
301
+ claudeCodeToA2A,
302
+ clearAgentPresence,
303
+ clearEventViewedBy,
304
+ clearPlanIndexViewedBy,
305
+ conversationRouter,
306
+ createGitHubArtifact,
307
+ createHandedOffConversationVersion,
308
+ createInitialConversationVersion,
309
+ createInputRequest,
310
+ createLinkedPR,
311
+ createLocalArtifact,
312
+ createPlanSnapshot,
313
+ createPlanUrl,
314
+ createPlanUrlWithHistory,
315
+ createUserResolver,
316
+ decodeChunkMessage,
317
+ decodeExportEndMessage,
318
+ decodeExportStartMessage,
319
+ decodeP2PMessage,
320
+ decodePlan,
321
+ encodeChunkMessage,
322
+ encodeExportEndMessage,
323
+ encodeExportStartMessage,
324
+ encodePlan,
325
+ extractDeliverables,
326
+ extractMentions,
327
+ extractTextFromCommentBody,
328
+ formatAsClaudeCodeJSONL,
329
+ formatDeliverablesForLLM,
330
+ formatThreadsForLLM,
331
+ getAgentPresence,
332
+ getAgentPresences,
333
+ getAllEventViewedByForPlan,
334
+ getAllTagsFromIndex,
335
+ getAllViewedByFromIndex,
336
+ getApprovedUsers,
337
+ getArtifactUrl,
338
+ getArtifacts,
339
+ getConversationVersions,
340
+ getDeliverables,
341
+ getLatestSnapshot,
342
+ getLinkedPR,
343
+ getLinkedPRs,
344
+ getPRReviewComments,
345
+ getPRReviewCommentsForPR,
346
+ getPlanEvents,
347
+ getPlanFromUrl,
348
+ getPlanIndex,
349
+ getPlanIndexEntry,
350
+ getPlanMetadata,
351
+ getPlanMetadataWithValidation,
352
+ getPlanOwnerId,
353
+ getRejectedUsers,
354
+ getSnapshots,
355
+ getStepCompletions,
356
+ getTokenTimeRemaining,
357
+ getViewedBy,
358
+ getViewedByFromIndex,
359
+ hookRouter,
360
+ initPlanMetadata,
361
+ isApprovalRequired,
362
+ isConversationChunk,
363
+ isConversationExportEnd,
364
+ isConversationExportStart,
365
+ isEventUnread,
366
+ isInboxWorthy,
367
+ isP2PConversationMessage,
368
+ isPlanUnread,
369
+ isStepCompleted,
370
+ isThread,
371
+ isUrlEncodedPlanV1,
372
+ isUrlEncodedPlanV2,
373
+ isUserApproved,
374
+ isUserRejected,
375
+ isValidYDocKey,
376
+ linkArtifactToDeliverable,
377
+ linkPR,
378
+ logPlanEvent,
379
+ markEventAsViewed,
380
+ markPlanAsViewed,
381
+ markVersionHandedOff,
382
+ parseClaudeCodeOrigin,
383
+ parseClaudeCodeTranscriptString,
384
+ parseInviteFromUrl,
385
+ parseThreads,
386
+ planRouter,
387
+ rejectUser,
388
+ removeArtifact,
389
+ removePRReviewComment,
390
+ removePlanIndexEntry,
391
+ removePlanTag,
392
+ removeViewedByFromIndex,
393
+ resolvePRReviewComment,
394
+ revokeUser,
395
+ setAgentPresence,
396
+ setPlanIndexEntry,
397
+ setPlanMetadata,
398
+ subscriptionRouter,
399
+ summarizeA2AConversation,
400
+ toggleStepCompletion,
401
+ touchPlanIndexEntry,
402
+ transitionPlanStatus,
403
+ unarchivePlan,
404
+ unlinkPR,
405
+ unrejectUser,
406
+ updateLinkedPRStatus,
407
+ updatePlanIndexViewedBy,
408
+ validateA2AMessages
409
+ };