@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.
- package/dist/config.js +380 -0
- package/dist/execution/executionDispatcher.js +3810 -0
- package/dist/main.js +90 -0
- package/dist/nodeEventHistory.js +206 -0
- package/dist/scheduler/dreamLogic.js +50 -0
- package/dist/scheduler/dreamScheduler.js +65 -0
- package/dist/services/agentFileAccessService.js +1913 -0
- package/dist/services/agentRuntimeCleanupBroker.js +62 -0
- package/dist/services/agentSkillsBroker.js +118 -0
- package/dist/services/agentSkillsService.js +83 -0
- package/dist/services/agentWorkspaceBroker.js +937 -0
- package/dist/services/agentWorkspaceService.js +70 -0
- package/dist/services/appVersion.js +14 -0
- package/dist/services/auth.js +586 -0
- package/dist/services/claudeControlBroker.js +154 -0
- package/dist/services/claudeTranscriptBroker.js +100 -0
- package/dist/services/claudeTranscriptService.js +359 -0
- package/dist/services/codexAppServerBroker.js +155 -0
- package/dist/services/codexTranscriptBroker.js +98 -0
- package/dist/services/codexTranscriptService.js +961 -0
- package/dist/services/droidMissionBroker.js +124 -0
- package/dist/services/droidMissionImporter.js +630 -0
- package/dist/services/droidModelOptions.js +165 -0
- package/dist/services/hubServerRegistrationService.js +268 -0
- package/dist/services/libraryManifest.js +43 -0
- package/dist/services/libraryScaffold.js +26 -0
- package/dist/services/libraryService.js +2263 -0
- package/dist/services/memoryService.js +386 -0
- package/dist/services/missionEvidence.js +377 -0
- package/dist/services/missionService.js +2361 -0
- package/dist/services/missionTrace.js +158 -0
- package/dist/services/nativeMissionBriefParser.js +120 -0
- package/dist/services/nativeMissionOrchestrator.js +2045 -0
- package/dist/services/nativeMissionReportGenerator.js +227 -0
- package/dist/services/nativeMissionValidationRunner.js +452 -0
- package/dist/services/nativeMissionWorkerBroker.js +190 -0
- package/dist/services/nodeRegistry.js +34 -0
- package/dist/services/nodeStateReconciler.js +97 -0
- package/dist/services/panelMediaScanner.js +119 -0
- package/dist/services/persistentRuntimeJsonlClient.js +153 -0
- package/dist/services/platformAgentPolicy.js +180 -0
- package/dist/services/platformAgentService.js +2041 -0
- package/dist/services/projectAccessResolver.js +93 -0
- package/dist/services/projectService.js +392 -0
- package/dist/services/resourceSpaceService.js +140 -0
- package/dist/services/scenarioRuntimeService.js +1130 -0
- package/dist/services/suggestedPlannerService.js +868 -0
- package/dist/services/workbenchGitBroker.js +161 -0
- package/dist/services/workbenchGitService.js +69 -0
- package/dist/services/workbenchInspectBroker.js +65 -0
- package/dist/services/workbenchNodePathService.js +79 -0
- package/dist/services/workbenchRegistryService.js +240 -0
- package/dist/services/workbenchRootService.js +181 -0
- package/dist/services/workbenchTerminalBroker.js +378 -0
- package/dist/services/workspaceRunOwnership.js +60 -0
- package/dist/services/workspaceScaffold.js +105 -0
- package/dist/services/workspaceSessionRuntimeService.js +576 -0
- package/dist/services/workspaceSessionService.js +245 -0
- package/dist/services/workspaceToolActionRunner.js +1582 -0
- package/dist/services/workspaceToolErrors.js +10 -0
- package/dist/services/workspaceToolExecutionUtils.js +895 -0
- package/dist/services/workspaceToolLatestStateProjector.js +91 -0
- package/dist/services/workspaceToolManifest.js +572 -0
- package/dist/services/workspaceToolMutationQueue.js +43 -0
- package/dist/services/workspaceToolPanelProjection.js +460 -0
- package/dist/services/workspaceToolPromotion.js +255 -0
- package/dist/services/workspaceToolPromotionState.js +224 -0
- package/dist/services/workspaceToolPublishDiagnostics.js +189 -0
- package/dist/services/workspaceToolPublishIdentityResolver.js +146 -0
- package/dist/services/workspaceToolReadModel.js +378 -0
- package/dist/services/workspaceToolRunLedger.js +239 -0
- package/dist/services/workspaceToolService.js +3067 -0
- package/dist/services/workspaceToolSnapshotPanelSync.js +293 -0
- package/dist/services/workspaceToolTerminalLifecycle.js +283 -0
- package/dist/services/workspaceToolTypes.js +1 -0
- package/dist/services/workspaceToolUploadMaterializer.js +228 -0
- package/dist/web/actionCardRoutes.js +129 -0
- package/dist/web/actionCards.js +469 -0
- package/dist/web/activationContext.js +684 -0
- package/dist/web/agentChannelGuards.js +48 -0
- package/dist/web/agentMentionCooldowns.js +32 -0
- package/dist/web/agentReminders.js +1668 -0
- package/dist/web/agentRuntimePresence.js +197 -0
- package/dist/web/agentSelfState.js +494 -0
- package/dist/web/agentTaskLinks.js +26 -0
- package/dist/web/agentVisibility.js +79 -0
- package/dist/web/assets.js +95 -0
- package/dist/web/channelActivationPrompt.js +395 -0
- package/dist/web/channelMemoryNotes.js +127 -0
- package/dist/web/channelMentions.js +10 -0
- package/dist/web/channelMessageSequences.js +19 -0
- package/dist/web/channelSubscriptions.js +26 -0
- package/dist/web/clearedTaskRoots.js +10 -0
- package/dist/web/collaborationPromptGuidance.js +36 -0
- package/dist/web/collaborationSurfaceState.js +140 -0
- package/dist/web/contextBundleRanking.js +154 -0
- package/dist/web/contextBundleResolver.js +488 -0
- package/dist/web/conversationBuiltinSkillRoots.js +50 -0
- package/dist/web/conversationControls.js +232 -0
- package/dist/web/conversationHandoffs.js +612 -0
- package/dist/web/conversationManager.js +2511 -0
- package/dist/web/conversationSummaries.js +876 -0
- package/dist/web/conversationSurfaceKinds.js +17 -0
- package/dist/web/conversationTargets.js +173 -0
- package/dist/web/directActivationPrompt.js +122 -0
- package/dist/web/directReplyTargets.js +69 -0
- package/dist/web/directThreadResolver.js +129 -0
- package/dist/web/dmTaskHandoffPrompt.js +120 -0
- package/dist/web/dmTaskThreadStatusProjection.js +229 -0
- package/dist/web/ftsQuery.js +33 -0
- package/dist/web/internalAgentRouter.js +11341 -0
- package/dist/web/libraryCuratorScheduler.js +58 -0
- package/dist/web/libraryDocumentPromptGuidance.js +8 -0
- package/dist/web/messageCheckpoints.js +19 -0
- package/dist/web/nodeWsHandler.js +2495 -0
- package/dist/web/notificationRounds.js +1061 -0
- package/dist/web/panelActionMessages.js +108 -0
- package/dist/web/panelActivationPrompt.js +18 -0
- package/dist/web/panelAudit.js +273 -0
- package/dist/web/panelLifecycle.js +222 -0
- package/dist/web/panelMediaPolicy.js +43 -0
- package/dist/web/panelPathPolicy.js +63 -0
- package/dist/web/panelPreviews.js +175 -0
- package/dist/web/panelQueryHandles.js +2749 -0
- package/dist/web/panelRoutes.js +2147 -0
- package/dist/web/panels.js +904 -0
- package/dist/web/peerInboxAggregates.js +1247 -0
- package/dist/web/planApprovalState.js +92 -0
- package/dist/web/platformAgentScheduler.js +66 -0
- package/dist/web/proactiveOpportunities.js +452 -0
- package/dist/web/promptContextSections.js +242 -0
- package/dist/web/promptHistorySanitizer.js +26 -0
- package/dist/web/promptSlashCommands.js +158 -0
- package/dist/web/rollingConversationSummary.js +453 -0
- package/dist/web/routeHelpers.js +11 -0
- package/dist/web/routes/handoff.js +288 -0
- package/dist/web/routes/history.js +345 -0
- package/dist/web/routes/memory.js +258 -0
- package/dist/web/routes/selfState.js +171 -0
- package/dist/web/routes/workspace.js +154 -0
- package/dist/web/runSurfaceWatermarks.js +431 -0
- package/dist/web/runtimeCapabilities.js +48 -0
- package/dist/web/sameAgentHandoffs.js +494 -0
- package/dist/web/server.js +15567 -0
- package/dist/web/sharedCollaborationCapsules.js +163 -0
- package/dist/web/soloSessionRelay.js +42 -0
- package/dist/web/soloWsHandler.js +138 -0
- package/dist/web/suggestedPlannerScheduler.js +56 -0
- package/dist/web/surfaceActivationPolicy.js +108 -0
- package/dist/web/surfaceCollaborators.js +61 -0
- package/dist/web/surfaceSystemStatus.js +263 -0
- package/dist/web/targetParticipants.js +77 -0
- package/dist/web/taskEvents.js +49 -0
- package/dist/web/taskLifecycleMessages.js +165 -0
- package/dist/web/taskLoops.js +732 -0
- package/dist/web/taskMemoryNotes.js +224 -0
- package/dist/web/taskNumbers.js +16 -0
- package/dist/web/taskOwnerGuards.js +49 -0
- package/dist/web/taskParticipantResolver.js +42 -0
- package/dist/web/taskParticipants.js +97 -0
- package/dist/web/taskSourceDetails.js +20 -0
- package/dist/web/taskStateViews.js +210 -0
- package/dist/web/taskStatusTransitions.js +9 -0
- package/dist/web/taskThreadFollowups.js +599 -0
- package/dist/web/taskThreadRuntimeClosure.js +685 -0
- package/dist/web/taskUpdateDelivery.js +104 -0
- package/dist/web/threadReplyContentHeuristics.js +30 -0
- package/dist/web/threadRoots.js +61 -0
- package/dist/web/threadTaskBindings.js +365 -0
- package/dist/web/uiPanelPromptGuidance.js +27 -0
- package/dist/web/workspaceMemoryHints.js +143 -0
- package/dist/web/workspaceToolPromptGuidance.js +30 -0
- package/dist/web/wsHandler.js +397 -0
- package/dist/web/wsSink.js +116 -0
- package/package.json +54 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { resolveWorkspaceToolPublishIdentityState, } from './workspaceToolPromotionState.js';
|
|
2
|
+
export class WorkspaceToolPublishIdentityResolver {
|
|
3
|
+
db;
|
|
4
|
+
constructor(db) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
}
|
|
7
|
+
resolve(params) {
|
|
8
|
+
const promotionLink = params.sourceConversationId
|
|
9
|
+
? this.loadPanelPromotionByConversation(params.sourceConversationId)
|
|
10
|
+
: null;
|
|
11
|
+
const existingByMaintenanceConversation = params.sourceConversationId
|
|
12
|
+
? this.loadWorkspaceToolIdentityByMaintenanceConversation(params.userId, params.agentId, params.sourceConversationId)
|
|
13
|
+
: undefined;
|
|
14
|
+
const linkedTool = promotionLink?.toolId
|
|
15
|
+
? this.loadLiveWorkspaceToolIdentityByToolId(promotionLink.toolId)
|
|
16
|
+
: undefined;
|
|
17
|
+
const sourcePanelId = promotionLink?.panelId
|
|
18
|
+
?? linkedTool?.sourcePanelId
|
|
19
|
+
?? existingByMaintenanceConversation?.sourcePanelId
|
|
20
|
+
?? null;
|
|
21
|
+
const existingByPanelId = sourcePanelId
|
|
22
|
+
? this.loadWorkspaceToolIdentityByPanelId(params.userId, params.agentId, sourcePanelId)
|
|
23
|
+
: undefined;
|
|
24
|
+
const collaboratorSlug = this.loadWorkspaceToolIdentityByCollaboratorSlug(params.userId, params.agentId, params.slug);
|
|
25
|
+
const existingByCollaboratorSlug = collaboratorSlug.row;
|
|
26
|
+
const existingBySlug = this.loadOwnedWorkspaceToolIdentityBySlug(params.userId, params.agentId, params.slug);
|
|
27
|
+
const publishState = resolveWorkspaceToolPublishIdentityState({
|
|
28
|
+
promotionLink,
|
|
29
|
+
linkedTool,
|
|
30
|
+
existingByMaintenanceConversation,
|
|
31
|
+
existingByPanelId,
|
|
32
|
+
existingByCollaboratorSlug,
|
|
33
|
+
existingBySlug,
|
|
34
|
+
allowCreateNewTool: params.allowCreateNewTool,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
promotionLink,
|
|
38
|
+
existingByMaintenanceConversation,
|
|
39
|
+
existingByPanelId,
|
|
40
|
+
existingByCollaboratorSlug,
|
|
41
|
+
existingBySlug,
|
|
42
|
+
linkedTool,
|
|
43
|
+
sourcePanelId,
|
|
44
|
+
loadConflict: collaboratorSlug.conflict,
|
|
45
|
+
publishState,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
loadPanelPromotionByConversation(conversationId) {
|
|
49
|
+
return this.db.prepare(`SELECT ptp.panel_id as panelId,
|
|
50
|
+
ptp.user_id as userId,
|
|
51
|
+
ptp.agent_id as agentId,
|
|
52
|
+
ptp.promotion_conversation_id as promotionConversationId,
|
|
53
|
+
ptp.tool_id as linkedToolId,
|
|
54
|
+
wt.deleted_at as linkedToolDeletedAt,
|
|
55
|
+
CASE WHEN wt.deleted_at IS NULL THEN wt.tool_id ELSE NULL END as toolId,
|
|
56
|
+
CASE WHEN wt.deleted_at IS NULL THEN wt.name ELSE NULL END as toolName,
|
|
57
|
+
CASE WHEN wt.deleted_at IS NULL THEN wt.revision ELSE NULL END as toolRevision,
|
|
58
|
+
CASE WHEN wt.deleted_at IS NULL THEN wt.maintenance_conversation_id ELSE NULL END as maintenanceConversationId,
|
|
59
|
+
ptp.created_at as createdAt,
|
|
60
|
+
ptp.updated_at as updatedAt
|
|
61
|
+
FROM panel_tool_promotions ptp
|
|
62
|
+
LEFT JOIN workspace_tools wt
|
|
63
|
+
ON wt.tool_id = ptp.tool_id
|
|
64
|
+
WHERE ptp.promotion_conversation_id = ?
|
|
65
|
+
OR wt.maintenance_conversation_id = ?
|
|
66
|
+
LIMIT 1`).get(conversationId, conversationId) ?? null;
|
|
67
|
+
}
|
|
68
|
+
loadWorkspaceToolIdentityByMaintenanceConversation(userId, agentId, maintenanceConversationId) {
|
|
69
|
+
return this.db.prepare(`${workspaceToolIdentitySelectSql()}
|
|
70
|
+
WHERE user_id = ?
|
|
71
|
+
AND agent_id = ?
|
|
72
|
+
AND maintenance_conversation_id = ?
|
|
73
|
+
ORDER BY deleted_at IS NULL DESC, updated_at DESC
|
|
74
|
+
LIMIT 1`).get(userId, agentId, maintenanceConversationId);
|
|
75
|
+
}
|
|
76
|
+
loadLiveWorkspaceToolIdentityByToolId(toolId) {
|
|
77
|
+
return this.db.prepare(`${workspaceToolIdentitySelectSql()}
|
|
78
|
+
WHERE tool_id = ?
|
|
79
|
+
AND deleted_at IS NULL
|
|
80
|
+
LIMIT 1`).get(toolId);
|
|
81
|
+
}
|
|
82
|
+
loadWorkspaceToolIdentityByPanelId(userId, agentId, panelId) {
|
|
83
|
+
return this.db.prepare(`${workspaceToolIdentitySelectSql()}
|
|
84
|
+
WHERE user_id = ?
|
|
85
|
+
AND agent_id = ?
|
|
86
|
+
AND source_panel_id = ?
|
|
87
|
+
ORDER BY deleted_at IS NULL DESC, updated_at DESC
|
|
88
|
+
LIMIT 1`).get(userId, agentId, panelId);
|
|
89
|
+
}
|
|
90
|
+
loadWorkspaceToolIdentityByCollaboratorSlug(userId, agentId, slug) {
|
|
91
|
+
const rows = this.db.prepare(`SELECT wt.tool_id as toolId,
|
|
92
|
+
wt.user_id as userId,
|
|
93
|
+
wt.agent_id as agentId,
|
|
94
|
+
wt.source_panel_id as sourcePanelId,
|
|
95
|
+
wt.panel_id as panelId,
|
|
96
|
+
wt.slug,
|
|
97
|
+
wt.active_terminal_id as activeTerminalId,
|
|
98
|
+
wt.maintenance_conversation_id as maintenanceConversationId,
|
|
99
|
+
wt.revision,
|
|
100
|
+
wt.deleted_at as deletedAt
|
|
101
|
+
FROM workspace_tools wt
|
|
102
|
+
JOIN surface_collaborators sc
|
|
103
|
+
ON sc.surface_type = 'tool'
|
|
104
|
+
AND sc.surface_id = wt.tool_id
|
|
105
|
+
AND sc.agent_id = ?
|
|
106
|
+
WHERE wt.user_id = ?
|
|
107
|
+
AND wt.slug = ?
|
|
108
|
+
AND wt.agent_id != ?
|
|
109
|
+
AND wt.deleted_at IS NULL
|
|
110
|
+
ORDER BY wt.updated_at DESC, wt.created_at DESC`).all(agentId, userId, slug, agentId);
|
|
111
|
+
if (rows.length > 1) {
|
|
112
|
+
return {
|
|
113
|
+
row: null,
|
|
114
|
+
conflict: {
|
|
115
|
+
kind: 'ambiguous_collaborator_slug',
|
|
116
|
+
message: `Multiple tools named "${slug}" list this agent as a maintainer; publish from the owner maintenance chat to disambiguate.`,
|
|
117
|
+
statusCode: 409,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
row: rows[0] ?? null,
|
|
123
|
+
conflict: null,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
loadOwnedWorkspaceToolIdentityBySlug(userId, agentId, slug) {
|
|
127
|
+
return this.db.prepare(`${workspaceToolIdentitySelectSql()}
|
|
128
|
+
WHERE user_id = ?
|
|
129
|
+
AND agent_id = ?
|
|
130
|
+
AND slug = ?
|
|
131
|
+
LIMIT 1`).get(userId, agentId, slug);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function workspaceToolIdentitySelectSql() {
|
|
135
|
+
return `SELECT tool_id as toolId,
|
|
136
|
+
user_id as userId,
|
|
137
|
+
agent_id as agentId,
|
|
138
|
+
source_panel_id as sourcePanelId,
|
|
139
|
+
panel_id as panelId,
|
|
140
|
+
slug,
|
|
141
|
+
active_terminal_id as activeTerminalId,
|
|
142
|
+
maintenance_conversation_id as maintenanceConversationId,
|
|
143
|
+
revision,
|
|
144
|
+
deleted_at as deletedAt
|
|
145
|
+
FROM workspace_tools`;
|
|
146
|
+
}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { getUserAgentAccess, getUserChannelAccess } from './auth.js';
|
|
2
|
+
import { parseStateRowJson, runRowToInfo, } from './workspaceToolExecutionUtils.js';
|
|
3
|
+
import { parseWorkspaceToolManifest, resolveWorkspaceToolActionMode, sanitizeWorkspaceToolManifestForViewer, } from './workspaceToolManifest.js';
|
|
4
|
+
import { deriveWorkspaceToolBusinessState, deriveWorkspaceToolRuntimeState, } from './workspaceToolPanelProjection.js';
|
|
5
|
+
const WORKSPACE_TOOL_ROW_SELECT = `
|
|
6
|
+
wt.tool_id as toolId,
|
|
7
|
+
wt.user_id as userId,
|
|
8
|
+
wt.agent_id as agentId,
|
|
9
|
+
a.name as agentName,
|
|
10
|
+
a.node_id as agentNodeId,
|
|
11
|
+
a.workspace_path as agentWorkspacePath,
|
|
12
|
+
a.deleted_at as agentDeletedAt,
|
|
13
|
+
n.status as agentNodeStatus,
|
|
14
|
+
wt.source_panel_id as sourcePanelId,
|
|
15
|
+
wt.panel_id as panelId,
|
|
16
|
+
wt.slug,
|
|
17
|
+
wt.name,
|
|
18
|
+
wt.description,
|
|
19
|
+
wt.icon,
|
|
20
|
+
wt.scope,
|
|
21
|
+
wt.scope_channel_id as scopeChannelId,
|
|
22
|
+
wt.allow_shared_exec as allowSharedExec,
|
|
23
|
+
wt.public_review_status as publicReviewStatus,
|
|
24
|
+
wt.pending_public_review as pendingPublicReview,
|
|
25
|
+
wt.manifest_path as manifestPath,
|
|
26
|
+
wt.bundle_root as bundleRoot,
|
|
27
|
+
wt.manifest_json as manifestJson,
|
|
28
|
+
wt.latest_state_json as latestStateJson,
|
|
29
|
+
wt.active_terminal_id as activeTerminalId,
|
|
30
|
+
wt.maintenance_conversation_id as maintenanceConversationId,
|
|
31
|
+
wt.source_conversation_id as sourceConversationId,
|
|
32
|
+
wt.source_message_id as sourceMessageId,
|
|
33
|
+
wt.cloned_from_tool_id as clonedFromToolId,
|
|
34
|
+
wt.cloned_from_revision as clonedFromRevision,
|
|
35
|
+
wt.revision,
|
|
36
|
+
wt.created_at as createdAt,
|
|
37
|
+
wt.updated_at as updatedAt,
|
|
38
|
+
wt.deleted_at as deletedAt
|
|
39
|
+
`;
|
|
40
|
+
function parseVerificationDetails(raw) {
|
|
41
|
+
if (!raw)
|
|
42
|
+
return null;
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(raw);
|
|
45
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
46
|
+
? parsed
|
|
47
|
+
: null;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function workspaceToolRunRowToInfoForViewer(row, actionKind, params) {
|
|
54
|
+
const info = runRowToInfo(row, actionKind);
|
|
55
|
+
const canViewOwnerFields = params.canViewOwnerFields === true || params.viewerUserId === params.ownerUserId;
|
|
56
|
+
const canViewRunInvocation = canViewOwnerFields || params.viewerUserId === (row.requestedByUserId ?? null);
|
|
57
|
+
const visibleInfo = canViewOwnerFields ? info : { ...info, executionWorkspacePath: null };
|
|
58
|
+
if (canViewRunInvocation) {
|
|
59
|
+
return visibleInfo;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...visibleInfo,
|
|
63
|
+
terminalId: null,
|
|
64
|
+
params: null,
|
|
65
|
+
requestedByUserId: null,
|
|
66
|
+
requestedByUsername: null,
|
|
67
|
+
requestedByAgentId: null,
|
|
68
|
+
requestedByAgentName: null,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export class WorkspaceToolReadModel {
|
|
72
|
+
db;
|
|
73
|
+
constructor(db) {
|
|
74
|
+
this.db = db;
|
|
75
|
+
}
|
|
76
|
+
loadUsername(userId) {
|
|
77
|
+
const row = this.db.prepare(`SELECT username
|
|
78
|
+
FROM users
|
|
79
|
+
WHERE id = ?`).get(userId);
|
|
80
|
+
return row?.username ?? null;
|
|
81
|
+
}
|
|
82
|
+
isAdminUser(userId) {
|
|
83
|
+
const row = this.db.prepare(`SELECT is_admin as isAdmin
|
|
84
|
+
FROM users
|
|
85
|
+
WHERE id = ?`).get(userId);
|
|
86
|
+
return row?.isAdmin === 1;
|
|
87
|
+
}
|
|
88
|
+
loadToolRowForUser(userId, toolId) {
|
|
89
|
+
return this.db.prepare(`SELECT ${WORKSPACE_TOOL_ROW_SELECT}
|
|
90
|
+
FROM workspace_tools wt
|
|
91
|
+
LEFT JOIN agents a ON a.agent_id = wt.agent_id
|
|
92
|
+
LEFT JOIN nodes n ON n.node_id = a.node_id
|
|
93
|
+
WHERE wt.tool_id = ?
|
|
94
|
+
AND wt.user_id = ?
|
|
95
|
+
AND wt.deleted_at IS NULL
|
|
96
|
+
LIMIT 1`).get(toolId, userId) ?? null;
|
|
97
|
+
}
|
|
98
|
+
loadToolRowById(toolId) {
|
|
99
|
+
return this.db.prepare(`SELECT ${WORKSPACE_TOOL_ROW_SELECT}
|
|
100
|
+
FROM workspace_tools wt
|
|
101
|
+
LEFT JOIN agents a ON a.agent_id = wt.agent_id
|
|
102
|
+
LEFT JOIN nodes n ON n.node_id = a.node_id
|
|
103
|
+
WHERE wt.tool_id = ?
|
|
104
|
+
AND wt.deleted_at IS NULL
|
|
105
|
+
LIMIT 1`).get(toolId) ?? null;
|
|
106
|
+
}
|
|
107
|
+
loadToolRowForViewer(userId, toolId, options) {
|
|
108
|
+
if (options?.allowAdminBypass && this.isAdminUser(userId)) {
|
|
109
|
+
return this.loadToolRowById(toolId);
|
|
110
|
+
}
|
|
111
|
+
const allowedChannelIds = getUserChannelAccess(this.db, userId);
|
|
112
|
+
const rows = this.loadVisibleToolRowsForViewer(userId, {
|
|
113
|
+
toolIds: [toolId],
|
|
114
|
+
allowedChannelIds,
|
|
115
|
+
});
|
|
116
|
+
return rows[0] ?? null;
|
|
117
|
+
}
|
|
118
|
+
loadToolRowByPanelIdForViewer(userId, panelId) {
|
|
119
|
+
if (this.isAdminUser(userId)) {
|
|
120
|
+
return this.db.prepare(`SELECT ${WORKSPACE_TOOL_ROW_SELECT}
|
|
121
|
+
FROM workspace_tools wt
|
|
122
|
+
LEFT JOIN agents a ON a.agent_id = wt.agent_id
|
|
123
|
+
LEFT JOIN nodes n ON n.node_id = a.node_id
|
|
124
|
+
WHERE wt.panel_id = ?
|
|
125
|
+
AND wt.deleted_at IS NULL
|
|
126
|
+
LIMIT 1`).get(panelId) ?? null;
|
|
127
|
+
}
|
|
128
|
+
const allowedChannelIds = getUserChannelAccess(this.db, userId);
|
|
129
|
+
const rows = this.loadVisibleToolRowsForViewer(userId, {
|
|
130
|
+
panelIds: [panelId],
|
|
131
|
+
allowedChannelIds,
|
|
132
|
+
});
|
|
133
|
+
return rows[0] ?? null;
|
|
134
|
+
}
|
|
135
|
+
loadVisibleToolRowsForViewer(userId, options) {
|
|
136
|
+
const allowedChannelIds = options?.allowedChannelIds ?? getUserChannelAccess(this.db, userId);
|
|
137
|
+
const conditions = ['wt.deleted_at IS NULL'];
|
|
138
|
+
const params = [];
|
|
139
|
+
if (options?.toolIds?.length) {
|
|
140
|
+
const normalizedToolIds = [...new Set(options.toolIds.map((toolId) => toolId.trim()).filter(Boolean))];
|
|
141
|
+
if (normalizedToolIds.length === 0)
|
|
142
|
+
return [];
|
|
143
|
+
conditions.push(`wt.tool_id IN (${normalizedToolIds.map(() => '?').join(', ')})`);
|
|
144
|
+
params.push(...normalizedToolIds);
|
|
145
|
+
}
|
|
146
|
+
if (options?.panelIds?.length) {
|
|
147
|
+
const normalizedPanelIds = [...new Set(options.panelIds.map((panelId) => panelId.trim()).filter(Boolean))];
|
|
148
|
+
if (normalizedPanelIds.length === 0)
|
|
149
|
+
return [];
|
|
150
|
+
conditions.push(`wt.panel_id IN (${normalizedPanelIds.map(() => '?').join(', ')})`);
|
|
151
|
+
params.push(...normalizedPanelIds);
|
|
152
|
+
}
|
|
153
|
+
const visibilityClauses = [
|
|
154
|
+
'wt.user_id = ?',
|
|
155
|
+
`(wt.scope = 'public' AND wt.public_review_status = 'approved' AND wt.pending_public_review = 0)`,
|
|
156
|
+
];
|
|
157
|
+
const visibilityParams = [userId];
|
|
158
|
+
if (allowedChannelIds.length > 0) {
|
|
159
|
+
visibilityClauses.push(`(wt.scope = 'channel' AND wt.scope_channel_id IN (${allowedChannelIds.map(() => '?').join(', ')}))`);
|
|
160
|
+
visibilityParams.push(...allowedChannelIds);
|
|
161
|
+
}
|
|
162
|
+
conditions.push(`(${visibilityClauses.join(' OR ')})`);
|
|
163
|
+
return this.db.prepare(`SELECT ${WORKSPACE_TOOL_ROW_SELECT}
|
|
164
|
+
FROM workspace_tools wt
|
|
165
|
+
LEFT JOIN agents a ON a.agent_id = wt.agent_id
|
|
166
|
+
LEFT JOIN nodes n ON n.node_id = a.node_id
|
|
167
|
+
WHERE ${conditions.join(' AND ')}
|
|
168
|
+
ORDER BY wt.updated_at DESC, wt.created_at DESC`).all(...params, ...visibilityParams);
|
|
169
|
+
}
|
|
170
|
+
loadPublicReviewToolRows(status = 'pending_review') {
|
|
171
|
+
const statusCondition = status === 'pending_review'
|
|
172
|
+
? 'wt.pending_public_review = 1'
|
|
173
|
+
: 'wt.pending_public_review = 0 AND wt.public_review_status = ?';
|
|
174
|
+
return this.db.prepare(`SELECT ${WORKSPACE_TOOL_ROW_SELECT}
|
|
175
|
+
FROM workspace_tools wt
|
|
176
|
+
LEFT JOIN agents a ON a.agent_id = wt.agent_id
|
|
177
|
+
LEFT JOIN nodes n ON n.node_id = a.node_id
|
|
178
|
+
WHERE wt.deleted_at IS NULL
|
|
179
|
+
AND ${statusCondition}
|
|
180
|
+
ORDER BY wt.updated_at DESC, wt.created_at DESC`).all(...(status === 'pending_review' ? [] : [status]));
|
|
181
|
+
}
|
|
182
|
+
canManageToolCollaborators(userId, row) {
|
|
183
|
+
return row.userId === userId || this.isAdminUser(userId);
|
|
184
|
+
}
|
|
185
|
+
canManageToolForViewer(userId, row) {
|
|
186
|
+
if (row.userId === userId || this.isAdminUser(userId))
|
|
187
|
+
return true;
|
|
188
|
+
return this.userCanManageToolViaMaintainerAgent(userId, row.toolId);
|
|
189
|
+
}
|
|
190
|
+
rowToToolInfo(row) {
|
|
191
|
+
return this.rowToToolInfoForViewer(row, row.userId);
|
|
192
|
+
}
|
|
193
|
+
rowToToolInfoForViewer(row, viewerUserId) {
|
|
194
|
+
const manifest = parseWorkspaceToolManifest(row.manifestJson);
|
|
195
|
+
const isOwner = row.userId === viewerUserId;
|
|
196
|
+
const canManage = this.canManageToolForViewer(viewerUserId, row);
|
|
197
|
+
const canViewOwnerFields = isOwner || this.isAdminUser(viewerUserId);
|
|
198
|
+
const lastRunRow = this.db.prepare(`SELECT run_id as runId,
|
|
199
|
+
wtr.tool_id as toolId,
|
|
200
|
+
action_id as actionId,
|
|
201
|
+
terminal_id as terminalId,
|
|
202
|
+
status,
|
|
203
|
+
params_json as paramsJson,
|
|
204
|
+
exit_code as exitCode,
|
|
205
|
+
signal,
|
|
206
|
+
started_at as startedAt,
|
|
207
|
+
ended_at as endedAt,
|
|
208
|
+
requested_by_user_id as requestedByUserId,
|
|
209
|
+
u.username as requestedByUsername,
|
|
210
|
+
requested_by_agent_id as requestedByAgentId,
|
|
211
|
+
a.name as requestedByAgentName,
|
|
212
|
+
execution_target_kind as executionTargetKind,
|
|
213
|
+
execution_agent_id as executionAgentId,
|
|
214
|
+
execution_node_id as executionNodeId,
|
|
215
|
+
execution_hostname as executionHostname,
|
|
216
|
+
execution_workspace_path as executionWorkspacePath
|
|
217
|
+
FROM workspace_tool_runs wtr
|
|
218
|
+
LEFT JOIN users u ON u.id = wtr.requested_by_user_id
|
|
219
|
+
LEFT JOIN agents a ON a.agent_id = wtr.requested_by_agent_id
|
|
220
|
+
WHERE wtr.tool_id = ?
|
|
221
|
+
ORDER BY started_at DESC
|
|
222
|
+
LIMIT 1`).get(row.toolId);
|
|
223
|
+
const latestState = parseStateRowJson(row.latestStateJson);
|
|
224
|
+
const verification = this.loadLatestVerificationForTool(row.toolId, row.revision);
|
|
225
|
+
const runtimeState = deriveWorkspaceToolRuntimeState({
|
|
226
|
+
activeTerminalId: row.activeTerminalId,
|
|
227
|
+
lastRunStatus: lastRunRow?.status ?? null,
|
|
228
|
+
});
|
|
229
|
+
return {
|
|
230
|
+
toolId: row.toolId,
|
|
231
|
+
userId: row.userId,
|
|
232
|
+
agentId: row.agentId,
|
|
233
|
+
agentName: row.agentName ?? null,
|
|
234
|
+
agentNodeId: row.agentNodeId ?? null,
|
|
235
|
+
agentHealth: {
|
|
236
|
+
isOnline: row.agentNodeStatus === 'online',
|
|
237
|
+
isDeleted: row.agentDeletedAt != null,
|
|
238
|
+
hasNode: Boolean(row.agentNodeId?.trim()),
|
|
239
|
+
hasWorkspace: Boolean(row.agentWorkspacePath?.trim()),
|
|
240
|
+
},
|
|
241
|
+
sourcePanelId: row.sourcePanelId ?? null,
|
|
242
|
+
panelId: row.panelId ?? null,
|
|
243
|
+
slug: row.slug,
|
|
244
|
+
name: row.name,
|
|
245
|
+
description: row.description,
|
|
246
|
+
icon: row.icon ?? null,
|
|
247
|
+
scope: row.scope,
|
|
248
|
+
scopeChannelId: row.scopeChannelId ?? null,
|
|
249
|
+
allowSharedExec: row.allowSharedExec === 1,
|
|
250
|
+
publicReviewStatus: row.publicReviewStatus,
|
|
251
|
+
pendingPublicReview: row.pendingPublicReview === 1,
|
|
252
|
+
isOwner,
|
|
253
|
+
canManage,
|
|
254
|
+
manifestPath: canViewOwnerFields ? row.manifestPath : null,
|
|
255
|
+
bundleRoot: canViewOwnerFields ? row.bundleRoot : null,
|
|
256
|
+
backendRuntime: manifest.actions.length === 0 ? 'none' : manifest.cli?.entry?.trim() ? 'cli' : 'command',
|
|
257
|
+
actionBackendRuntimes: Object.fromEntries(manifest.actions.map((action) => [
|
|
258
|
+
action.actionId,
|
|
259
|
+
resolveWorkspaceToolActionMode(action) === 'notify_agent'
|
|
260
|
+
? 'none'
|
|
261
|
+
: action.command?.trim()
|
|
262
|
+
? 'command'
|
|
263
|
+
: manifest.cli?.entry?.trim()
|
|
264
|
+
? 'cli'
|
|
265
|
+
: action.kind === 'stop'
|
|
266
|
+
? 'none'
|
|
267
|
+
: 'command',
|
|
268
|
+
])),
|
|
269
|
+
manifest: sanitizeWorkspaceToolManifestForViewer(manifest, {
|
|
270
|
+
scope: row.scope,
|
|
271
|
+
scopeChannelId: row.scopeChannelId ?? null,
|
|
272
|
+
allowSharedExec: row.allowSharedExec === 1,
|
|
273
|
+
isOwner: canViewOwnerFields,
|
|
274
|
+
}),
|
|
275
|
+
latestState,
|
|
276
|
+
businessState: deriveWorkspaceToolBusinessState(latestState),
|
|
277
|
+
runtimeState,
|
|
278
|
+
isRunning: row.activeTerminalId != null,
|
|
279
|
+
activeTerminalId: canViewOwnerFields ? (row.activeTerminalId ?? null) : null,
|
|
280
|
+
maintenanceConversationId: canViewOwnerFields ? (row.maintenanceConversationId ?? null) : null,
|
|
281
|
+
sourceConversationId: canViewOwnerFields ? (row.sourceConversationId ?? null) : null,
|
|
282
|
+
sourceMessageId: canViewOwnerFields ? (row.sourceMessageId ?? null) : null,
|
|
283
|
+
clonedFromToolId: canViewOwnerFields ? (row.clonedFromToolId ?? null) : null,
|
|
284
|
+
clonedFromRevision: canViewOwnerFields ? (row.clonedFromRevision ?? null) : null,
|
|
285
|
+
verification: verification
|
|
286
|
+
? {
|
|
287
|
+
verificationId: verification.verificationId,
|
|
288
|
+
toolId: verification.toolId,
|
|
289
|
+
toolRevision: verification.toolRevision,
|
|
290
|
+
sourceToolId: canViewOwnerFields ? verification.sourceToolId : null,
|
|
291
|
+
sourceRevision: canViewOwnerFields ? verification.sourceRevision : null,
|
|
292
|
+
targetAgentId: verification.targetAgentId,
|
|
293
|
+
targetNodeId: verification.targetNodeId,
|
|
294
|
+
targetWorkspacePath: canViewOwnerFields ? verification.targetWorkspacePath : null,
|
|
295
|
+
conversationId: canViewOwnerFields ? verification.conversationId : null,
|
|
296
|
+
status: verification.status,
|
|
297
|
+
summary: verification.summary,
|
|
298
|
+
details: canViewOwnerFields ? parseVerificationDetails(verification.detailsJson) : null,
|
|
299
|
+
smokeRunId: canViewOwnerFields ? verification.smokeRunId : null,
|
|
300
|
+
startedAt: verification.startedAt,
|
|
301
|
+
endedAt: verification.endedAt,
|
|
302
|
+
updatedAt: verification.updatedAt,
|
|
303
|
+
}
|
|
304
|
+
: null,
|
|
305
|
+
revision: row.revision,
|
|
306
|
+
createdAt: row.createdAt,
|
|
307
|
+
updatedAt: row.updatedAt,
|
|
308
|
+
deletedAt: row.deletedAt ?? null,
|
|
309
|
+
lastRun: lastRunRow
|
|
310
|
+
? workspaceToolRunRowToInfoForViewer(lastRunRow, manifest.actions.find((action) => action.actionId === lastRunRow.actionId)?.kind, {
|
|
311
|
+
viewerUserId,
|
|
312
|
+
ownerUserId: row.userId,
|
|
313
|
+
canViewOwnerFields,
|
|
314
|
+
})
|
|
315
|
+
: null,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
loadLatestVerificationForTool(toolId, toolRevision) {
|
|
319
|
+
return this.db.prepare(`SELECT verification_id as verificationId,
|
|
320
|
+
tool_id as toolId,
|
|
321
|
+
tool_revision as toolRevision,
|
|
322
|
+
source_tool_id as sourceToolId,
|
|
323
|
+
source_revision as sourceRevision,
|
|
324
|
+
target_agent_id as targetAgentId,
|
|
325
|
+
target_node_id as targetNodeId,
|
|
326
|
+
target_workspace_path as targetWorkspacePath,
|
|
327
|
+
conversation_id as conversationId,
|
|
328
|
+
status,
|
|
329
|
+
summary,
|
|
330
|
+
details_json as detailsJson,
|
|
331
|
+
smoke_run_id as smokeRunId,
|
|
332
|
+
started_at as startedAt,
|
|
333
|
+
ended_at as endedAt,
|
|
334
|
+
updated_at as updatedAt
|
|
335
|
+
FROM workspace_tool_verifications
|
|
336
|
+
WHERE tool_id = ?
|
|
337
|
+
AND tool_revision = ?
|
|
338
|
+
ORDER BY updated_at DESC, started_at DESC
|
|
339
|
+
LIMIT 1`).get(toolId, toolRevision) ?? null;
|
|
340
|
+
}
|
|
341
|
+
loadVerificationByConversation(conversationId) {
|
|
342
|
+
return this.db.prepare(`SELECT verification_id as verificationId,
|
|
343
|
+
tool_id as toolId,
|
|
344
|
+
tool_revision as toolRevision,
|
|
345
|
+
source_tool_id as sourceToolId,
|
|
346
|
+
source_revision as sourceRevision,
|
|
347
|
+
target_agent_id as targetAgentId,
|
|
348
|
+
target_node_id as targetNodeId,
|
|
349
|
+
target_workspace_path as targetWorkspacePath,
|
|
350
|
+
conversation_id as conversationId,
|
|
351
|
+
status,
|
|
352
|
+
summary,
|
|
353
|
+
details_json as detailsJson,
|
|
354
|
+
smoke_run_id as smokeRunId,
|
|
355
|
+
started_at as startedAt,
|
|
356
|
+
ended_at as endedAt,
|
|
357
|
+
updated_at as updatedAt
|
|
358
|
+
FROM workspace_tool_verifications
|
|
359
|
+
WHERE conversation_id = ?
|
|
360
|
+
ORDER BY updated_at DESC, started_at DESC
|
|
361
|
+
LIMIT 1`).get(conversationId) ?? null;
|
|
362
|
+
}
|
|
363
|
+
userCanManageToolViaMaintainerAgent(userId, toolId) {
|
|
364
|
+
const accessibleAgentIds = getUserAgentAccess(this.db, userId)
|
|
365
|
+
.map((agentId) => agentId.trim())
|
|
366
|
+
.filter(Boolean);
|
|
367
|
+
if (accessibleAgentIds.length === 0)
|
|
368
|
+
return false;
|
|
369
|
+
const row = this.db.prepare(`SELECT 1 as present
|
|
370
|
+
FROM surface_collaborators
|
|
371
|
+
WHERE surface_type = 'tool'
|
|
372
|
+
AND surface_id = ?
|
|
373
|
+
AND role = 'collaborator'
|
|
374
|
+
AND agent_id IN (${accessibleAgentIds.map(() => '?').join(', ')})
|
|
375
|
+
LIMIT 1`).get(toolId, ...accessibleAgentIds);
|
|
376
|
+
return Boolean(row);
|
|
377
|
+
}
|
|
378
|
+
}
|