@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,245 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { getRuntimeDriver } from '@bbigbang/protocol';
|
|
3
|
+
import { createSession } from '@bbigbang/runtime-acp';
|
|
4
|
+
export class WorkspaceSessionServiceError extends Error {
|
|
5
|
+
statusCode;
|
|
6
|
+
constructor(statusCode, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class WorkspaceSessionService {
|
|
12
|
+
db;
|
|
13
|
+
workbenchRootService;
|
|
14
|
+
getAgentById;
|
|
15
|
+
constructor(params) {
|
|
16
|
+
this.db = params.db;
|
|
17
|
+
this.workbenchRootService = params.workbenchRootService;
|
|
18
|
+
this.getAgentById = params.getAgentById;
|
|
19
|
+
}
|
|
20
|
+
ensureSession(params) {
|
|
21
|
+
const agentId = normalizeRequiredText(params.agentId, 'agentId is required.');
|
|
22
|
+
const workspaceRootId = normalizeRequiredText(params.workspaceRootId, 'workspaceRootId is required.');
|
|
23
|
+
const agent = this.getAgentById(agentId);
|
|
24
|
+
if (!agent)
|
|
25
|
+
throw new WorkspaceSessionServiceError(404, 'Agent not found.');
|
|
26
|
+
if (!params.canAccessAgent(agentId)) {
|
|
27
|
+
throw new WorkspaceSessionServiceError(403, 'Access denied.');
|
|
28
|
+
}
|
|
29
|
+
const root = this.resolveExecutableRoot(workspaceRootId, agentId);
|
|
30
|
+
const title = normalizeOptionalText(params.title);
|
|
31
|
+
const existing = this.selectLatestOpenSession(params.user.id, agentId, workspaceRootId);
|
|
32
|
+
if (existing) {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
this.db.prepare(`UPDATE workspace_sessions
|
|
35
|
+
SET title = CASE WHEN ? IS NULL THEN title ELSE ? END,
|
|
36
|
+
last_active_at = ?,
|
|
37
|
+
updated_at = ?
|
|
38
|
+
WHERE workspace_session_id = ?`).run(title, title, now, now, existing.workspaceSessionId);
|
|
39
|
+
return {
|
|
40
|
+
session: this.getSessionForUser(existing.workspaceSessionId, params.user, params.canAccessAgent),
|
|
41
|
+
created: false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const now = Date.now();
|
|
45
|
+
const sessionKey = randomUUID();
|
|
46
|
+
const runtime = getRuntimeDriver(agent.agentType);
|
|
47
|
+
createSession(this.db, {
|
|
48
|
+
sessionKey,
|
|
49
|
+
agentCommand: runtime.command,
|
|
50
|
+
agentArgs: runtime.args,
|
|
51
|
+
cwd: root.rootPath,
|
|
52
|
+
loadSupported: false,
|
|
53
|
+
});
|
|
54
|
+
const workspaceSessionId = randomUUID();
|
|
55
|
+
this.db.prepare(`INSERT INTO workspace_sessions(
|
|
56
|
+
workspace_session_id, agent_id, project_id, workspace_root_id, title, status,
|
|
57
|
+
runtime_profile, session_key, created_by_user_id, created_at, updated_at,
|
|
58
|
+
last_active_at, archived_at
|
|
59
|
+
)
|
|
60
|
+
VALUES(?, ?, ?, ?, ?, 'idle', 'workspace_native', ?, ?, ?, ?, ?, NULL)`).run(workspaceSessionId, agentId, root.kind === 'project_space' ? root.projectId ?? null : null, workspaceRootId, title ?? '', sessionKey, params.user.id, now, now, now);
|
|
61
|
+
return {
|
|
62
|
+
session: this.getSessionForUser(workspaceSessionId, params.user, params.canAccessAgent),
|
|
63
|
+
created: true,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
listSessions(params) {
|
|
67
|
+
const agentId = normalizeOptionalText(params.agentId);
|
|
68
|
+
const workspaceRootId = normalizeOptionalText(params.workspaceRootId);
|
|
69
|
+
if (agentId && !params.canAccessAgent(agentId)) {
|
|
70
|
+
throw new WorkspaceSessionServiceError(403, 'Access denied.');
|
|
71
|
+
}
|
|
72
|
+
const conditions = [];
|
|
73
|
+
const values = [];
|
|
74
|
+
if (!params.user.isAdmin) {
|
|
75
|
+
conditions.push('created_by_user_id = ?');
|
|
76
|
+
values.push(params.user.id);
|
|
77
|
+
}
|
|
78
|
+
if (agentId) {
|
|
79
|
+
conditions.push('agent_id = ?');
|
|
80
|
+
values.push(agentId);
|
|
81
|
+
}
|
|
82
|
+
if (workspaceRootId) {
|
|
83
|
+
conditions.push('workspace_root_id = ?');
|
|
84
|
+
values.push(workspaceRootId);
|
|
85
|
+
}
|
|
86
|
+
if (!params.includeArchived) {
|
|
87
|
+
conditions.push('archived_at IS NULL');
|
|
88
|
+
}
|
|
89
|
+
const rows = this.db.prepare(`${WORKSPACE_SESSION_SELECT}
|
|
90
|
+
${conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''}
|
|
91
|
+
ORDER BY last_active_at DESC, updated_at DESC`).all(...values);
|
|
92
|
+
return {
|
|
93
|
+
sessions: rows
|
|
94
|
+
.filter((row) => this.canReadSessionRow(row, params.user, params.canAccessAgent))
|
|
95
|
+
.map(mapWorkspaceSessionRow),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
getSessionForUser(workspaceSessionId, user, canAccessAgent) {
|
|
99
|
+
const row = this.selectSession(workspaceSessionId);
|
|
100
|
+
if (!row)
|
|
101
|
+
throw new WorkspaceSessionServiceError(404, 'Workspace session not found.');
|
|
102
|
+
this.assertSessionAccess(row, user, canAccessAgent);
|
|
103
|
+
return mapWorkspaceSessionRow(row);
|
|
104
|
+
}
|
|
105
|
+
getRuntimeContext(params) {
|
|
106
|
+
const row = this.selectSession(params.workspaceSessionId);
|
|
107
|
+
if (!row)
|
|
108
|
+
throw new WorkspaceSessionServiceError(404, 'Workspace session not found.');
|
|
109
|
+
const root = this.assertSessionAccess(row, params.user, params.canAccessAgent);
|
|
110
|
+
const agent = this.getAgentById(row.agentId);
|
|
111
|
+
if (!agent)
|
|
112
|
+
throw new WorkspaceSessionServiceError(404, 'Agent not found.');
|
|
113
|
+
return {
|
|
114
|
+
session: mapWorkspaceSessionRow(row),
|
|
115
|
+
sessionKey: row.sessionKey,
|
|
116
|
+
agent,
|
|
117
|
+
root,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
archiveSession(params) {
|
|
121
|
+
const row = this.selectSession(params.workspaceSessionId);
|
|
122
|
+
if (!row)
|
|
123
|
+
throw new WorkspaceSessionServiceError(404, 'Workspace session not found.');
|
|
124
|
+
this.assertSessionAccess(row, params.user, params.canAccessAgent);
|
|
125
|
+
if (row.status !== 'idle' && row.status !== 'failed') {
|
|
126
|
+
throw new WorkspaceSessionServiceError(409, 'Only idle or failed workspace sessions can be archived.');
|
|
127
|
+
}
|
|
128
|
+
if (row.archivedAt != null)
|
|
129
|
+
return mapWorkspaceSessionRow(row);
|
|
130
|
+
const now = Date.now();
|
|
131
|
+
this.db.prepare(`UPDATE workspace_sessions
|
|
132
|
+
SET archived_at = ?,
|
|
133
|
+
updated_at = ?
|
|
134
|
+
WHERE workspace_session_id = ?`).run(now, now, row.workspaceSessionId);
|
|
135
|
+
return mapWorkspaceSessionRow(this.selectSession(row.workspaceSessionId));
|
|
136
|
+
}
|
|
137
|
+
updateSessionStatus(workspaceSessionId, status, options) {
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
this.db.prepare(`UPDATE workspace_sessions
|
|
140
|
+
SET status = ?,
|
|
141
|
+
updated_at = ?,
|
|
142
|
+
last_active_at = CASE WHEN ? THEN ? ELSE last_active_at END
|
|
143
|
+
WHERE workspace_session_id = ?`).run(status, now, options?.touchLastActive ? 1 : 0, now, workspaceSessionId);
|
|
144
|
+
const row = this.selectSession(workspaceSessionId);
|
|
145
|
+
return row ? mapWorkspaceSessionRow(row) : null;
|
|
146
|
+
}
|
|
147
|
+
selectLatestOpenSession(userId, agentId, workspaceRootId) {
|
|
148
|
+
return this.db.prepare(`${WORKSPACE_SESSION_SELECT}
|
|
149
|
+
WHERE created_by_user_id = ?
|
|
150
|
+
AND agent_id = ?
|
|
151
|
+
AND workspace_root_id = ?
|
|
152
|
+
AND archived_at IS NULL
|
|
153
|
+
ORDER BY last_active_at DESC, updated_at DESC
|
|
154
|
+
LIMIT 1`).get(userId, agentId, workspaceRootId) ?? null;
|
|
155
|
+
}
|
|
156
|
+
selectSession(workspaceSessionId) {
|
|
157
|
+
return this.db.prepare(`${WORKSPACE_SESSION_SELECT}
|
|
158
|
+
WHERE workspace_session_id = ?`).get(workspaceSessionId) ?? null;
|
|
159
|
+
}
|
|
160
|
+
assertSessionAccess(row, user, canAccessAgent) {
|
|
161
|
+
if (!user.isAdmin && row.createdByUserId !== user.id) {
|
|
162
|
+
throw new WorkspaceSessionServiceError(403, 'Access denied.');
|
|
163
|
+
}
|
|
164
|
+
if (!canAccessAgent(row.agentId)) {
|
|
165
|
+
throw new WorkspaceSessionServiceError(403, 'Access denied.');
|
|
166
|
+
}
|
|
167
|
+
return this.resolveExecutableRoot(row.workspaceRootId, row.agentId);
|
|
168
|
+
}
|
|
169
|
+
canReadSessionRow(row, user, canAccessAgent) {
|
|
170
|
+
if (!user.isAdmin && row.createdByUserId !== user.id)
|
|
171
|
+
return false;
|
|
172
|
+
if (!canAccessAgent(row.agentId))
|
|
173
|
+
return false;
|
|
174
|
+
try {
|
|
175
|
+
this.resolveExecutableRoot(row.workspaceRootId, row.agentId);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
resolveExecutableRoot(workspaceRootId, agentId) {
|
|
183
|
+
const root = this.workbenchRootService.getRoot(workspaceRootId);
|
|
184
|
+
if (!root)
|
|
185
|
+
throw new WorkspaceSessionServiceError(404, 'Workspace root not found.');
|
|
186
|
+
if (root.kind === 'resource_space') {
|
|
187
|
+
throw new WorkspaceSessionServiceError(409, 'Resource spaces cannot host workspace-native agent sessions.');
|
|
188
|
+
}
|
|
189
|
+
if (root.kind === 'agent_workspace' && root.agentId !== agentId) {
|
|
190
|
+
throw new WorkspaceSessionServiceError(409, 'Agent workspace root does not match the requested agent.');
|
|
191
|
+
}
|
|
192
|
+
if (root.kind === 'project_space') {
|
|
193
|
+
if (!root.projectId) {
|
|
194
|
+
throw new WorkspaceSessionServiceError(409, 'Project root is missing its project identity.');
|
|
195
|
+
}
|
|
196
|
+
if (!(root.agentIds ?? []).includes(agentId)) {
|
|
197
|
+
throw new WorkspaceSessionServiceError(409, 'Agent is not bound to this project workspace.');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return root;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const WORKSPACE_SESSION_SELECT = `
|
|
204
|
+
SELECT workspace_session_id as workspaceSessionId,
|
|
205
|
+
agent_id as agentId,
|
|
206
|
+
project_id as projectId,
|
|
207
|
+
workspace_root_id as workspaceRootId,
|
|
208
|
+
title,
|
|
209
|
+
status,
|
|
210
|
+
runtime_profile as runtimeProfile,
|
|
211
|
+
session_key as sessionKey,
|
|
212
|
+
created_by_user_id as createdByUserId,
|
|
213
|
+
created_at as createdAt,
|
|
214
|
+
updated_at as updatedAt,
|
|
215
|
+
last_active_at as lastActiveAt,
|
|
216
|
+
archived_at as archivedAt
|
|
217
|
+
FROM workspace_sessions`;
|
|
218
|
+
function mapWorkspaceSessionRow(row) {
|
|
219
|
+
return {
|
|
220
|
+
workspaceSessionId: row.workspaceSessionId,
|
|
221
|
+
agentId: row.agentId,
|
|
222
|
+
projectId: row.projectId,
|
|
223
|
+
workspaceRootId: row.workspaceRootId,
|
|
224
|
+
title: row.title,
|
|
225
|
+
status: row.status,
|
|
226
|
+
runtimeProfile: row.runtimeProfile,
|
|
227
|
+
createdByUserId: row.createdByUserId,
|
|
228
|
+
createdAt: row.createdAt,
|
|
229
|
+
updatedAt: row.updatedAt,
|
|
230
|
+
lastActiveAt: row.lastActiveAt,
|
|
231
|
+
archivedAt: row.archivedAt,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function normalizeOptionalText(value) {
|
|
235
|
+
if (typeof value !== 'string')
|
|
236
|
+
return null;
|
|
237
|
+
const trimmed = value.trim();
|
|
238
|
+
return trimmed || null;
|
|
239
|
+
}
|
|
240
|
+
function normalizeRequiredText(value, message) {
|
|
241
|
+
const normalized = normalizeOptionalText(value);
|
|
242
|
+
if (!normalized)
|
|
243
|
+
throw new WorkspaceSessionServiceError(400, message);
|
|
244
|
+
return normalized;
|
|
245
|
+
}
|