@bbigbang/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/dist/config.js +380 -0
  2. package/dist/execution/executionDispatcher.js +3810 -0
  3. package/dist/main.js +90 -0
  4. package/dist/nodeEventHistory.js +206 -0
  5. package/dist/scheduler/dreamLogic.js +50 -0
  6. package/dist/scheduler/dreamScheduler.js +65 -0
  7. package/dist/services/agentFileAccessService.js +1913 -0
  8. package/dist/services/agentRuntimeCleanupBroker.js +62 -0
  9. package/dist/services/agentSkillsBroker.js +118 -0
  10. package/dist/services/agentSkillsService.js +83 -0
  11. package/dist/services/agentWorkspaceBroker.js +937 -0
  12. package/dist/services/agentWorkspaceService.js +70 -0
  13. package/dist/services/appVersion.js +14 -0
  14. package/dist/services/auth.js +586 -0
  15. package/dist/services/claudeControlBroker.js +154 -0
  16. package/dist/services/claudeTranscriptBroker.js +100 -0
  17. package/dist/services/claudeTranscriptService.js +359 -0
  18. package/dist/services/codexAppServerBroker.js +155 -0
  19. package/dist/services/codexTranscriptBroker.js +98 -0
  20. package/dist/services/codexTranscriptService.js +961 -0
  21. package/dist/services/droidMissionBroker.js +124 -0
  22. package/dist/services/droidMissionImporter.js +630 -0
  23. package/dist/services/droidModelOptions.js +165 -0
  24. package/dist/services/hubServerRegistrationService.js +268 -0
  25. package/dist/services/libraryManifest.js +43 -0
  26. package/dist/services/libraryScaffold.js +26 -0
  27. package/dist/services/libraryService.js +2263 -0
  28. package/dist/services/memoryService.js +386 -0
  29. package/dist/services/missionEvidence.js +377 -0
  30. package/dist/services/missionService.js +2361 -0
  31. package/dist/services/missionTrace.js +158 -0
  32. package/dist/services/nativeMissionBriefParser.js +120 -0
  33. package/dist/services/nativeMissionOrchestrator.js +2045 -0
  34. package/dist/services/nativeMissionReportGenerator.js +227 -0
  35. package/dist/services/nativeMissionValidationRunner.js +452 -0
  36. package/dist/services/nativeMissionWorkerBroker.js +190 -0
  37. package/dist/services/nodeRegistry.js +34 -0
  38. package/dist/services/nodeStateReconciler.js +97 -0
  39. package/dist/services/panelMediaScanner.js +119 -0
  40. package/dist/services/persistentRuntimeJsonlClient.js +153 -0
  41. package/dist/services/platformAgentPolicy.js +180 -0
  42. package/dist/services/platformAgentService.js +2041 -0
  43. package/dist/services/projectAccessResolver.js +93 -0
  44. package/dist/services/projectService.js +392 -0
  45. package/dist/services/resourceSpaceService.js +140 -0
  46. package/dist/services/scenarioRuntimeService.js +1130 -0
  47. package/dist/services/suggestedPlannerService.js +868 -0
  48. package/dist/services/workbenchGitBroker.js +161 -0
  49. package/dist/services/workbenchGitService.js +69 -0
  50. package/dist/services/workbenchInspectBroker.js +65 -0
  51. package/dist/services/workbenchNodePathService.js +79 -0
  52. package/dist/services/workbenchRegistryService.js +240 -0
  53. package/dist/services/workbenchRootService.js +181 -0
  54. package/dist/services/workbenchTerminalBroker.js +378 -0
  55. package/dist/services/workspaceRunOwnership.js +60 -0
  56. package/dist/services/workspaceScaffold.js +105 -0
  57. package/dist/services/workspaceSessionRuntimeService.js +576 -0
  58. package/dist/services/workspaceSessionService.js +245 -0
  59. package/dist/services/workspaceToolActionRunner.js +1582 -0
  60. package/dist/services/workspaceToolErrors.js +10 -0
  61. package/dist/services/workspaceToolExecutionUtils.js +895 -0
  62. package/dist/services/workspaceToolLatestStateProjector.js +91 -0
  63. package/dist/services/workspaceToolManifest.js +572 -0
  64. package/dist/services/workspaceToolMutationQueue.js +43 -0
  65. package/dist/services/workspaceToolPanelProjection.js +460 -0
  66. package/dist/services/workspaceToolPromotion.js +255 -0
  67. package/dist/services/workspaceToolPromotionState.js +224 -0
  68. package/dist/services/workspaceToolPublishDiagnostics.js +189 -0
  69. package/dist/services/workspaceToolPublishIdentityResolver.js +146 -0
  70. package/dist/services/workspaceToolReadModel.js +378 -0
  71. package/dist/services/workspaceToolRunLedger.js +239 -0
  72. package/dist/services/workspaceToolService.js +3067 -0
  73. package/dist/services/workspaceToolSnapshotPanelSync.js +293 -0
  74. package/dist/services/workspaceToolTerminalLifecycle.js +283 -0
  75. package/dist/services/workspaceToolTypes.js +1 -0
  76. package/dist/services/workspaceToolUploadMaterializer.js +228 -0
  77. package/dist/web/actionCardRoutes.js +129 -0
  78. package/dist/web/actionCards.js +469 -0
  79. package/dist/web/activationContext.js +684 -0
  80. package/dist/web/agentChannelGuards.js +48 -0
  81. package/dist/web/agentMentionCooldowns.js +32 -0
  82. package/dist/web/agentReminders.js +1668 -0
  83. package/dist/web/agentRuntimePresence.js +197 -0
  84. package/dist/web/agentSelfState.js +494 -0
  85. package/dist/web/agentTaskLinks.js +26 -0
  86. package/dist/web/agentVisibility.js +79 -0
  87. package/dist/web/assets.js +95 -0
  88. package/dist/web/channelActivationPrompt.js +395 -0
  89. package/dist/web/channelMemoryNotes.js +127 -0
  90. package/dist/web/channelMentions.js +10 -0
  91. package/dist/web/channelMessageSequences.js +19 -0
  92. package/dist/web/channelSubscriptions.js +26 -0
  93. package/dist/web/clearedTaskRoots.js +10 -0
  94. package/dist/web/collaborationPromptGuidance.js +36 -0
  95. package/dist/web/collaborationSurfaceState.js +140 -0
  96. package/dist/web/contextBundleRanking.js +154 -0
  97. package/dist/web/contextBundleResolver.js +488 -0
  98. package/dist/web/conversationBuiltinSkillRoots.js +50 -0
  99. package/dist/web/conversationControls.js +232 -0
  100. package/dist/web/conversationHandoffs.js +612 -0
  101. package/dist/web/conversationManager.js +2511 -0
  102. package/dist/web/conversationSummaries.js +876 -0
  103. package/dist/web/conversationSurfaceKinds.js +17 -0
  104. package/dist/web/conversationTargets.js +173 -0
  105. package/dist/web/directActivationPrompt.js +122 -0
  106. package/dist/web/directReplyTargets.js +69 -0
  107. package/dist/web/directThreadResolver.js +129 -0
  108. package/dist/web/dmTaskHandoffPrompt.js +120 -0
  109. package/dist/web/dmTaskThreadStatusProjection.js +229 -0
  110. package/dist/web/ftsQuery.js +33 -0
  111. package/dist/web/internalAgentRouter.js +11341 -0
  112. package/dist/web/libraryCuratorScheduler.js +58 -0
  113. package/dist/web/libraryDocumentPromptGuidance.js +8 -0
  114. package/dist/web/messageCheckpoints.js +19 -0
  115. package/dist/web/nodeWsHandler.js +2495 -0
  116. package/dist/web/notificationRounds.js +1061 -0
  117. package/dist/web/panelActionMessages.js +108 -0
  118. package/dist/web/panelActivationPrompt.js +18 -0
  119. package/dist/web/panelAudit.js +273 -0
  120. package/dist/web/panelLifecycle.js +222 -0
  121. package/dist/web/panelMediaPolicy.js +43 -0
  122. package/dist/web/panelPathPolicy.js +63 -0
  123. package/dist/web/panelPreviews.js +175 -0
  124. package/dist/web/panelQueryHandles.js +2749 -0
  125. package/dist/web/panelRoutes.js +2147 -0
  126. package/dist/web/panels.js +904 -0
  127. package/dist/web/peerInboxAggregates.js +1247 -0
  128. package/dist/web/planApprovalState.js +92 -0
  129. package/dist/web/platformAgentScheduler.js +66 -0
  130. package/dist/web/proactiveOpportunities.js +452 -0
  131. package/dist/web/promptContextSections.js +242 -0
  132. package/dist/web/promptHistorySanitizer.js +26 -0
  133. package/dist/web/promptSlashCommands.js +158 -0
  134. package/dist/web/rollingConversationSummary.js +453 -0
  135. package/dist/web/routeHelpers.js +11 -0
  136. package/dist/web/routes/handoff.js +288 -0
  137. package/dist/web/routes/history.js +345 -0
  138. package/dist/web/routes/memory.js +258 -0
  139. package/dist/web/routes/selfState.js +171 -0
  140. package/dist/web/routes/workspace.js +154 -0
  141. package/dist/web/runSurfaceWatermarks.js +431 -0
  142. package/dist/web/runtimeCapabilities.js +48 -0
  143. package/dist/web/sameAgentHandoffs.js +494 -0
  144. package/dist/web/server.js +15567 -0
  145. package/dist/web/sharedCollaborationCapsules.js +163 -0
  146. package/dist/web/soloSessionRelay.js +42 -0
  147. package/dist/web/soloWsHandler.js +138 -0
  148. package/dist/web/suggestedPlannerScheduler.js +56 -0
  149. package/dist/web/surfaceActivationPolicy.js +108 -0
  150. package/dist/web/surfaceCollaborators.js +61 -0
  151. package/dist/web/surfaceSystemStatus.js +263 -0
  152. package/dist/web/targetParticipants.js +77 -0
  153. package/dist/web/taskEvents.js +49 -0
  154. package/dist/web/taskLifecycleMessages.js +165 -0
  155. package/dist/web/taskLoops.js +732 -0
  156. package/dist/web/taskMemoryNotes.js +224 -0
  157. package/dist/web/taskNumbers.js +16 -0
  158. package/dist/web/taskOwnerGuards.js +49 -0
  159. package/dist/web/taskParticipantResolver.js +42 -0
  160. package/dist/web/taskParticipants.js +97 -0
  161. package/dist/web/taskSourceDetails.js +20 -0
  162. package/dist/web/taskStateViews.js +210 -0
  163. package/dist/web/taskStatusTransitions.js +9 -0
  164. package/dist/web/taskThreadFollowups.js +599 -0
  165. package/dist/web/taskThreadRuntimeClosure.js +685 -0
  166. package/dist/web/taskUpdateDelivery.js +104 -0
  167. package/dist/web/threadReplyContentHeuristics.js +30 -0
  168. package/dist/web/threadRoots.js +61 -0
  169. package/dist/web/threadTaskBindings.js +365 -0
  170. package/dist/web/uiPanelPromptGuidance.js +27 -0
  171. package/dist/web/workspaceMemoryHints.js +143 -0
  172. package/dist/web/workspaceToolPromptGuidance.js +30 -0
  173. package/dist/web/wsHandler.js +397 -0
  174. package/dist/web/wsSink.js +116 -0
  175. package/package.json +54 -0
