@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
package/dist/config.js ADDED
@@ -0,0 +1,380 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { createInterface } from 'node:readline/promises';
6
+ import Database from 'better-sqlite3';
7
+ import { z } from 'zod';
8
+ import { AGENT_SURFACE_MODE_ENV, normalizeAgentSurfaceMode } from '@bbigbang/protocol';
9
+ const DEFAULT_CODEX_ACP_NPX_ARGS = [
10
+ '-y',
11
+ '@zed-industries/codex-acp@latest',
12
+ '-c',
13
+ 'sandbox_mode="danger-full-access"',
14
+ '-c',
15
+ 'approval_policy="never"',
16
+ ];
17
+ function resolveHomeDir() {
18
+ return os.homedir();
19
+ }
20
+ export function resolveGatewayHomeDir() {
21
+ const env = process.env.BIGBANG_HOME;
22
+ if (env?.trim())
23
+ return expandPath(env.trim(), resolveHomeDir());
24
+ const homeDir = resolveHomeDir();
25
+ const bigbangHome = path.join(homeDir, '.bigbang');
26
+ const legacyHome = path.join(homeDir, '.agent-collab');
27
+ const bigbangConfigPath = configFilePath(bigbangHome);
28
+ const legacyConfigPath = configFilePath(legacyHome);
29
+ if (fs.existsSync(legacyConfigPath)
30
+ && (!fs.existsSync(bigbangConfigPath) || isUninitializedGeneratedDefaultConfig(bigbangConfigPath, bigbangHome, homeDir))) {
31
+ return legacyHome;
32
+ }
33
+ return bigbangHome;
34
+ }
35
+ function isUninitializedGeneratedDefaultConfig(filePath, gatewayHome, homeDir) {
36
+ try {
37
+ const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
38
+ const looksGenerated = parsed.serverSlug === 'default'
39
+ && parsed.serverName === 'Default'
40
+ && parsed.publicServerUrl === ''
41
+ && parsed.publicBasePath === ''
42
+ && parsed.hubRegistryPath === '';
43
+ if (!looksGenerated)
44
+ return false;
45
+ const dbPath = typeof parsed.dbPath === 'string' && parsed.dbPath.trim()
46
+ ? resolvePathRelativeTo(parsed.dbPath, gatewayHome, homeDir)
47
+ : path.join(gatewayHome, 'data', 'gateway.db');
48
+ return !sqliteDatabaseHasUsers(dbPath);
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
54
+ function sqliteDatabaseHasUsers(dbPath) {
55
+ if (!fs.existsSync(dbPath))
56
+ return false;
57
+ let db = null;
58
+ try {
59
+ db = new Database(dbPath, { readonly: true, fileMustExist: true });
60
+ const usersTable = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='users'").get();
61
+ if (!usersTable)
62
+ return false;
63
+ const row = db.prepare('SELECT COUNT(*) as count FROM users').get();
64
+ return row.count > 0;
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ finally {
70
+ db?.close();
71
+ }
72
+ }
73
+ export function configFilePath(gatewayHome) {
74
+ return path.join(gatewayHome, 'config.json');
75
+ }
76
+ function expandPath(raw, homeDir) {
77
+ if (raw === '~')
78
+ return homeDir;
79
+ if (raw.startsWith('~/'))
80
+ return path.join(homeDir, raw.slice(2));
81
+ return raw;
82
+ }
83
+ function resolvePathRelativeTo(raw, baseDir, homeDir) {
84
+ const expanded = expandPath(raw, homeDir);
85
+ if (path.isAbsolute(expanded))
86
+ return expanded;
87
+ return path.join(baseDir, expanded);
88
+ }
89
+ function createConfigSchema(defaults) {
90
+ const absPath = z
91
+ .string()
92
+ .min(1)
93
+ .refine((p) => path.isAbsolute(p), {
94
+ message: 'must be an absolute path',
95
+ });
96
+ const serverSlug = z
97
+ .string()
98
+ .trim()
99
+ .min(1)
100
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,62}$/, {
101
+ message: 'must be a single URL-safe path segment',
102
+ });
103
+ const publicBasePath = z
104
+ .string()
105
+ .trim()
106
+ .refine((value) => value === '' || /^\/[A-Za-z0-9][A-Za-z0-9_/-]*[A-Za-z0-9_-]$/.test(value), {
107
+ message: 'must be empty or a leading-slash path prefix without a trailing slash',
108
+ })
109
+ .refine((value) => !value.includes('//'), {
110
+ message: 'must not contain empty path segments',
111
+ });
112
+ return z.object({
113
+ webPort: z.number().int().min(1).max(65535).default(3100),
114
+ webHost: z.string().min(1).default('0.0.0.0'),
115
+ publicServerUrl: z.string().default(''),
116
+ agentBridgeServerUrl: z.string().default(''),
117
+ hubRegistryPath: z.string().default(''),
118
+ hubServerJoinPackageSpec: z.string().default(''),
119
+ hubServerJoinNpxPackageSpecs: z.array(z.string()).default([]),
120
+ hubServerJoinInstallPackages: z.array(z.string()).default([]),
121
+ serverId: z.string().min(1),
122
+ serverSlug: serverSlug.default('default'),
123
+ serverName: z.string().min(1).default('Default'),
124
+ publicBasePath: publicBasePath.default(''),
125
+ internalAgentAuthToken: z.string().min(1).default('internal-agent-auth-token'),
126
+ nodeDispatchAckTimeoutMs: z.number().int().min(100).max(60_000).default(5_000),
127
+ acpAgentCommand: z.string().min(1).default('npx'),
128
+ acpAgentArgs: z
129
+ .array(z.string())
130
+ .default([...DEFAULT_CODEX_ACP_NPX_ARGS]),
131
+ acpPromptTimeoutMs: z.number().int().min(1_000).max(3_600_000).default(3_600_000),
132
+ // Default workspace is ~ (switchable per conversation via /workspace)
133
+ workspaceRoot: absPath.default(defaults.defaultWorkspaceRoot),
134
+ panelAbsolutePathRoots: z.array(absPath).default([]),
135
+ // Default DB path lives under ~/.bigbang
136
+ dbPath: z.string().min(1).default(defaults.defaultDbPath),
137
+ runtimeIdleTtlSeconds: z.number().int().min(10).default(15 * 60),
138
+ maxBindingRuntimes: z.number().int().min(1).max(200).default(30),
139
+ workspaceToolMaxActivePersistentRunsPerAgent: z.number().int().min(1).max(100).default(3),
140
+ uiDefaultMode: z.enum(['verbose', 'summary']).default('summary'),
141
+ uiJsonMaxChars: z.number().int().min(200).max(200_000).default(12_000),
142
+ contextReplayEnabled: z.boolean().default(true),
143
+ contextReplayRuns: z.number().int().min(0).max(100).default(16),
144
+ contextReplayMaxChars: z.number().int().min(200).max(512_000).default(128_000),
145
+ humanUserName: z.string().min(1).default('yanzong'),
146
+ agentSurfaceMode: z.enum(['bigbang', 'mcp']).default('bigbang'),
147
+ }).superRefine((value, ctx) => {
148
+ if (value.publicBasePath.trim() && !value.agentBridgeServerUrl.trim()) {
149
+ ctx.addIssue({
150
+ code: 'custom',
151
+ path: ['agentBridgeServerUrl'],
152
+ message: 'is required when publicBasePath is configured',
153
+ });
154
+ }
155
+ });
156
+ }
157
+ export async function loadConfig(options = {}) {
158
+ const homeDir = resolveHomeDir();
159
+ const gatewayHome = resolveGatewayHomeDir();
160
+ fs.mkdirSync(gatewayHome, { recursive: true });
161
+ const defaults = {
162
+ defaultWorkspaceRoot: homeDir,
163
+ defaultDbPath: path.join(gatewayHome, 'data', 'gateway.db'),
164
+ };
165
+ const schema = createConfigSchema(defaults);
166
+ const file = configFilePath(gatewayHome);
167
+ let raw;
168
+ if (fs.existsSync(file)) {
169
+ raw = JSON.parse(fs.readFileSync(file, 'utf8'));
170
+ }
171
+ else {
172
+ const input = options.input ?? process.stdin;
173
+ const output = options.output ?? process.stdout;
174
+ const shouldRunWizard = options.interactiveBootstrap === true &&
175
+ isInteractiveTerminal(input, output);
176
+ raw = shouldRunWizard
177
+ ? await runFirstTimeSetup({
178
+ defaults,
179
+ file,
180
+ input,
181
+ output,
182
+ })
183
+ : createDefaultConfig(defaults);
184
+ fs.writeFileSync(file, JSON.stringify(raw, null, 2) + '\n', 'utf8');
185
+ }
186
+ // Normalize paths.
187
+ if (typeof raw?.workspaceRoot === 'string') {
188
+ raw.workspaceRoot = resolvePathRelativeTo(raw.workspaceRoot, gatewayHome, homeDir);
189
+ }
190
+ if (Array.isArray(raw?.panelAbsolutePathRoots)) {
191
+ raw.panelAbsolutePathRoots = raw.panelAbsolutePathRoots
192
+ .filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
193
+ .map((entry) => resolvePathRelativeTo(entry, gatewayHome, homeDir));
194
+ }
195
+ if (typeof raw?.dbPath === 'string') {
196
+ raw.dbPath = resolvePathRelativeTo(raw.dbPath, gatewayHome, homeDir);
197
+ }
198
+ if (typeof raw?.publicServerUrl !== 'string') {
199
+ raw.publicServerUrl = '';
200
+ }
201
+ if (typeof raw?.agentBridgeServerUrl !== 'string') {
202
+ raw.agentBridgeServerUrl = '';
203
+ }
204
+ if (typeof raw?.hubRegistryPath === 'string' && raw.hubRegistryPath.trim()) {
205
+ raw.hubRegistryPath = resolvePathRelativeTo(raw.hubRegistryPath, gatewayHome, homeDir);
206
+ }
207
+ else {
208
+ raw.hubRegistryPath = '';
209
+ }
210
+ if (typeof raw?.hubServerJoinPackageSpec !== 'string') {
211
+ raw.hubServerJoinPackageSpec = '';
212
+ }
213
+ if (!Array.isArray(raw?.hubServerJoinNpxPackageSpecs)) {
214
+ raw.hubServerJoinNpxPackageSpecs = [];
215
+ }
216
+ if (!Array.isArray(raw?.hubServerJoinInstallPackages)) {
217
+ raw.hubServerJoinInstallPackages = [];
218
+ }
219
+ const identityChanged = ensureServerIdentity(raw);
220
+ if (typeof raw?.internalAgentAuthToken !== 'string' || !raw.internalAgentAuthToken.trim()) {
221
+ raw.internalAgentAuthToken = randomUUID();
222
+ fs.writeFileSync(file, JSON.stringify(raw, null, 2) + '\n', 'utf8');
223
+ }
224
+ else if (identityChanged) {
225
+ fs.writeFileSync(file, JSON.stringify(raw, null, 2) + '\n', 'utf8');
226
+ }
227
+ if (typeof raw?.nodeDispatchAckTimeoutMs !== 'number') {
228
+ raw.nodeDispatchAckTimeoutMs = 5_000;
229
+ }
230
+ raw.agentSurfaceMode = normalizeAgentSurfaceMode(process.env[AGENT_SURFACE_MODE_ENV] ?? (typeof raw?.agentSurfaceMode === 'string' ? raw.agentSurfaceMode : undefined));
231
+ return schema.parse(raw);
232
+ }
233
+ function createDefaultConfig(defaults) {
234
+ return {
235
+ workspaceRoot: defaults.defaultWorkspaceRoot,
236
+ panelAbsolutePathRoots: [],
237
+ dbPath: defaults.defaultDbPath,
238
+ acpAgentCommand: 'npx',
239
+ acpAgentArgs: [...DEFAULT_CODEX_ACP_NPX_ARGS],
240
+ acpPromptTimeoutMs: 3_600_000,
241
+ uiDefaultMode: 'summary',
242
+ webPort: 3100,
243
+ webHost: '0.0.0.0',
244
+ publicServerUrl: '',
245
+ agentBridgeServerUrl: '',
246
+ hubRegistryPath: '',
247
+ hubServerJoinPackageSpec: '',
248
+ hubServerJoinNpxPackageSpecs: [],
249
+ hubServerJoinInstallPackages: [],
250
+ serverId: randomUUID(),
251
+ serverSlug: 'default',
252
+ serverName: 'Default',
253
+ publicBasePath: '',
254
+ internalAgentAuthToken: randomUUID(),
255
+ nodeDispatchAckTimeoutMs: 5_000,
256
+ workspaceToolMaxActivePersistentRunsPerAgent: 3,
257
+ };
258
+ }
259
+ function ensureServerIdentity(raw) {
260
+ let changed = false;
261
+ if (typeof raw.serverId !== 'string' || !raw.serverId.trim()) {
262
+ raw.serverId = randomUUID();
263
+ changed = true;
264
+ }
265
+ else if (raw.serverId !== raw.serverId.trim()) {
266
+ raw.serverId = raw.serverId.trim();
267
+ changed = true;
268
+ }
269
+ if (typeof raw.serverSlug !== 'string' || !raw.serverSlug.trim()) {
270
+ raw.serverSlug = 'default';
271
+ changed = true;
272
+ }
273
+ else if (raw.serverSlug !== raw.serverSlug.trim()) {
274
+ raw.serverSlug = raw.serverSlug.trim();
275
+ changed = true;
276
+ }
277
+ if (typeof raw.serverName !== 'string' || !raw.serverName.trim()) {
278
+ raw.serverName = 'Default';
279
+ changed = true;
280
+ }
281
+ else if (raw.serverName !== raw.serverName.trim()) {
282
+ raw.serverName = raw.serverName.trim();
283
+ changed = true;
284
+ }
285
+ if (typeof raw.publicBasePath !== 'string') {
286
+ raw.publicBasePath = '';
287
+ changed = true;
288
+ }
289
+ else {
290
+ let normalized = raw.publicBasePath.trim();
291
+ if (normalized && !normalized.startsWith('/')) {
292
+ normalized = `/${normalized}`;
293
+ }
294
+ normalized = normalized.replace(/\/+$/u, '');
295
+ if (raw.publicBasePath !== normalized) {
296
+ raw.publicBasePath = normalized;
297
+ changed = true;
298
+ }
299
+ }
300
+ return changed;
301
+ }
302
+ function isInteractiveTerminal(input, output) {
303
+ return Boolean(input.isTTY && output.isTTY);
304
+ }
305
+ async function runFirstTimeSetup(params) {
306
+ params.output.write('\n');
307
+ params.output.write('bigbang first-time setup\n');
308
+ params.output.write(`Config file: ${params.file}\n`);
309
+ params.output.write('Press Enter to accept defaults.\n\n');
310
+ const rl = createInterface({
311
+ input: params.input,
312
+ output: params.output,
313
+ });
314
+ try {
315
+ const acpAgentCommand = await askWithDefault(rl, 'ACP agent command', 'npx');
316
+ const acpArgsRaw = await askWithDefault(rl, 'ACP agent args (space-separated)', '-y @zed-industries/codex-acp@latest -c sandbox_mode="danger-full-access" -c approval_policy="never"');
317
+ const workspaceRoot = await askWithDefault(rl, 'Default workspace root', params.defaults.defaultWorkspaceRoot);
318
+ const dbPath = await askWithDefault(rl, 'SQLite DB path', params.defaults.defaultDbPath);
319
+ const webPort = await askPortWithDefault(rl, 'Web server port', 3100);
320
+ const publicServerUrl = await askOptional(rl, 'Public browser URL origin (optional, e.g. https://acac.cpolar.top)');
321
+ const agentBridgeServerUrl = await askOptional(rl, 'Agent bridge server URL for node callbacks (optional, e.g. http://10.0.0.5:3100)');
322
+ const raw = {
323
+ workspaceRoot,
324
+ dbPath,
325
+ acpAgentCommand,
326
+ acpAgentArgs: splitArgs(acpArgsRaw),
327
+ acpPromptTimeoutMs: 3_600_000,
328
+ uiDefaultMode: 'summary',
329
+ webPort,
330
+ webHost: '0.0.0.0',
331
+ publicServerUrl,
332
+ agentBridgeServerUrl,
333
+ internalAgentAuthToken: randomUUID(),
334
+ nodeDispatchAckTimeoutMs: 5_000,
335
+ };
336
+ params.output.write('\nSaved config. You can edit it later at:\n');
337
+ params.output.write(`${params.file}\n\n`);
338
+ return raw;
339
+ }
340
+ finally {
341
+ rl.close();
342
+ }
343
+ }
344
+ async function askWithDefault(rl, label, defaultValue) {
345
+ const answer = (await rl.question(`${label} [${defaultValue}]: `)).trim();
346
+ return answer || defaultValue;
347
+ }
348
+ async function askOptional(rl, label) {
349
+ return (await rl.question(`${label}: `)).trim();
350
+ }
351
+ async function askYesNo(rl, label, defaultValue) {
352
+ const hint = defaultValue ? 'Y/n' : 'y/N';
353
+ const answer = (await rl.question(`${label} [${hint}]: `)).trim().toLowerCase();
354
+ if (!answer)
355
+ return defaultValue;
356
+ if (answer === 'y' || answer === 'yes')
357
+ return true;
358
+ if (answer === 'n' || answer === 'no')
359
+ return false;
360
+ return defaultValue;
361
+ }
362
+ async function askPortWithDefault(rl, label, defaultValue) {
363
+ const answer = (await rl.question(`${label} [${defaultValue}]: `)).trim();
364
+ if (!answer)
365
+ return defaultValue;
366
+ const num = Number.parseInt(answer, 10);
367
+ if (!Number.isInteger(num) || num < 1 || num > 65535) {
368
+ return defaultValue;
369
+ }
370
+ return num;
371
+ }
372
+ function splitArgs(raw) {
373
+ const parts = raw
374
+ .split(/\s+/)
375
+ .map((v) => v.trim())
376
+ .filter(Boolean);
377
+ if (parts.length > 0)
378
+ return parts;
379
+ return [...DEFAULT_CODEX_ACP_NPX_ARGS];
380
+ }