@bbigbang/protocol 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/index.js ADDED
@@ -0,0 +1,398 @@
1
+ // ─── 服务端 → 客户端 事件 ───
2
+ export { validatePanelTemplateProps } from './panel.js';
3
+ export { collectDatasetAggregateNodes, collectPanelLevelActionBars, collectPanelLevelParameterInputs, collectPanelLevelUnsupportedNodes, collectPanelTemplateUnsupportedNodes, isPanelLevelActionBarNode, isPanelLevelContainerNode, isPanelLevelDatasetAggregateNode, isPanelLevelNodeEffectivelyEmpty, isPanelLevelParameterInputNode, isPanelTemplateContainerNode, mapPanelLevelNodes, matchPanelApiJsonlAllowedUrlPrefix, normalizePanelApiJsonlAuthProfileName, normalizePanelApiJsonlAuthProfileNames, normalizePanelApiJsonlAllowedUrlPrefix, normalizePanelApiJsonlAllowedUrlPrefixes, panelLevelNodeContainsEmptyLayoutContainer, panelLevelNodeHasActionBar, panelLevelNodeUsesDatasetAggregate, validatePanelApiJsonlAuthProfile, validatePanelApiJsonlUrl, validatePanelApiJsonlUrlList, walkPanelTemplateNodes, walkPanelLevelNodes, } from './panel.js';
4
+ export { AGENT_SURFACE_MODE_ENV, AGENT_SURFACE_MODES, DEFAULT_AGENT_SURFACE_MODE, normalizeAgentSurfaceMode, } from './agentSurface.js';
5
+ export const BUILTIN_UI_PANEL_SKILL_ROOT_SENTINEL = 'bigbang:builtin/ui-panel';
6
+ export const BUILTIN_LIBRARY_DOCUMENTS_SKILL_ROOT_SENTINEL = 'bigbang:builtin/library-documents';
7
+ export const BUILTIN_WORKSPACE_TOOL_SKILL_ROOT_SENTINEL = 'bigbang:builtin/workspace-tool-builder';
8
+ export const AGENT_PERMISSION_KINDS = [
9
+ 'read',
10
+ 'edit',
11
+ 'delete',
12
+ 'move',
13
+ 'search',
14
+ 'execute',
15
+ 'think',
16
+ 'fetch',
17
+ 'switch_mode',
18
+ 'other',
19
+ ];
20
+ export const AGENT_PERMISSION_DEFINITIONS = [
21
+ { kind: 'read', label: 'Read', description: 'Read workspace files.' },
22
+ { kind: 'edit', label: 'Edit', description: 'Create or modify workspace files.' },
23
+ { kind: 'delete', label: 'Delete', description: 'Delete files or folders.' },
24
+ { kind: 'move', label: 'Move', description: 'Rename or move files.' },
25
+ { kind: 'search', label: 'Search', description: 'Search local files and content.' },
26
+ { kind: 'execute', label: 'Execute', description: 'Run terminal commands.' },
27
+ { kind: 'think', label: 'Think', description: 'Use planning or task-helper tools.' },
28
+ { kind: 'fetch', label: 'Network / Web Search', description: 'Access network tools, including web search when supported.' },
29
+ { kind: 'switch_mode', label: 'Switch Mode', description: 'Change runtime interaction mode.' },
30
+ { kind: 'other', label: 'Other', description: 'Use uncategorized tools.' },
31
+ ];
32
+ export const AGENT_RUNTIME_PERMISSION_SUPPORT = {
33
+ codex_app_server: {
34
+ read: 'enforced',
35
+ edit: 'enforced',
36
+ delete: 'limited',
37
+ move: 'limited',
38
+ search: 'enforced',
39
+ execute: 'enforced',
40
+ fetch: 'enforced',
41
+ },
42
+ claude_sdk: {
43
+ read: 'enforced',
44
+ edit: 'enforced',
45
+ search: 'enforced',
46
+ execute: 'enforced',
47
+ think: 'enforced',
48
+ fetch: 'enforced',
49
+ switch_mode: 'enforced',
50
+ other: 'enforced',
51
+ },
52
+ claude_acp: {},
53
+ codex_acp: {},
54
+ };
55
+ export function getAgentPermissionSupport(agentType, kind) {
56
+ return AGENT_RUNTIME_PERMISSION_SUPPORT[agentType][kind] ?? 'unsupported';
57
+ }
58
+ export function isAgentPermissionSupported(agentType, kind) {
59
+ return getAgentPermissionSupport(agentType, kind) !== 'unsupported';
60
+ }
61
+ export function listAgentRuntimePermissions(agentType) {
62
+ return AGENT_PERMISSION_DEFINITIONS.map((definition) => ({
63
+ ...definition,
64
+ support: getAgentPermissionSupport(agentType, definition.kind),
65
+ }));
66
+ }
67
+ export function parseAgentPermissionKind(value) {
68
+ if (typeof value !== 'string')
69
+ return null;
70
+ const normalized = value.trim().toLowerCase();
71
+ return AGENT_PERMISSION_KINDS.includes(normalized)
72
+ ? normalized
73
+ : null;
74
+ }
75
+ export function normalizeAgentDisabledToolKinds(agentType, values) {
76
+ if (!Array.isArray(values))
77
+ return undefined;
78
+ const enforceRuntimeSupport = agentType === 'codex_app_server' || agentType === 'claude_sdk';
79
+ const out = [];
80
+ const seen = new Set();
81
+ for (const value of values) {
82
+ const kind = parseAgentPermissionKind(value);
83
+ if (!kind || seen.has(kind))
84
+ continue;
85
+ if (enforceRuntimeSupport && !isAgentPermissionSupported(agentType, kind))
86
+ continue;
87
+ seen.add(kind);
88
+ out.push(kind);
89
+ }
90
+ return out.length > 0 ? out : undefined;
91
+ }
92
+ export const CLAUDE_SESSION_MODEL_OPTIONS = [
93
+ {
94
+ id: 'claude-opus-4-6[1m]',
95
+ label: 'Opus 4.6 1M',
96
+ description: 'Opus 4.6 with 1M context window',
97
+ },
98
+ {
99
+ id: 'claude-opus-4-6',
100
+ label: 'Opus 4.6',
101
+ description: 'Opus 4.6 · Most capable for complex work',
102
+ isDefault: true,
103
+ },
104
+ {
105
+ id: 'claude-sonnet-4-6',
106
+ label: 'Sonnet 4.6',
107
+ description: 'Sonnet 4.6 · Best for everyday tasks',
108
+ },
109
+ {
110
+ id: 'claude-haiku-4-5',
111
+ label: 'Haiku 4.5',
112
+ description: 'Haiku 4.5 · Fastest for quick answers',
113
+ },
114
+ ];
115
+ export const AGENT_RUNTIME_CAPABILITIES = {
116
+ claude_acp: [],
117
+ claude_sdk: [],
118
+ codex_acp: [],
119
+ codex_app_server: ['activeTurnSteer', 'planApprovalLoop'],
120
+ };
121
+ export function listAgentRuntimeCapabilities(agentType) {
122
+ return [...AGENT_RUNTIME_CAPABILITIES[agentType]];
123
+ }
124
+ export function hasAgentRuntimeCapability(agentType, capability) {
125
+ return AGENT_RUNTIME_CAPABILITIES[agentType].includes(capability);
126
+ }
127
+ export const CODEX_ACP_DEFAULT_ARGS = [
128
+ '-c',
129
+ 'sandbox_mode="danger-full-access"',
130
+ '-c',
131
+ 'approval_policy="never"',
132
+ '-c',
133
+ 'features.memories=false',
134
+ '-c',
135
+ 'memories.use_memories=false',
136
+ '-c',
137
+ 'memories.generate_memories=false',
138
+ ];
139
+ export const RUNTIME_DRIVERS = {
140
+ claude_acp: {
141
+ agentType: 'claude_acp',
142
+ command: 'claude-code-acp',
143
+ args: [],
144
+ supportsResume: true,
145
+ supportsPushNotifications: true,
146
+ capabilities: [...AGENT_RUNTIME_CAPABILITIES.claude_acp],
147
+ nativeMemoryBackend: 'workspace',
148
+ defaultEnv: {
149
+ CLAUDE_CODE_DISABLE_AUTO_MEMORY: '1',
150
+ },
151
+ },
152
+ claude_sdk: {
153
+ agentType: 'claude_sdk',
154
+ command: 'claude-sdk',
155
+ args: [],
156
+ supportsResume: true,
157
+ supportsPushNotifications: false,
158
+ capabilities: ['activeTurnSteer'],
159
+ nativeMemoryBackend: 'workspace',
160
+ defaultEnv: {
161
+ CLAUDE_CODE_DISABLE_AUTO_MEMORY: '1',
162
+ },
163
+ },
164
+ codex_acp: {
165
+ agentType: 'codex_acp',
166
+ command: 'codex-acp',
167
+ args: [...CODEX_ACP_DEFAULT_ARGS],
168
+ supportsResume: true,
169
+ supportsPushNotifications: false,
170
+ capabilities: [...AGENT_RUNTIME_CAPABILITIES.codex_acp],
171
+ nativeMemoryBackend: 'workspace',
172
+ },
173
+ codex_app_server: {
174
+ agentType: 'codex_app_server',
175
+ command: 'codex',
176
+ args: ['app-server'],
177
+ supportsResume: true,
178
+ supportsPushNotifications: false,
179
+ capabilities: [...AGENT_RUNTIME_CAPABILITIES.codex_app_server],
180
+ nativeMemoryBackend: 'workspace',
181
+ },
182
+ };
183
+ export function getRuntimeDriver(agentType) {
184
+ return RUNTIME_DRIVERS[agentType];
185
+ }
186
+ export function listRuntimeDrivers() {
187
+ return Object.values(RUNTIME_DRIVERS);
188
+ }
189
+ export const BEIJING_TIME_ZONE = 'Asia/Shanghai';
190
+ const BEIJING_DATE_TIME_FORMATTER = new Intl.DateTimeFormat('en-US', {
191
+ timeZone: BEIJING_TIME_ZONE,
192
+ year: 'numeric',
193
+ month: '2-digit',
194
+ day: '2-digit',
195
+ hour: '2-digit',
196
+ minute: '2-digit',
197
+ second: '2-digit',
198
+ hour12: false,
199
+ });
200
+ const BEIJING_DATE_TIME_NO_SECONDS_FORMATTER = new Intl.DateTimeFormat('en-US', {
201
+ timeZone: BEIJING_TIME_ZONE,
202
+ year: 'numeric',
203
+ month: '2-digit',
204
+ day: '2-digit',
205
+ hour: '2-digit',
206
+ minute: '2-digit',
207
+ hour12: false,
208
+ });
209
+ const BEIJING_MONTH_DAY_TIME_FORMATTER = new Intl.DateTimeFormat('en-US', {
210
+ timeZone: BEIJING_TIME_ZONE,
211
+ month: '2-digit',
212
+ day: '2-digit',
213
+ hour: '2-digit',
214
+ minute: '2-digit',
215
+ hour12: false,
216
+ });
217
+ const BEIJING_MONTH_DAY_TIME_WITH_SECONDS_FORMATTER = new Intl.DateTimeFormat('en-US', {
218
+ timeZone: BEIJING_TIME_ZONE,
219
+ month: '2-digit',
220
+ day: '2-digit',
221
+ hour: '2-digit',
222
+ minute: '2-digit',
223
+ second: '2-digit',
224
+ hour12: false,
225
+ });
226
+ const BEIJING_TIME_FORMATTER = new Intl.DateTimeFormat('en-US', {
227
+ timeZone: BEIJING_TIME_ZONE,
228
+ hour: '2-digit',
229
+ minute: '2-digit',
230
+ hour12: false,
231
+ });
232
+ const BEIJING_TIME_WITH_SECONDS_FORMATTER = new Intl.DateTimeFormat('en-US', {
233
+ timeZone: BEIJING_TIME_ZONE,
234
+ hour: '2-digit',
235
+ minute: '2-digit',
236
+ second: '2-digit',
237
+ hour12: false,
238
+ });
239
+ function normalizeTimeInput(input) {
240
+ const date = input instanceof Date ? input : new Date(input);
241
+ return Number.isFinite(date.getTime()) ? date : null;
242
+ }
243
+ function getDateTimeParts(formatter, input) {
244
+ const date = normalizeTimeInput(input);
245
+ if (!date)
246
+ return null;
247
+ const parts = formatter.formatToParts(date);
248
+ const values = {};
249
+ for (const part of parts) {
250
+ if (part.type !== 'literal')
251
+ values[part.type] = part.value;
252
+ }
253
+ return values;
254
+ }
255
+ export function formatBeijingDateTime(input, options) {
256
+ const parts = getDateTimeParts(options?.withSeconds === false
257
+ ? BEIJING_DATE_TIME_NO_SECONDS_FORMATTER
258
+ : BEIJING_DATE_TIME_FORMATTER, input);
259
+ if (!parts)
260
+ return '';
261
+ const dateText = `${parts.year}-${parts.month}-${parts.day}`;
262
+ const timeText = options?.withSeconds === false
263
+ ? `${parts.hour}:${parts.minute}`
264
+ : `${parts.hour}:${parts.minute}:${parts.second}`;
265
+ return `${dateText} ${timeText}`;
266
+ }
267
+ export function formatBeijingPromptTimestamp(input) {
268
+ const formatted = formatBeijingDateTime(input);
269
+ return formatted ? `${formatted} UTC+8` : '';
270
+ }
271
+ export function formatBeijingMonthDayTime(input, options) {
272
+ const parts = getDateTimeParts(options?.withSeconds
273
+ ? BEIJING_MONTH_DAY_TIME_WITH_SECONDS_FORMATTER
274
+ : BEIJING_MONTH_DAY_TIME_FORMATTER, input);
275
+ if (!parts)
276
+ return '';
277
+ const timeText = options?.withSeconds
278
+ ? `${parts.hour}:${parts.minute}:${parts.second}`
279
+ : `${parts.hour}:${parts.minute}`;
280
+ return `${parts.month}/${parts.day} ${timeText}`;
281
+ }
282
+ export function formatBeijingTime(input, options) {
283
+ const date = normalizeTimeInput(input);
284
+ if (!date)
285
+ return '';
286
+ return (options?.withSeconds ? BEIJING_TIME_WITH_SECONDS_FORMATTER : BEIJING_TIME_FORMATTER).format(date);
287
+ }
288
+ export const THREAD_SHORT_ID_LENGTH = 16;
289
+ export function stripIgnoredMentionContexts(content) {
290
+ let sanitized = content;
291
+ sanitized = sanitized.replace(/```[\s\S]*?```/g, ' ');
292
+ sanitized = sanitized.replace(/~~~[\s\S]*?~~~/g, ' ');
293
+ sanitized = sanitized.replace(/`[^`\n]*`/g, ' ');
294
+ sanitized = sanitized.replace(/^\s*>.*$/gm, ' ');
295
+ const quotedSpanPatterns = [
296
+ /"[^"\n]*"/g,
297
+ /“[^”\n]*”/g,
298
+ /‘[^’\n]*’/g,
299
+ /「[^」\n]*」/g,
300
+ /『[^』\n]*』/g,
301
+ ];
302
+ for (const pattern of quotedSpanPatterns) {
303
+ sanitized = sanitized.replace(pattern, ' ');
304
+ }
305
+ return sanitized;
306
+ }
307
+ export function extractMentionedNames(content) {
308
+ const sanitizedContent = stripIgnoredMentionContexts(content);
309
+ const mentionRegex = /@([a-zA-Z0-9_-]+)/g;
310
+ const mentioned = new Set();
311
+ let match;
312
+ while ((match = mentionRegex.exec(sanitizedContent)) !== null) {
313
+ mentioned.add(match[1].toLowerCase());
314
+ }
315
+ return [...mentioned];
316
+ }
317
+ export function normalizeThreadShortIdInput(threadRootId) {
318
+ const normalized = threadRootId?.trim().toLowerCase();
319
+ return normalized ? normalized : null;
320
+ }
321
+ export function normalizeMessageIdForThreadShortId(messageId) {
322
+ const trimmed = messageId.trim().toLowerCase();
323
+ const withoutClientPrefix = trimmed.startsWith('client-') ? trimmed.slice('client-'.length) : trimmed;
324
+ const alnumOnly = withoutClientPrefix.replace(/[^a-z0-9]/g, '');
325
+ return alnumOnly || trimmed.replace(/[^a-z0-9]/g, '') || trimmed;
326
+ }
327
+ export function buildThreadShortId(messageId) {
328
+ const normalized = normalizeMessageIdForThreadShortId(messageId);
329
+ return normalized.slice(0, THREAD_SHORT_ID_LENGTH);
330
+ }
331
+ export function buildRecentMessageSourceKey(params) {
332
+ if (params.sourceType === 'dm') {
333
+ return `dm:${encodeURIComponent((params.agentId ?? '').trim())}`;
334
+ }
335
+ if (params.sourceType === 'channel') {
336
+ return `channel:${encodeURIComponent((params.channelId ?? '').trim())}`;
337
+ }
338
+ return `${params.sourceType}:${encodeURIComponent((params.channelId ?? '').trim())}:${encodeURIComponent((params.threadRootId ?? '').trim())}`;
339
+ }
340
+ export function parseRecentMessageSourceKey(sourceKey) {
341
+ const separatorIndex = sourceKey.indexOf(':');
342
+ if (separatorIndex <= 0)
343
+ return null;
344
+ const sourceType = sourceKey.slice(0, separatorIndex);
345
+ const rest = sourceKey.slice(separatorIndex + 1);
346
+ try {
347
+ if (sourceType === 'dm') {
348
+ const agentId = decodeURIComponent(rest).trim();
349
+ return agentId ? { sourceType: 'dm', agentId } : null;
350
+ }
351
+ if (sourceType === 'channel') {
352
+ const channelId = decodeURIComponent(rest).trim();
353
+ return channelId ? { sourceType: 'channel', channelId } : null;
354
+ }
355
+ if (sourceType === 'thread' || sourceType === 'task') {
356
+ const secondSeparatorIndex = rest.indexOf(':');
357
+ if (secondSeparatorIndex <= 0)
358
+ return null;
359
+ const channelId = decodeURIComponent(rest.slice(0, secondSeparatorIndex)).trim();
360
+ const threadRootId = decodeURIComponent(rest.slice(secondSeparatorIndex + 1)).trim();
361
+ return channelId && threadRootId
362
+ ? { sourceType, channelId, threadRootId }
363
+ : null;
364
+ }
365
+ }
366
+ catch {
367
+ return null;
368
+ }
369
+ return null;
370
+ }
371
+ export const WORKSPACE_TOOL_PANEL_ACTION_PARAM_NAMESPACE = 'tool_action';
372
+ export function buildWorkspaceToolPanelActionParamKey(actionId, paramName) {
373
+ return `${WORKSPACE_TOOL_PANEL_ACTION_PARAM_NAMESPACE}.${actionId}.${paramName}`;
374
+ }
375
+ export function parseWorkspaceToolPanelActionParamKey(key) {
376
+ if (typeof key !== 'string' || !key.startsWith(`${WORKSPACE_TOOL_PANEL_ACTION_PARAM_NAMESPACE}.`)) {
377
+ return null;
378
+ }
379
+ const remainder = key.slice(WORKSPACE_TOOL_PANEL_ACTION_PARAM_NAMESPACE.length + 1);
380
+ const separatorIndex = remainder.lastIndexOf('.');
381
+ if (separatorIndex <= 0 || separatorIndex === remainder.length - 1) {
382
+ return null;
383
+ }
384
+ return {
385
+ actionId: remainder.slice(0, separatorIndex),
386
+ paramName: remainder.slice(separatorIndex + 1),
387
+ };
388
+ }
389
+ export function extractWorkspaceToolPanelActionParams(actionId, formValues) {
390
+ if (!formValues)
391
+ return {};
392
+ const prefix = `${WORKSPACE_TOOL_PANEL_ACTION_PARAM_NAMESPACE}.${actionId}.`;
393
+ return Object.fromEntries(Object.entries(formValues)
394
+ .filter(([key]) => key.startsWith(prefix))
395
+ .map(([key, value]) => [key.slice(prefix.length), value]));
396
+ }
397
+ export * from './handoff.js';
398
+ export * from './panel.js';