@@ -0,0 +1,431 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { CLEARED_TASK_ROOT_TARGET_GLOB } from './clearedTaskRoots.js';
3
+ import { resolveChannelFromTarget, resolveThreadRootId } from './conversationTargets.js';
4
+ function normalizeThreadRootId(threadRootId) {
5
+ return threadRootId?.trim() ?? '';
6
+ }
7
+ function normalizePositiveSeq(value) {
8
+ const parsed = Number(value);
9
+ if (!Number.isFinite(parsed) || parsed <= 0)
10
+ return null;
11
+ return Math.floor(parsed);
12
+ }
13
+ function sharedTargetKey() {
14
+ return '';
15
+ }
16
+ function activationSeenSeq(metadata) {
17
+ if (!metadata)
18
+ return null;
19
+ const candidates = [
20
+ normalizePositiveSeq(metadata.triggerMessage?.seq),
21
+ normalizePositiveSeq(metadata.mentionSuppression?.triggerSeq),
22
+ normalizePositiveSeq(metadata.peerInboxAggregate?.lastSeq),
23
+ normalizePositiveSeq(metadata.ownerAwareness?.triggerSeq),
24
+ ].filter((seq) => seq !== null);
25
+ if (candidates.length === 0)
26
+ return null;
27
+ return Math.max(...candidates);
28
+ }
29
+ function peerInboxItemSeenSeq(db, metadata) {
30
+ const itemMessageIds = metadata?.peerInboxAggregate?.itemMessageIds
31
+ ?.filter((messageId) => typeof messageId === 'string' && messageId.trim().length > 0)
32
+ .map((messageId) => messageId.trim());
33
+ if (!itemMessageIds || itemMessageIds.length === 0)
34
+ return null;
35
+ const placeholders = itemMessageIds.map(() => '?').join(', ');
36
+ const row = db.prepare(`SELECT MAX(seq) as maxSeq
37
+ FROM channel_messages
38
+ WHERE message_id IN (${placeholders})`).get(...itemMessageIds);
39
+ return normalizePositiveSeq(row?.maxSeq);
40
+ }
41
+ function runActivationBaselineForSurface(db, params) {
42
+ const row = db.prepare(`SELECT activation_metadata_json as activationMetadataJson,
43
+ reply_target as replyTarget
44
+ FROM run_debug_inputs
45
+ WHERE run_id = ?
46
+ ORDER BY created_at DESC, rowid DESC
47
+ LIMIT 1`).get(params.runId);
48
+ if (!row?.activationMetadataJson)
49
+ return null;
50
+ const replyTarget = row.replyTarget?.trim() || null;
51
+ if (replyTarget) {
52
+ const replyChannelId = resolveChannelFromTarget(replyTarget, db);
53
+ if (replyChannelId && replyChannelId !== params.channelId)
54
+ return null;
55
+ const replyThreadRootId = normalizeThreadRootId(resolveThreadRootId(replyTarget));
56
+ if (replyThreadRootId !== normalizeThreadRootId(params.threadRootId))
57
+ return null;
58
+ }
59
+ try {
60
+ const metadata = JSON.parse(row.activationMetadataJson);
61
+ const metadataSeq = activationSeenSeq(metadata);
62
+ const itemSeq = peerInboxItemSeenSeq(db, metadata);
63
+ return Math.max(metadataSeq ?? 0, itemSeq ?? 0) || null;
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ export function resolveRunWatermarkIdentity(db, agentId, params) {
70
+ const requestedRunId = params.runId?.trim() || null;
71
+ const requestedConversationId = params.conversationId?.trim() || null;
72
+ if (requestedRunId) {
73
+ const row = db.prepare(`SELECT r.run_id as runId,
74
+ c.id as conversationId,
75
+ c.agent_id as agentId
76
+ FROM runs r
77
+ LEFT JOIN conversations c ON c.session_key = r.session_key
78
+ WHERE r.run_id = ?
79
+ LIMIT 1`).get(requestedRunId);
80
+ if (!row || row.agentId !== agentId)
81
+ return null;
82
+ if (requestedConversationId && row.conversationId !== requestedConversationId)
83
+ return null;
84
+ return { runId: row.runId, conversationId: row.conversationId };
85
+ }
86
+ if (requestedConversationId) {
87
+ const row = db.prepare(`SELECT c.id as conversationId,
88
+ r.run_id as runId
89
+ FROM conversations c
90
+ JOIN runs r ON r.session_key = c.session_key
91
+ WHERE c.id = ?
92
+ AND c.agent_id = ?
93
+ AND r.ended_at IS NULL
94
+ ORDER BY r.started_at DESC, r.rowid DESC
95
+ LIMIT 1`).get(requestedConversationId, agentId);
96
+ return row ? { runId: row.runId, conversationId: row.conversationId } : null;
97
+ }
98
+ return null;
99
+ }
100
+ export function getRunSurfaceSeenSeq(db, params) {
101
+ const row = db.prepare(`SELECT seen_up_to_seq as seenUpToSeq
102
+ FROM agent_run_surface_watermarks
103
+ WHERE run_id = ?
104
+ AND channel_id = ?
105
+ AND thread_root_id = ?
106
+ AND target_key = ?
107
+ LIMIT 1`).get(params.runId, params.channelId, normalizeThreadRootId(params.threadRootId), params.targetKey ?? sharedTargetKey());
108
+ return row ? Math.max(0, Math.floor(row.seenUpToSeq)) : null;
109
+ }
110
+ export function bumpRunSurfaceWatermark(db, params) {
111
+ const seenUpToSeq = normalizePositiveSeq(params.seenUpToSeq);
112
+ if (seenUpToSeq === null)
113
+ return;
114
+ const now = params.now ?? Date.now();
115
+ db.prepare(`INSERT INTO agent_run_surface_watermarks(
116
+ run_id, agent_id, conversation_id, channel_id, thread_root_id, target_key,
117
+ seen_up_to_seq, source, updated_at
118
+ ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)
119
+ ON CONFLICT(run_id, channel_id, thread_root_id, target_key) DO UPDATE SET
120
+ seen_up_to_seq = MAX(agent_run_surface_watermarks.seen_up_to_seq, excluded.seen_up_to_seq),
121
+ agent_id = excluded.agent_id,
122
+ conversation_id = COALESCE(excluded.conversation_id, agent_run_surface_watermarks.conversation_id),
123
+ source = excluded.source,
124
+ updated_at = excluded.updated_at`).run(params.runId, params.agentId, params.conversationId ?? null, params.channelId, normalizeThreadRootId(params.threadRootId), params.targetKey ?? sharedTargetKey(), seenUpToSeq, params.source, now);
125
+ }
126
+ export function ensureRunSurfaceWatermarkFromActivation(db, params) {
127
+ if (params.channelId.startsWith('dm:'))
128
+ return null;
129
+ const existing = getRunSurfaceSeenSeq(db, {
130
+ runId: params.runId,
131
+ channelId: params.channelId,
132
+ threadRootId: params.threadRootId,
133
+ targetKey: sharedTargetKey(),
134
+ });
135
+ const metadataSeq = activationSeenSeq(params.metadata);
136
+ const itemSeq = peerInboxItemSeenSeq(db, params.metadata);
137
+ const baselineSeq = Math.max(metadataSeq ?? 0, itemSeq ?? 0) || null;
138
+ if (baselineSeq !== null) {
139
+ bumpRunSurfaceWatermark(db, {
140
+ runId: params.runId,
141
+ agentId: params.agentId,
142
+ conversationId: params.conversationId,
143
+ channelId: params.channelId,
144
+ threadRootId: params.threadRootId,
145
+ targetKey: sharedTargetKey(),
146
+ seenUpToSeq: baselineSeq,
147
+ source: 'activation',
148
+ now: params.now,
149
+ });
150
+ return Math.max(existing ?? 0, baselineSeq);
151
+ }
152
+ return existing;
153
+ }
154
+ export function recordRunSurfaceRowsSeen(db, params) {
155
+ if (!params.identity || params.rows.length === 0)
156
+ return;
157
+ const maxSeqBySurface = new Map();
158
+ for (const row of params.rows) {
159
+ if (!row.channelId || row.channelId.startsWith('dm:'))
160
+ continue;
161
+ const threadRootId = normalizeThreadRootId(params.threadRootIdOverride ?? row.threadRootId);
162
+ const key = `${row.channelId}::${threadRootId}`;
163
+ const current = maxSeqBySurface.get(key);
164
+ if (!current || row.seq > current.maxSeq) {
165
+ maxSeqBySurface.set(key, { channelId: row.channelId, threadRootId, maxSeq: row.seq });
166
+ }
167
+ }
168
+ for (const surface of maxSeqBySurface.values()) {
169
+ bumpRunSurfaceWatermark(db, {
170
+ runId: params.identity.runId,
171
+ agentId: params.agentId,
172
+ conversationId: params.identity.conversationId,
173
+ channelId: surface.channelId,
174
+ threadRootId: surface.threadRootId,
175
+ targetKey: sharedTargetKey(),
176
+ seenUpToSeq: surface.maxSeq,
177
+ source: params.source,
178
+ now: params.now,
179
+ });
180
+ }
181
+ }
182
+ export function recordRunSurfaceCatchUpRowsSeen(db, params) {
183
+ if (!params.identity || params.rows.length === 0 || params.channelId.startsWith('dm:'))
184
+ return;
185
+ const afterSeq = Math.max(0, Math.floor(params.afterSeq));
186
+ const threadRootId = normalizeThreadRootId(params.threadRootId);
187
+ const currentSeenSeq = getRunSurfaceSeenSeq(db, {
188
+ runId: params.identity.runId,
189
+ channelId: params.channelId,
190
+ threadRootId,
191
+ targetKey: sharedTargetKey(),
192
+ });
193
+ if (currentSeenSeq === null) {
194
+ const activationBaseline = runActivationBaselineForSurface(db, {
195
+ runId: params.identity.runId,
196
+ channelId: params.channelId,
197
+ threadRootId,
198
+ });
199
+ if (activationBaseline === afterSeq) {
200
+ bumpRunSurfaceWatermark(db, {
201
+ runId: params.identity.runId,
202
+ agentId: params.agentId,
203
+ conversationId: params.identity.conversationId,
204
+ channelId: params.channelId,
205
+ threadRootId,
206
+ targetKey: sharedTargetKey(),
207
+ seenUpToSeq: activationBaseline,
208
+ source: 'activation',
209
+ now: params.now,
210
+ });
211
+ }
212
+ }
213
+ const effectiveCurrentSeenSeq = getRunSurfaceSeenSeq(db, {
214
+ runId: params.identity.runId,
215
+ channelId: params.channelId,
216
+ threadRootId,
217
+ targetKey: sharedTargetKey(),
218
+ });
219
+ if (effectiveCurrentSeenSeq !== afterSeq)
220
+ return;
221
+ let maxSeq = null;
222
+ for (const row of params.rows) {
223
+ if (row.channelId !== params.channelId)
224
+ continue;
225
+ if (row.threadRootId !== undefined && normalizeThreadRootId(row.threadRootId) !== threadRootId)
226
+ continue;
227
+ if (row.seq <= afterSeq)
228
+ continue;
229
+ maxSeq = maxSeq === null ? row.seq : Math.max(maxSeq, row.seq);
230
+ }
231
+ if (maxSeq === null)
232
+ return;
233
+ bumpRunSurfaceWatermark(db, {
234
+ runId: params.identity.runId,
235
+ agentId: params.agentId,
236
+ conversationId: params.identity.conversationId,
237
+ channelId: params.channelId,
238
+ threadRootId,
239
+ targetKey: sharedTargetKey(),
240
+ seenUpToSeq: maxSeq,
241
+ source: params.source,
242
+ now: params.now,
243
+ });
244
+ }
245
+ export function findFreshnessConflict(db, params) {
246
+ if (params.channelId.startsWith('dm:'))
247
+ return null;
248
+ const seenUpToSeq = Math.max(0, Math.floor(params.seenUpToSeq));
249
+ const threadRootId = normalizeThreadRootId(params.threadRootId);
250
+ const scopeClause = threadRootId
251
+ ? `(cm.thread_root_id = ? OR (cm.thread_root_id IS NULL AND cm.target = ?))`
252
+ : `cm.thread_root_id IS NULL AND cm.target NOT GLOB ?`;
253
+ const scopeParams = threadRootId
254
+ ? [threadRootId, params.resolvedTarget]
255
+ : [CLEARED_TASK_ROOT_TARGET_GLOB];
256
+ const currentRunRow = db.prepare(`SELECT started_at as startedAt
257
+ FROM runs
258
+ WHERE run_id = ?
259
+ LIMIT 1`).get(params.currentRunId);
260
+ const currentRunStartedAt = Math.max(0, Math.floor(currentRunRow?.startedAt ?? 0));
261
+ const aggregate = db.prepare(`SELECT MIN(cm.seq) as blockedFromSeq,
262
+ MAX(cm.seq) as blockedToSeq
263
+ FROM channel_messages cm
264
+ WHERE cm.channel_id = ?
265
+ AND ${scopeClause}
266
+ AND cm.seq > ?
267
+ AND (cm.run_id IS NULL OR cm.run_id != ?)
268
+ AND (cm.sender_id != ? OR cm.created_at > ?)
269
+ AND cm.sender_type IN ('user', 'agent')`).get(params.channelId, ...scopeParams, seenUpToSeq, params.currentRunId, params.agentId, currentRunStartedAt);
270
+ if (!aggregate?.blockedFromSeq || !aggregate.blockedToSeq)
271
+ return null;
272
+ const rows = db.prepare(`SELECT cm.message_id as id,
273
+ cm.sender_id as senderId,
274
+ cm.sender_name as senderName,
275
+ cm.sender_type as senderType,
276
+ cm.target,
277
+ cm.content,
278
+ cm.seq,
279
+ cm.created_at as createdAt
280
+ FROM channel_messages cm
281
+ WHERE cm.channel_id = ?
282
+ AND ${scopeClause}
283
+ AND cm.seq > ?
284
+ AND (cm.run_id IS NULL OR cm.run_id != ?)
285
+ AND (cm.sender_id != ? OR cm.created_at > ?)
286
+ AND cm.sender_type IN ('user', 'agent')
287
+ ORDER BY cm.seq ASC
288
+ LIMIT ?`).all(params.channelId, ...scopeParams, seenUpToSeq, params.currentRunId, params.agentId, currentRunStartedAt, params.limit ?? 5);
289
+ return {
290
+ blockedFromSeq: aggregate.blockedFromSeq,
291
+ blockedToSeq: aggregate.blockedToSeq,
292
+ latestMessages: rows.map((row) => ({
293
+ id: row.id,
294
+ senderId: row.senderId,
295
+ senderName: row.senderName,
296
+ senderType: row.senderType,
297
+ target: row.target,
298
+ content: row.content,
299
+ seq: row.seq,
300
+ createdAt: new Date(row.createdAt).toISOString(),
301
+ })),
302
+ };
303
+ }
304
+ export function createHeldMessageDraft(db, params) {
305
+ const draftId = randomUUID();
306
+ const now = params.now ?? Date.now();
307
+ db.prepare(`INSERT INTO held_message_drafts(
308
+ draft_id, agent_id, conversation_id, run_id, resolved_target, channel_id,
309
+ thread_root_id, target_key, effective_kind, peer_delivery, attachment_ids_json,
310
+ content, seen_up_to_seq, blocked_from_seq, blocked_to_seq,
311
+ blocking_summary_json, status, created_at, updated_at
312
+ ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'held', ?, ?)`).run(draftId, params.agentId, params.conversationId ?? null, params.runId ?? null, params.resolvedTarget, params.channelId, normalizeThreadRootId(params.threadRootId), sharedTargetKey(), params.effectiveKind ?? null, params.peerDelivery ?? null, params.attachmentIdsJson ?? null, params.content, Math.max(0, Math.floor(params.seenUpToSeq)), params.conflict.blockedFromSeq, params.conflict.blockedToSeq, JSON.stringify(params.conflict.latestMessages), now, now);
313
+ return draftId;
314
+ }
315
+ export function createGuardedMessageDraft(db, params) {
316
+ const draftId = randomUUID();
317
+ const now = params.now ?? Date.now();
318
+ const seenUpToSeq = Math.max(0, Math.floor(params.seenUpToSeq ?? 0));
319
+ db.prepare(`INSERT INTO held_message_drafts(
320
+ draft_id, agent_id, conversation_id, run_id, resolved_target, channel_id,
321
+ thread_root_id, target_key, effective_kind, peer_delivery, attachment_ids_json,
322
+ content, seen_up_to_seq, blocked_from_seq, blocked_to_seq,
323
+ blocking_summary_json, status, created_at, updated_at
324
+ ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'held', ?, ?)`).run(draftId, params.agentId, params.conversationId ?? null, params.runId ?? null, params.resolvedTarget, params.channelId, normalizeThreadRootId(params.threadRootId), sharedTargetKey(), params.effectiveKind ?? null, params.peerDelivery ?? null, params.attachmentIdsJson ?? null, params.content, seenUpToSeq, seenUpToSeq, seenUpToSeq, JSON.stringify(params.blockingSummary), now, now);
325
+ return draftId;
326
+ }
327
+ function parseJsonOrNull(value) {
328
+ if (!value)
329
+ return null;
330
+ try {
331
+ return JSON.parse(value);
332
+ }
333
+ catch {
334
+ return null;
335
+ }
336
+ }
337
+ function parseAttachmentIds(value) {
338
+ const parsed = parseJsonOrNull(value);
339
+ if (!Array.isArray(parsed))
340
+ return [];
341
+ return parsed.filter((item) => typeof item === 'string' && item.trim().length > 0);
342
+ }
343
+ function blockingReasonFromSummary(summary, row) {
344
+ if (summary && typeof summary === 'object' && !Array.isArray(summary)) {
345
+ const reason = summary.reason;
346
+ return typeof reason === 'string' && reason.trim().length > 0 ? reason : null;
347
+ }
348
+ if (Array.isArray(summary)) {
349
+ return 'stale_surface_conflict';
350
+ }
351
+ return null;
352
+ }
353
+ function contentPreview(content) {
354
+ const normalized = content.replace(/\s+/g, ' ').trim();
355
+ return normalized.length > 240 ? `${normalized.slice(0, 240)}...` : normalized;
356
+ }
357
+ export function listHeldMessageDraftsForAgent(db, params) {
358
+ const where = ['agent_id = ?'];
359
+ const args = [params.agentId];
360
+ const runId = params.runId?.trim();
361
+ if (runId) {
362
+ where.push('run_id = ?');
363
+ args.push(runId);
364
+ }
365
+ const draftId = params.draftId?.trim();
366
+ if (draftId) {
367
+ where.push('draft_id = ?');
368
+ args.push(draftId);
369
+ }
370
+ const status = params.status?.trim();
371
+ if (status) {
372
+ where.push('status = ?');
373
+ args.push(status);
374
+ }
375
+ const limit = Math.max(1, Math.min(Math.floor(params.limit ?? 20), 100));
376
+ const rows = db.prepare(`SELECT draft_id as draftId,
377
+ agent_id as agentId,
378
+ conversation_id as conversationId,
379
+ run_id as runId,
380
+ resolved_target as resolvedTarget,
381
+ channel_id as channelId,
382
+ thread_root_id as threadRootId,
383
+ effective_kind as effectiveKind,
384
+ peer_delivery as peerDelivery,
385
+ attachment_ids_json as attachmentIdsJson,
386
+ content,
387
+ seen_up_to_seq as seenUpToSeq,
388
+ blocked_from_seq as blockedFromSeq,
389
+ blocked_to_seq as blockedToSeq,
390
+ blocking_summary_json as blockingSummaryJson,
391
+ status,
392
+ created_at as createdAt,
393
+ updated_at as updatedAt
394
+ FROM held_message_drafts
395
+ WHERE ${where.join(' AND ')}
396
+ ORDER BY created_at DESC, rowid DESC
397
+ LIMIT ?`).all(...args, limit);
398
+ return rows.map((row) => {
399
+ const blockingSummary = parseJsonOrNull(row.blockingSummaryJson);
400
+ const base = {
401
+ draftId: row.draftId,
402
+ agentId: row.agentId,
403
+ conversationId: row.conversationId,
404
+ runId: row.runId,
405
+ resolvedTarget: row.resolvedTarget,
406
+ channelId: row.channelId,
407
+ threadRootId: row.threadRootId && row.threadRootId.length > 0 ? row.threadRootId : null,
408
+ effectiveKind: row.effectiveKind,
409
+ peerDelivery: row.peerDelivery,
410
+ attachmentIds: parseAttachmentIds(row.attachmentIdsJson),
411
+ contentPreview: contentPreview(row.content),
412
+ contentLength: row.content.length,
413
+ seenUpToSeq: row.seenUpToSeq,
414
+ blockedFromSeq: row.blockedFromSeq,
415
+ blockedToSeq: row.blockedToSeq,
416
+ blockingReason: blockingReasonFromSummary(blockingSummary, row),
417
+ blockingSummary,
418
+ status: row.status,
419
+ createdAt: row.createdAt,
420
+ updatedAt: row.updatedAt,
421
+ };
422
+ return params.includeContent ? { ...base, content: row.content } : base;
423
+ });
424
+ }
425
+ export function buildFreshnessReadHistoryInstruction(resolvedTarget, seenUpToSeq, surface = 'bigbang') {
426
+ const escapedTarget = resolvedTarget.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
427
+ if (surface === 'mcp') {
428
+ return `read_history(channel="${escapedTarget}", after=${Math.max(0, Math.floor(seenUpToSeq))}, limit=20)`;
429
+ }
430
+ return `bigbang message read --channel "${escapedTarget}" --after ${Math.max(0, Math.floor(seenUpToSeq))} --limit 20`;
431
+ }
@@ -0,0 +1,48 @@
1
+ import { listAgentRuntimeCapabilities, } from '@bbigbang/protocol';
2
+ function isAgentRuntimeCapability(value) {
3
+ return value === 'activeTurnSteer'
4
+ || value === 'planApprovalLoop';
5
+ }
6
+ function isAgentType(value) {
7
+ return value === 'claude_acp'
8
+ || value === 'claude_sdk'
9
+ || value === 'codex_acp'
10
+ || value === 'codex_app_server';
11
+ }
12
+ function shouldUseStaticCapabilityFallback(agentType) {
13
+ return agentType !== 'claude_sdk';
14
+ }
15
+ function parseRuntimeDrivers(value) {
16
+ if (!value)
17
+ return null;
18
+ try {
19
+ const parsed = JSON.parse(value);
20
+ return Array.isArray(parsed) ? parsed : null;
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ export function listEffectiveAgentRuntimeCapabilities(db, params) {
27
+ if (!isAgentType(params.agentType))
28
+ return [];
29
+ const fallback = listAgentRuntimeCapabilities(params.agentType);
30
+ const nodeId = params.nodeId?.trim();
31
+ if (!nodeId)
32
+ return shouldUseStaticCapabilityFallback(params.agentType) ? fallback : [];
33
+ const row = db.prepare(`SELECT runtime_drivers_json as runtimeDriversJson
34
+ FROM node_runtime_snapshots
35
+ WHERE node_id = ?`).get(nodeId);
36
+ const runtimeDrivers = parseRuntimeDrivers(row?.runtimeDriversJson);
37
+ if (!runtimeDrivers)
38
+ return shouldUseStaticCapabilityFallback(params.agentType) ? fallback : [];
39
+ const driver = runtimeDrivers.find((candidate) => candidate?.agentType === params.agentType);
40
+ if (!driver)
41
+ return [];
42
+ if (!Array.isArray(driver.capabilities))
43
+ return shouldUseStaticCapabilityFallback(params.agentType) ? fallback : [];
44
+ return driver.capabilities.filter(isAgentRuntimeCapability);
45
+ }
46
+ export function hasEffectiveAgentRuntimeCapability(db, params) {
47
+ return listEffectiveAgentRuntimeCapabilities(db, params).includes(params.capability);
48
+ }