@sideboard-ai/core 0.1.77 → 0.1.81
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/{agents-LKUHPPEQ.js → agents-EBKJ55PN.js} +5 -5
- package/dist/{agents-XJV6J3K2.js → agents-UQ7D6U6L.js} +6 -6
- package/dist/{app-settings-3TLA2EJ7.js → app-settings-6IOQYGBK.js} +7 -1
- package/dist/{app-settings-P42Z3VOB.js → app-settings-NILNWNNQ.js} +7 -1
- package/dist/{chunk-2FJI5JXX.js → chunk-4AVU4QXO.js} +54 -20
- package/dist/{chunk-XJNCWYFR.js → chunk-4HJK57XU.js} +8 -14
- package/dist/{chunk-VERLUKN2.js → chunk-6F2TQFJE.js} +6 -6
- package/dist/{chunk-EEKSZTMU.js → chunk-CQBQWX73.js} +10 -16
- package/dist/{chunk-OE7YBB5X.js → chunk-FUUVPN4A.js} +108 -3
- package/dist/{chunk-W7YOTDVO.js → chunk-IFPN6TER.js} +47 -2
- package/dist/{chunk-75U65MBE.js → chunk-K553XK7M.js} +2 -2
- package/dist/{chunk-GWTLKXXP.js → chunk-P5VDPGAN.js} +3 -3
- package/dist/{chunk-2ZIPJRJE.js → chunk-TDJ43HUD.js} +2 -2
- package/dist/{chunk-PTJJIQK7.js → chunk-XKNBSYA7.js} +47 -2
- package/dist/{chunk-QD37IILI.js → chunk-XNECBC6T.js} +66 -20
- package/dist/{chunk-MF2YMEGD.js → chunk-YVVXWWCC.js} +110 -3
- package/dist/{coordinator-prompt-LLFJUO2R.js → coordinator-prompt-JQF72JKX.js} +4 -4
- package/dist/{coordinator-prompt-MRCMMRSF.js → coordinator-prompt-NYNEFKIV.js} +3 -3
- package/dist/{global-workspace-YNMNO4CL.js → global-workspace-DZM4ZFGU.js} +5 -5
- package/dist/{global-workspace-TWHMYLTZ.js → global-workspace-NUMUJRWG.js} +4 -4
- package/dist/index.cjs +585 -251
- package/dist/index.d.cts +97 -8
- package/dist/index.d.ts +97 -8
- package/dist/index.js +363 -222
- package/dist/mcp/run-stdio.cjs +2502 -2286
- package/dist/mcp/run-stdio.js +162 -133
- package/dist/{workspaces-O3U5BENH.js → workspaces-QLRCOXAY.js} +6 -6
- package/dist/{workspaces-GQ4XKBD3.js → workspaces-SUU2GO3A.js} +5 -5
- package/dist/{worktree-VOCH3WS3.js → worktree-5VLLFI5W.js} +5 -1
- package/dist/{worktree-KWXHMKRN.js → worktree-UNSOCYZU.js} +5 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listWorkspaces,
|
|
5
5
|
removeWorkspace,
|
|
6
6
|
syncWorkspacesFromThreads
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-K553XK7M.js";
|
|
8
8
|
import {
|
|
9
9
|
BRIGHTSY_MCP_ALLOWED_TOOLS,
|
|
10
10
|
CLAUDE_MODEL_CATALOG,
|
|
@@ -13,12 +13,14 @@ import {
|
|
|
13
13
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
14
14
|
SIDEBOARD_MCP_PROFILE_ENV,
|
|
15
15
|
allAdapters,
|
|
16
|
+
applyTurnUsage,
|
|
16
17
|
brightsyAdapter,
|
|
17
18
|
brightsyMcpAllowedTools,
|
|
18
19
|
buildCachedUserContent,
|
|
19
20
|
buildClaudeStreamJsonUserMessage,
|
|
20
21
|
claudeAdapter,
|
|
21
22
|
codexAdapter,
|
|
23
|
+
contextTokens,
|
|
22
24
|
countCacheControlBlocks,
|
|
23
25
|
cursorAdapter,
|
|
24
26
|
decodeBrightsyTarget,
|
|
@@ -26,6 +28,7 @@ import {
|
|
|
26
28
|
encodeBrightsyTarget,
|
|
27
29
|
findInvalidCacheControlTtlOrder,
|
|
28
30
|
flattenTurnInput,
|
|
31
|
+
fromInclusiveInputUsage,
|
|
29
32
|
getAdapter,
|
|
30
33
|
getAgentSetupInfo,
|
|
31
34
|
installAgent,
|
|
@@ -41,6 +44,7 @@ import {
|
|
|
41
44
|
loginAgent,
|
|
42
45
|
mcpAllowTools,
|
|
43
46
|
mcpAuthWarnings,
|
|
47
|
+
mergeUsage,
|
|
44
48
|
normalizeTurnInput,
|
|
45
49
|
openInSystemTerminal,
|
|
46
50
|
opencodeAdapter,
|
|
@@ -50,6 +54,7 @@ import {
|
|
|
50
54
|
permissionMode,
|
|
51
55
|
prepareTerminalCommand,
|
|
52
56
|
promptMentionsBrightsy,
|
|
57
|
+
requestOccupancy,
|
|
53
58
|
resolveCursorModelId,
|
|
54
59
|
resolveLoginCommand,
|
|
55
60
|
resolveQuotaFallbackAgent,
|
|
@@ -57,8 +62,9 @@ import {
|
|
|
57
62
|
shouldInjectBrightsyMcp,
|
|
58
63
|
sideboardMcpProfile,
|
|
59
64
|
threadRequestsBrightsyMcp,
|
|
65
|
+
totalTokens,
|
|
60
66
|
writeInjectedMcpConfig
|
|
61
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-XNECBC6T.js";
|
|
62
68
|
import {
|
|
63
69
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
64
70
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -85,7 +91,7 @@ import {
|
|
|
85
91
|
parseForceStopMessage,
|
|
86
92
|
slackCoordinatorSourceRef,
|
|
87
93
|
takenTeamSlugsForOrchestration
|
|
88
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-6F2TQFJE.js";
|
|
89
95
|
import {
|
|
90
96
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
91
97
|
SLACK_REPLY_FORMATTING,
|
|
@@ -94,7 +100,7 @@ import {
|
|
|
94
100
|
enrichWorkspacesWithGithub,
|
|
95
101
|
ensureGlobalCoordinatorCwd,
|
|
96
102
|
formatWorkspaceInventory
|
|
97
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-CQBQWX73.js";
|
|
98
104
|
import {
|
|
99
105
|
brightsyConfigPath,
|
|
100
106
|
brightsyMcpServerName,
|
|
@@ -129,66 +135,6 @@ import {
|
|
|
129
135
|
pushTurnStderr,
|
|
130
136
|
summarizeTurnStderr
|
|
131
137
|
} from "./chunk-SEOICVGB.js";
|
|
132
|
-
import {
|
|
133
|
-
HARNESS_ENV_KEYS,
|
|
134
|
-
appSettingsPath,
|
|
135
|
-
applyAppEnvironment,
|
|
136
|
-
autoArchiveOnMergeEnabled,
|
|
137
|
-
autoCleanupOrphansEnabled,
|
|
138
|
-
autoRenameBranchEnabled,
|
|
139
|
-
autoRunAfterSetupEnabled,
|
|
140
|
-
brightsyCloudConnectAgent,
|
|
141
|
-
brightsyCloudConnectEnabled,
|
|
142
|
-
brightsyInjectWorktreeMcpEnabled,
|
|
143
|
-
caffeinateWhileCloudConnectEnabled,
|
|
144
|
-
caffeinateWhileRunningEnabled,
|
|
145
|
-
caffeinateWhileSlackListenEnabled,
|
|
146
|
-
childEnvWithAppSettings,
|
|
147
|
-
claudeChromeEnabled,
|
|
148
|
-
claudeUserSettingsPath,
|
|
149
|
-
deleteBranchOnPurgeEnabled,
|
|
150
|
-
disconnectLinearConnection,
|
|
151
|
-
ensureSlackDeviceIdentity,
|
|
152
|
-
getDefaultAgent,
|
|
153
|
-
getDefaultEffort,
|
|
154
|
-
getDefaultFast,
|
|
155
|
-
getDefaultModel,
|
|
156
|
-
getIssueSource,
|
|
157
|
-
getLinearApiKey,
|
|
158
|
-
harnessEnvKey,
|
|
159
|
-
isLinearConnected,
|
|
160
|
-
isSecureFileEncrypted,
|
|
161
|
-
loadAppSettings,
|
|
162
|
-
maxConcurrentAgents,
|
|
163
|
-
orchestrationQuotaFallbackAgent,
|
|
164
|
-
orchestrationQuotaOnLimit,
|
|
165
|
-
persistVaultKeyInKeychain,
|
|
166
|
-
readKeychainVaultKey,
|
|
167
|
-
readSecureJson,
|
|
168
|
-
resolveAgentExecutable,
|
|
169
|
-
resolveClaudeExecutable,
|
|
170
|
-
resolveEffectiveIssueSource,
|
|
171
|
-
resolveNewThreadOptions,
|
|
172
|
-
resolveThreadDefaults,
|
|
173
|
-
resolveVaultKey,
|
|
174
|
-
saveAppSettings,
|
|
175
|
-
saveLinearOAuth,
|
|
176
|
-
secureFileUnlocksWith,
|
|
177
|
-
setVaultMasterKey,
|
|
178
|
-
slackAppLevelToken,
|
|
179
|
-
slackListenEnabled,
|
|
180
|
-
toPublicAppSettings,
|
|
181
|
-
updateAdvancedSettings,
|
|
182
|
-
updateAgentExecutable,
|
|
183
|
-
updateAppEnvironment,
|
|
184
|
-
updateBrightsySettings,
|
|
185
|
-
updateClaudeSettings,
|
|
186
|
-
updateCodexSettings,
|
|
187
|
-
updateDefaultsSettings,
|
|
188
|
-
updateIntegrationsSettings,
|
|
189
|
-
updateOpencodeSettings,
|
|
190
|
-
writeSecureJson
|
|
191
|
-
} from "./chunk-W7YOTDVO.js";
|
|
192
138
|
import {
|
|
193
139
|
caffeinateHoldPath,
|
|
194
140
|
getCaffeinateHold,
|
|
@@ -196,14 +142,13 @@ import {
|
|
|
196
142
|
releaseCaffeinateHoldForThread,
|
|
197
143
|
setCaffeinateHold
|
|
198
144
|
} from "./chunk-MFF2RE3I.js";
|
|
199
|
-
import {
|
|
200
|
-
writePrivateFile
|
|
201
|
-
} from "./chunk-JT7R45JB.js";
|
|
202
145
|
import {
|
|
203
146
|
FAMOUS_SOCCER_TEAMS,
|
|
204
147
|
addPrStackLayer,
|
|
205
148
|
allocateTeamName,
|
|
206
149
|
allocateTeamSlug,
|
|
150
|
+
appendIndexedGitConfig,
|
|
151
|
+
applyGithubGitAuthEnv,
|
|
207
152
|
branchDisplayLabel,
|
|
208
153
|
checkoutPrStackLayer,
|
|
209
154
|
collectTakenTeamSlugs,
|
|
@@ -218,6 +163,7 @@ import {
|
|
|
218
163
|
extractGhErrorDetail,
|
|
219
164
|
fetchPrHead,
|
|
220
165
|
formatGhLandError,
|
|
166
|
+
formatGitAuthModeDirective,
|
|
221
167
|
formatIpcInvokeError,
|
|
222
168
|
formatRateLimitResetHint,
|
|
223
169
|
getPr,
|
|
@@ -227,6 +173,7 @@ import {
|
|
|
227
173
|
getPrStack,
|
|
228
174
|
ghHeadRef,
|
|
229
175
|
ghRepoSelectArgs,
|
|
176
|
+
githubAgentGitEnv,
|
|
230
177
|
initPrStack,
|
|
231
178
|
isDirty,
|
|
232
179
|
isGhRateLimitError,
|
|
@@ -261,13 +208,79 @@ import {
|
|
|
261
208
|
worktreeDisplayLabel,
|
|
262
209
|
worktreeDisplayLabelForGroup,
|
|
263
210
|
worktreeNameFromPath
|
|
264
|
-
} from "./chunk-
|
|
211
|
+
} from "./chunk-YVVXWWCC.js";
|
|
265
212
|
import {
|
|
266
213
|
ATTACHMENTS_DIR,
|
|
267
214
|
LEGACY_ATTACHMENTS_DIR,
|
|
268
215
|
attachmentsGitignoreBody,
|
|
269
216
|
isWorkspaceScratchPath
|
|
270
217
|
} from "./chunk-FKOIHGKV.js";
|
|
218
|
+
import {
|
|
219
|
+
GITHUB_GIT_AUTH_MODES,
|
|
220
|
+
HARNESS_ENV_KEYS,
|
|
221
|
+
appSettingsPath,
|
|
222
|
+
applyAppEnvironment,
|
|
223
|
+
autoArchiveOnMergeEnabled,
|
|
224
|
+
autoCleanupOrphansEnabled,
|
|
225
|
+
autoRenameBranchEnabled,
|
|
226
|
+
autoRunAfterSetupEnabled,
|
|
227
|
+
brightsyCloudConnectAgent,
|
|
228
|
+
brightsyCloudConnectEnabled,
|
|
229
|
+
brightsyInjectWorktreeMcpEnabled,
|
|
230
|
+
caffeinateWhileCloudConnectEnabled,
|
|
231
|
+
caffeinateWhileRunningEnabled,
|
|
232
|
+
caffeinateWhileSlackListenEnabled,
|
|
233
|
+
childEnvWithAppSettings,
|
|
234
|
+
claudeChromeEnabled,
|
|
235
|
+
claudeUserSettingsPath,
|
|
236
|
+
deleteBranchOnPurgeEnabled,
|
|
237
|
+
disconnectLinearConnection,
|
|
238
|
+
ensureSlackDeviceIdentity,
|
|
239
|
+
getDefaultAgent,
|
|
240
|
+
getDefaultEffort,
|
|
241
|
+
getDefaultFast,
|
|
242
|
+
getDefaultModel,
|
|
243
|
+
getGithubGitAuthMode,
|
|
244
|
+
getGithubPat,
|
|
245
|
+
getIssueSource,
|
|
246
|
+
getLinearApiKey,
|
|
247
|
+
harnessEnvKey,
|
|
248
|
+
isLinearConnected,
|
|
249
|
+
isSecureFileEncrypted,
|
|
250
|
+
loadAppSettings,
|
|
251
|
+
maxConcurrentAgents,
|
|
252
|
+
orchestrationQuotaFallbackAgent,
|
|
253
|
+
orchestrationQuotaOnLimit,
|
|
254
|
+
persistVaultKeyInKeychain,
|
|
255
|
+
readKeychainVaultKey,
|
|
256
|
+
readSecureJson,
|
|
257
|
+
resolveAgentExecutable,
|
|
258
|
+
resolveClaudeExecutable,
|
|
259
|
+
resolveEffectiveIssueSource,
|
|
260
|
+
resolveNewThreadOptions,
|
|
261
|
+
resolveThreadDefaults,
|
|
262
|
+
resolveVaultKey,
|
|
263
|
+
saveAppSettings,
|
|
264
|
+
saveLinearOAuth,
|
|
265
|
+
secureFileUnlocksWith,
|
|
266
|
+
setVaultMasterKey,
|
|
267
|
+
slackAppLevelToken,
|
|
268
|
+
slackListenEnabled,
|
|
269
|
+
toPublicAppSettings,
|
|
270
|
+
updateAdvancedSettings,
|
|
271
|
+
updateAgentExecutable,
|
|
272
|
+
updateAppEnvironment,
|
|
273
|
+
updateBrightsySettings,
|
|
274
|
+
updateClaudeSettings,
|
|
275
|
+
updateCodexSettings,
|
|
276
|
+
updateDefaultsSettings,
|
|
277
|
+
updateIntegrationsSettings,
|
|
278
|
+
updateOpencodeSettings,
|
|
279
|
+
writeSecureJson
|
|
280
|
+
} from "./chunk-IFPN6TER.js";
|
|
281
|
+
import {
|
|
282
|
+
writePrivateFile
|
|
283
|
+
} from "./chunk-JT7R45JB.js";
|
|
271
284
|
import {
|
|
272
285
|
appendMessage,
|
|
273
286
|
createEmptyThread,
|
|
@@ -1075,8 +1088,8 @@ function toolDetail(name, input) {
|
|
|
1075
1088
|
if (!input) return void 0;
|
|
1076
1089
|
const command = str(input.command) ?? str(input.cmd);
|
|
1077
1090
|
if (command) return command;
|
|
1078
|
-
const
|
|
1079
|
-
if (
|
|
1091
|
+
const path2 = str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? str(input.filename);
|
|
1092
|
+
if (path2) return path2;
|
|
1080
1093
|
const pattern = str(input.pattern) ?? str(input.glob) ?? str(input.glob_pattern);
|
|
1081
1094
|
if (pattern) return pattern;
|
|
1082
1095
|
const query = str(input.query) ?? str(input.prompt);
|
|
@@ -1120,12 +1133,12 @@ function toolDescription(name, input) {
|
|
|
1120
1133
|
return "Run shell command";
|
|
1121
1134
|
}
|
|
1122
1135
|
if (/edit|write|apply/i.test(name)) {
|
|
1123
|
-
const
|
|
1124
|
-
return
|
|
1136
|
+
const path2 = str(input.file_path) ?? str(input.path);
|
|
1137
|
+
return path2 ? `Edit ${path2.split("/").pop()}` : "Edit file";
|
|
1125
1138
|
}
|
|
1126
1139
|
if (/read/i.test(name)) {
|
|
1127
|
-
const
|
|
1128
|
-
return
|
|
1140
|
+
const path2 = str(input.file_path) ?? str(input.path);
|
|
1141
|
+
return path2 ? `Read ${path2.split("/").pop()}` : "Read file";
|
|
1129
1142
|
}
|
|
1130
1143
|
if (/grep/i.test(name)) return "Search files";
|
|
1131
1144
|
if (/glob/i.test(name)) return "Find files";
|
|
@@ -1289,41 +1302,6 @@ function normalizeParseResult(parsed) {
|
|
|
1289
1302
|
return Array.isArray(parsed) ? parsed : [parsed];
|
|
1290
1303
|
}
|
|
1291
1304
|
|
|
1292
|
-
// src/agents/usage.ts
|
|
1293
|
-
function sumOptional(a, b) {
|
|
1294
|
-
if (a == null && b == null) return void 0;
|
|
1295
|
-
return (a ?? 0) + (b ?? 0);
|
|
1296
|
-
}
|
|
1297
|
-
function requestOccupancy(u) {
|
|
1298
|
-
return u.inputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWriteTokens ?? 0);
|
|
1299
|
-
}
|
|
1300
|
-
function mergeUsage(a, b) {
|
|
1301
|
-
return {
|
|
1302
|
-
inputTokens: (a?.inputTokens ?? 0) + b.inputTokens,
|
|
1303
|
-
outputTokens: (a?.outputTokens ?? 0) + b.outputTokens,
|
|
1304
|
-
cacheReadTokens: sumOptional(a?.cacheReadTokens, b.cacheReadTokens),
|
|
1305
|
-
cacheWriteTokens: sumOptional(a?.cacheWriteTokens, b.cacheWriteTokens),
|
|
1306
|
-
lastRequestTokens: b.lastRequestTokens ?? a?.lastRequestTokens
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
function applyTurnUsage(current, incoming, scope = "request") {
|
|
1310
|
-
if (scope === "turn") {
|
|
1311
|
-
return {
|
|
1312
|
-
...incoming,
|
|
1313
|
-
lastRequestTokens: current?.lastRequestTokens ?? requestOccupancy(incoming)
|
|
1314
|
-
};
|
|
1315
|
-
}
|
|
1316
|
-
const merged = mergeUsage(current, incoming);
|
|
1317
|
-
return { ...merged, lastRequestTokens: requestOccupancy(incoming) };
|
|
1318
|
-
}
|
|
1319
|
-
function totalTokens(u) {
|
|
1320
|
-
return u.inputTokens + u.outputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWriteTokens ?? 0);
|
|
1321
|
-
}
|
|
1322
|
-
function contextTokens(u) {
|
|
1323
|
-
if (u.lastRequestTokens != null && u.lastRequestTokens > 0) return u.lastRequestTokens;
|
|
1324
|
-
return requestOccupancy(u);
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
1305
|
// src/agents/spawn.ts
|
|
1328
1306
|
async function spawnAgentTurn(thread, input, onEvent) {
|
|
1329
1307
|
ensureAgentPath();
|
|
@@ -1332,9 +1310,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1332
1310
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
1333
1311
|
);
|
|
1334
1312
|
}
|
|
1335
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
1313
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-DZM4ZFGU.js");
|
|
1336
1314
|
if (isGlobalThread2(thread)) {
|
|
1337
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
1315
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-JQF72JKX.js");
|
|
1338
1316
|
ensureGlobalCoordinatorCwd2(
|
|
1339
1317
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
1340
1318
|
);
|
|
@@ -1351,8 +1329,13 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
1351
1329
|
}
|
|
1352
1330
|
const env = childEnvWithAppSettings(cmd.env);
|
|
1353
1331
|
if (!isOrchestratorThread(thread)) {
|
|
1354
|
-
|
|
1355
|
-
|
|
1332
|
+
try {
|
|
1333
|
+
const originEnv = await originGhRepoEnv(thread.worktreePath, { env });
|
|
1334
|
+
Object.assign(env, originEnv);
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1337
|
+
console.warn(`[sideboard] originGhRepoEnv failed (${thread.worktreePath}): ${detail}`);
|
|
1338
|
+
}
|
|
1356
1339
|
}
|
|
1357
1340
|
const child = execa(cmd.file, cmd.args, {
|
|
1358
1341
|
cwd: cmd.cwd,
|
|
@@ -1487,6 +1470,8 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
1487
1470
|
lines.push(
|
|
1488
1471
|
"- Push with `git push -u origin HEAD` (or the current branch name). Do not `git push upstream`."
|
|
1489
1472
|
);
|
|
1473
|
+
lines.push("");
|
|
1474
|
+
lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
|
|
1490
1475
|
lines.push(
|
|
1491
1476
|
"- Derive the PR title and body from what the changes actually do and why \u2014 inspect the diff/commits and the user request. Do not use the soccer-team worktree nickname or placeholder branch as the PR title."
|
|
1492
1477
|
);
|
|
@@ -1494,7 +1479,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
1494
1479
|
"- Prefer a concise imperative title (Conventional Commits style when it fits: feat:/fix:/chore:/docs:). Body should summarize intent, key changes, and test notes."
|
|
1495
1480
|
);
|
|
1496
1481
|
lines.push(
|
|
1497
|
-
"- Commit with messages that state the purpose of the change (same standard as the PR). Stay on this thread branch. Never push directly to main/master or merge locally into the main checkout.
|
|
1482
|
+
"- Commit with messages that state the purpose of the change (same standard as the PR). Stay on this thread branch. Never push directly to main/master or merge locally into the main checkout. Do not merge the PR unless this turn is a Merge PR request or the user explicitly asked. When merging, use GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
|
|
1498
1483
|
);
|
|
1499
1484
|
if (thread.prUrl) {
|
|
1500
1485
|
lines.push(
|
|
@@ -1532,7 +1517,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
1532
1517
|
'- "Address review comments." \u2192 read PR review feedback, make the requested changes, commit, and push.'
|
|
1533
1518
|
);
|
|
1534
1519
|
lines.push(
|
|
1535
|
-
'- "Merge PR." \u2192 merge this thread\'s open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.'
|
|
1520
|
+
'- "Merge PR." \u2192 merge this thread\'s open pull request on GitHub (this phrase is the explicit ask). If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.'
|
|
1536
1521
|
);
|
|
1537
1522
|
return lines.join("\n");
|
|
1538
1523
|
}
|
|
@@ -1575,10 +1560,11 @@ var FILES_BY_AGENT = {
|
|
|
1575
1560
|
var MAX_CHARS_PER_FILE = 48e3;
|
|
1576
1561
|
function loadAgentInstructions(worktreePath, agent) {
|
|
1577
1562
|
const candidates = FILES_BY_AGENT[agent] ?? FILES_BY_AGENT.claude;
|
|
1578
|
-
const
|
|
1563
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
1564
|
+
const seenBodies = /* @__PURE__ */ new Set();
|
|
1579
1565
|
const out = [];
|
|
1580
1566
|
for (const rel of candidates) {
|
|
1581
|
-
if (
|
|
1567
|
+
if (seenPaths.has(rel)) continue;
|
|
1582
1568
|
const abs = join(worktreePath, rel);
|
|
1583
1569
|
if (!existsSync(abs)) continue;
|
|
1584
1570
|
try {
|
|
@@ -1590,7 +1576,10 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
1590
1576
|
|
|
1591
1577
|
\u2026(truncated)`;
|
|
1592
1578
|
}
|
|
1593
|
-
|
|
1579
|
+
const body = content.trim().replace(/\r\n/g, "\n");
|
|
1580
|
+
if (seenBodies.has(body)) continue;
|
|
1581
|
+
seenPaths.add(rel);
|
|
1582
|
+
seenBodies.add(body);
|
|
1594
1583
|
out.push({ relativePath: rel, content });
|
|
1595
1584
|
} catch {
|
|
1596
1585
|
}
|
|
@@ -1672,9 +1661,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
1672
1661
|
return new RegExp(`^${escaped}$`).test(name);
|
|
1673
1662
|
}
|
|
1674
1663
|
function readWorktreeInclude(repoPath) {
|
|
1675
|
-
const
|
|
1676
|
-
if (!existsSync2(
|
|
1677
|
-
return readFileSync2(
|
|
1664
|
+
const path2 = join2(repoPath, ".worktreeinclude");
|
|
1665
|
+
if (!existsSync2(path2)) return [];
|
|
1666
|
+
return readFileSync2(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
1678
1667
|
}
|
|
1679
1668
|
function resolveFilesToCopy(repoPath) {
|
|
1680
1669
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -1749,8 +1738,20 @@ async function captureLoginEnv() {
|
|
|
1749
1738
|
cachedLoginEnv = { ...process.env };
|
|
1750
1739
|
return { ...cachedLoginEnv };
|
|
1751
1740
|
}
|
|
1741
|
+
var NESTED_ELECTRON_ENV_PREFIXES = ["ELECTRON_", "CHROME_"];
|
|
1742
|
+
function stripNestedElectronEnv(env) {
|
|
1743
|
+
const out = { ...env };
|
|
1744
|
+
for (const key of Object.keys(out)) {
|
|
1745
|
+
if (NESTED_ELECTRON_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
1746
|
+
delete out[key];
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
return out;
|
|
1750
|
+
}
|
|
1752
1751
|
function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
1753
|
-
const env = {
|
|
1752
|
+
const env = stripNestedElectronEnv({
|
|
1753
|
+
...baseEnv ?? process.env
|
|
1754
|
+
});
|
|
1754
1755
|
const name = opts.workspaceName ?? basename(opts.worktreePath);
|
|
1755
1756
|
const ports = opts.ports ?? [];
|
|
1756
1757
|
const primary = ports[0];
|
|
@@ -1975,10 +1976,10 @@ import { join as join3 } from "path";
|
|
|
1975
1976
|
import { execa as execa3 } from "execa";
|
|
1976
1977
|
import { createInterface as createInterface3 } from "readline";
|
|
1977
1978
|
function loadCursorWorktreesJson(rootPath) {
|
|
1978
|
-
const
|
|
1979
|
-
if (!existsSync3(
|
|
1979
|
+
const path2 = join3(rootPath, ".cursor", "worktrees.json");
|
|
1980
|
+
if (!existsSync3(path2)) return null;
|
|
1980
1981
|
try {
|
|
1981
|
-
return JSON.parse(readFileSync3(
|
|
1982
|
+
return JSON.parse(readFileSync3(path2, "utf8"));
|
|
1982
1983
|
} catch {
|
|
1983
1984
|
return null;
|
|
1984
1985
|
}
|
|
@@ -2079,9 +2080,9 @@ function parseNameStatus(stdout) {
|
|
|
2079
2080
|
const out = [];
|
|
2080
2081
|
for (const line of stdout.split("\n").filter(Boolean)) {
|
|
2081
2082
|
const [status, ...pathParts] = line.split(" ");
|
|
2082
|
-
const
|
|
2083
|
-
if (!status || !
|
|
2084
|
-
out.push({ status: status[0] ?? status, path });
|
|
2083
|
+
const path2 = pathParts[pathParts.length - 1];
|
|
2084
|
+
if (!status || !path2) continue;
|
|
2085
|
+
out.push({ status: status[0] ?? status, path: path2 });
|
|
2085
2086
|
}
|
|
2086
2087
|
return out;
|
|
2087
2088
|
}
|
|
@@ -2089,12 +2090,12 @@ function parseNumstat(stdout) {
|
|
|
2089
2090
|
const map = /* @__PURE__ */ new Map();
|
|
2090
2091
|
for (const line of stdout.split("\n").filter(Boolean)) {
|
|
2091
2092
|
const [addRaw, delRaw, ...pathParts] = line.split(" ");
|
|
2092
|
-
const
|
|
2093
|
-
if (!
|
|
2093
|
+
const path2 = pathParts[pathParts.length - 1];
|
|
2094
|
+
if (!path2) continue;
|
|
2094
2095
|
const additions = addRaw === "-" ? 0 : Number(addRaw);
|
|
2095
2096
|
const deletions = delRaw === "-" ? 0 : Number(delRaw);
|
|
2096
2097
|
if (!Number.isFinite(additions) && !Number.isFinite(deletions)) continue;
|
|
2097
|
-
map.set(
|
|
2098
|
+
map.set(path2, {
|
|
2098
2099
|
additions: Number.isFinite(additions) ? additions : 0,
|
|
2099
2100
|
deletions: Number.isFinite(deletions) ? deletions : 0
|
|
2100
2101
|
});
|
|
@@ -2171,70 +2172,70 @@ function splitCombinedDiff(stdout) {
|
|
|
2171
2172
|
}
|
|
2172
2173
|
return map;
|
|
2173
2174
|
}
|
|
2174
|
-
function syntheticAddPatch(
|
|
2175
|
+
function syntheticAddPatch(path2, content, maxHunk) {
|
|
2175
2176
|
const lines = content.split("\n");
|
|
2176
2177
|
const body = lines.map((l) => `+${l}`).join("\n");
|
|
2177
|
-
const header = `diff --git a/${
|
|
2178
|
+
const header = `diff --git a/${path2} b/${path2}
|
|
2178
2179
|
new file mode 100644
|
|
2179
2180
|
--- /dev/null
|
|
2180
|
-
+++ b/${
|
|
2181
|
+
+++ b/${path2}
|
|
2181
2182
|
@@ -0,0 +1,${lines.length} @@
|
|
2182
2183
|
`;
|
|
2183
2184
|
return {
|
|
2184
|
-
path,
|
|
2185
|
+
path: path2,
|
|
2185
2186
|
status: "A",
|
|
2186
2187
|
patch: capPatch(`${header}${body}`, maxHunk),
|
|
2187
2188
|
additions: lines.length,
|
|
2188
2189
|
deletions: 0
|
|
2189
2190
|
};
|
|
2190
2191
|
}
|
|
2191
|
-
async function untrackedPatch(worktreePath,
|
|
2192
|
-
const abs = join4(worktreePath,
|
|
2192
|
+
async function untrackedPatch(worktreePath, path2, maxHunk) {
|
|
2193
|
+
const abs = join4(worktreePath, path2);
|
|
2193
2194
|
try {
|
|
2194
2195
|
const st = statSync2(abs);
|
|
2195
2196
|
if (st.isFile() && st.size > maxHunk) {
|
|
2196
2197
|
const buf = readFileSync4(abs).subarray(0, maxHunk);
|
|
2197
|
-
return syntheticAddPatch(
|
|
2198
|
+
return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
|
|
2198
2199
|
}
|
|
2199
2200
|
} catch {
|
|
2200
2201
|
}
|
|
2201
2202
|
const { stdout: patch } = await git(
|
|
2202
|
-
["diff", "--no-ext-diff", "--no-color", "--no-index", "--", "/dev/null",
|
|
2203
|
+
["diff", "--no-ext-diff", "--no-color", "--no-index", "--", "/dev/null", path2],
|
|
2203
2204
|
worktreePath,
|
|
2204
2205
|
{ reject: false, timeoutMs: 4e3 }
|
|
2205
2206
|
);
|
|
2206
|
-
const normalized = patch.replace(/^diff --git a\/.+? b\/.+?$/m, `diff --git a/${
|
|
2207
|
+
const normalized = patch.replace(/^diff --git a\/.+? b\/.+?$/m, `diff --git a/${path2} b/${path2}`).replace(/^--- .*$/m, "--- /dev/null").replace(/^\+\+\+ .*$/m, `+++ b/${path2}`);
|
|
2207
2208
|
const addLines = normalized.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
|
|
2208
2209
|
return {
|
|
2209
|
-
path,
|
|
2210
|
+
path: path2,
|
|
2210
2211
|
status: "A",
|
|
2211
2212
|
patch: capPatch(normalized, maxHunk),
|
|
2212
2213
|
additions: addLines,
|
|
2213
2214
|
deletions: 0
|
|
2214
2215
|
};
|
|
2215
2216
|
}
|
|
2216
|
-
async function listUntrackedPaths(worktreePath,
|
|
2217
|
+
async function listUntrackedPaths(worktreePath, path2) {
|
|
2217
2218
|
const args = ["ls-files", "-z", "--others", "--exclude-standard"];
|
|
2218
|
-
if (
|
|
2219
|
+
if (path2) args.push("--", path2);
|
|
2219
2220
|
const { stdout } = await git(args, worktreePath, { reject: false });
|
|
2220
2221
|
return stdout.split("\0").filter(Boolean).filter((p) => !isSideboardScratchPath(p));
|
|
2221
2222
|
}
|
|
2222
2223
|
async function listUntrackedFiles(worktreePath, maxHunk, paths) {
|
|
2223
2224
|
const list = paths ?? await listUntrackedPaths(worktreePath);
|
|
2224
2225
|
if (list.length === 0) return [];
|
|
2225
|
-
return Promise.all(list.map((
|
|
2226
|
+
return Promise.all(list.map((path2) => untrackedPatch(worktreePath, path2, maxHunk)));
|
|
2226
2227
|
}
|
|
2227
2228
|
function untrackedStubs(paths) {
|
|
2228
|
-
return paths.map((
|
|
2229
|
-
path,
|
|
2229
|
+
return paths.map((path2) => ({
|
|
2230
|
+
path: path2,
|
|
2230
2231
|
status: "A",
|
|
2231
2232
|
patch: "",
|
|
2232
2233
|
additions: 0,
|
|
2233
2234
|
deletions: 0
|
|
2234
2235
|
}));
|
|
2235
2236
|
}
|
|
2236
|
-
function pathspec(
|
|
2237
|
-
return
|
|
2237
|
+
function pathspec(path2) {
|
|
2238
|
+
return path2 ? ["--", path2] : [];
|
|
2238
2239
|
}
|
|
2239
2240
|
function gitDiff(args, cwd, opts) {
|
|
2240
2241
|
return git(["diff", "--no-ext-diff", "--no-color", ...args], cwd, {
|
|
@@ -2242,7 +2243,7 @@ function gitDiff(args, cwd, opts) {
|
|
|
2242
2243
|
timeoutMs: opts?.timeoutMs
|
|
2243
2244
|
});
|
|
2244
2245
|
}
|
|
2245
|
-
function fileFromPatch(
|
|
2246
|
+
function fileFromPatch(path2, patch, maxHunk) {
|
|
2246
2247
|
let status = "M";
|
|
2247
2248
|
if (/^new file mode /m.test(patch) || /^--- \/dev\/null/m.test(patch)) {
|
|
2248
2249
|
status = "A";
|
|
@@ -2254,15 +2255,15 @@ function fileFromPatch(path, patch, maxHunk) {
|
|
|
2254
2255
|
const additions = patch.split("\n").filter((l) => l.startsWith("+") && !l.startsWith("+++")).length;
|
|
2255
2256
|
const deletions = patch.split("\n").filter((l) => l.startsWith("-") && !l.startsWith("---")).length;
|
|
2256
2257
|
return {
|
|
2257
|
-
path,
|
|
2258
|
+
path: path2,
|
|
2258
2259
|
status,
|
|
2259
2260
|
patch: capPatch(patch, maxHunk),
|
|
2260
2261
|
additions,
|
|
2261
2262
|
deletions
|
|
2262
2263
|
};
|
|
2263
2264
|
}
|
|
2264
|
-
async function gitDiffParts(worktreePath, diffArgs, includePatches,
|
|
2265
|
-
const extra = pathspec(
|
|
2265
|
+
async function gitDiffParts(worktreePath, diffArgs, includePatches, path2) {
|
|
2266
|
+
const extra = pathspec(path2);
|
|
2266
2267
|
if (includePatches) {
|
|
2267
2268
|
const diff = await gitDiff([...diffArgs, ...extra], worktreePath, {
|
|
2268
2269
|
timeoutMs: 4e3
|
|
@@ -2300,17 +2301,17 @@ function filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk) {
|
|
|
2300
2301
|
const patches = splitCombinedDiff(combinedDiff);
|
|
2301
2302
|
if (!nameStatus.trim() && patches.size > 0) {
|
|
2302
2303
|
return [...patches.entries()].map(
|
|
2303
|
-
([
|
|
2304
|
+
([path2, patch]) => fileFromPatch(path2, patch, maxHunk)
|
|
2304
2305
|
);
|
|
2305
2306
|
}
|
|
2306
2307
|
const counts = parseNumstat(numstat);
|
|
2307
2308
|
const files = [];
|
|
2308
|
-
for (const { status, path } of parseNameStatus(nameStatus)) {
|
|
2309
|
-
const n = counts.get(
|
|
2309
|
+
for (const { status, path: path2 } of parseNameStatus(nameStatus)) {
|
|
2310
|
+
const n = counts.get(path2);
|
|
2310
2311
|
files.push({
|
|
2311
|
-
path,
|
|
2312
|
+
path: path2,
|
|
2312
2313
|
status,
|
|
2313
|
-
patch: capPatch(patches.get(
|
|
2314
|
+
patch: capPatch(patches.get(path2) ?? "", maxHunk),
|
|
2314
2315
|
additions: n?.additions,
|
|
2315
2316
|
deletions: n?.deletions
|
|
2316
2317
|
});
|
|
@@ -2394,7 +2395,7 @@ function emptyPathDiff(scope, base, hasLastTurnBase, commitSha = null) {
|
|
|
2394
2395
|
};
|
|
2395
2396
|
}
|
|
2396
2397
|
async function getPathDiff(worktreePath, repoPath, opts) {
|
|
2397
|
-
const { path, scope, commitSha, lastTurnBase, hasLastTurnBase, includePatches, maxHunk } = opts;
|
|
2398
|
+
const { path: path2, scope, commitSha, lastTurnBase, hasLastTurnBase, includePatches, maxHunk } = opts;
|
|
2398
2399
|
if (scope === "last_turn" && !lastTurnBase) {
|
|
2399
2400
|
return emptyPathDiff(scope, "last turn", false);
|
|
2400
2401
|
}
|
|
@@ -2433,7 +2434,7 @@ async function getPathDiff(worktreePath, repoPath, opts) {
|
|
|
2433
2434
|
labelBase = "HEAD";
|
|
2434
2435
|
}
|
|
2435
2436
|
const diff = await gitDiff(
|
|
2436
|
-
includePatches ? [...diffArgs, "--",
|
|
2437
|
+
includePatches ? [...diffArgs, "--", path2] : ["--name-status", ...diffArgs, "--", path2],
|
|
2437
2438
|
worktreePath,
|
|
2438
2439
|
{ timeoutMs: 4e3 }
|
|
2439
2440
|
);
|
|
@@ -2441,8 +2442,8 @@ async function getPathDiff(worktreePath, repoPath, opts) {
|
|
|
2441
2442
|
if (includePatches) {
|
|
2442
2443
|
const parsed = filesFromDiff("", "", diff.stdout, maxHunk);
|
|
2443
2444
|
for (const file of parsed) filesMap.set(file.path, file);
|
|
2444
|
-
if (diff.stdout.trim() && !filesMap.has(
|
|
2445
|
-
filesMap.set(
|
|
2445
|
+
if (diff.stdout.trim() && !filesMap.has(path2)) {
|
|
2446
|
+
filesMap.set(path2, fileFromPatch(path2, diff.stdout, maxHunk));
|
|
2446
2447
|
}
|
|
2447
2448
|
} else {
|
|
2448
2449
|
for (const file of filesFromDiff(diff.stdout, "", "", maxHunk)) {
|
|
@@ -2450,7 +2451,7 @@ async function getPathDiff(worktreePath, repoPath, opts) {
|
|
|
2450
2451
|
}
|
|
2451
2452
|
}
|
|
2452
2453
|
if (filesMap.size === 0) {
|
|
2453
|
-
const maybe = await listUntrackedPaths(worktreePath,
|
|
2454
|
+
const maybe = await listUntrackedPaths(worktreePath, path2);
|
|
2454
2455
|
if (maybe.length > 0) {
|
|
2455
2456
|
const extra = includePatches ? await listUntrackedFiles(worktreePath, maxHunk, maybe) : untrackedStubs(maybe);
|
|
2456
2457
|
for (const file of extra) filesMap.set(file.path, file);
|
|
@@ -3473,8 +3474,8 @@ function splitForCompaction(messages, thresholds = {}) {
|
|
|
3473
3474
|
function formatToolPart(t, detail) {
|
|
3474
3475
|
if (detail === "summary") {
|
|
3475
3476
|
const label = t.description || t.detail || t.name;
|
|
3476
|
-
const
|
|
3477
|
-
return `- ${t.name}: ${label}${
|
|
3477
|
+
const path2 = t.filePath ? ` (${t.filePath})` : "";
|
|
3478
|
+
return `- ${t.name}: ${label}${path2}`;
|
|
3478
3479
|
}
|
|
3479
3480
|
const lines = [`#### Tool: ${t.name}`, `Status: ${t.status}`];
|
|
3480
3481
|
if (t.description) lines.push(`Description: ${t.description}`);
|
|
@@ -3812,7 +3813,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3812
3813
|
return readThread(thread.id) ?? thread;
|
|
3813
3814
|
}
|
|
3814
3815
|
async function listLinearIssues(agent, repoPath) {
|
|
3815
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3816
|
+
const { getAdapter: getAdapter2 } = await import("./agents-UQ7D6U6L.js");
|
|
3816
3817
|
await requireAgent(agent, { requireLinear: true });
|
|
3817
3818
|
const adapter = getAdapter2(agent);
|
|
3818
3819
|
if (!adapter.listLinearIssues) {
|
|
@@ -4355,7 +4356,7 @@ async function adoptThread(input) {
|
|
|
4355
4356
|
messages: input.messages ?? []
|
|
4356
4357
|
});
|
|
4357
4358
|
writeThread(thread);
|
|
4358
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4359
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-QLRCOXAY.js");
|
|
4359
4360
|
await ensureWorkspace2(repoPath);
|
|
4360
4361
|
return thread;
|
|
4361
4362
|
}
|
|
@@ -4606,10 +4607,10 @@ function storePath() {
|
|
|
4606
4607
|
return join8(appDataDir(), "slack-reply-to.json");
|
|
4607
4608
|
}
|
|
4608
4609
|
function readStore() {
|
|
4609
|
-
const
|
|
4610
|
-
if (!existsSync10(
|
|
4610
|
+
const path2 = storePath();
|
|
4611
|
+
if (!existsSync10(path2)) return {};
|
|
4611
4612
|
try {
|
|
4612
|
-
const parsed = isSecureFileEncrypted(
|
|
4613
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse(readFileSync8(path2, "utf8"));
|
|
4613
4614
|
return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
4614
4615
|
} catch {
|
|
4615
4616
|
return {};
|
|
@@ -4632,12 +4633,12 @@ function storePath2() {
|
|
|
4632
4633
|
}
|
|
4633
4634
|
function readStore2() {
|
|
4634
4635
|
try {
|
|
4635
|
-
const
|
|
4636
|
-
const wasEncrypted = isSecureFileEncrypted(
|
|
4637
|
-
const parsed = readSecureJson(
|
|
4636
|
+
const path2 = storePath2();
|
|
4637
|
+
const wasEncrypted = isSecureFileEncrypted(path2);
|
|
4638
|
+
const parsed = readSecureJson(path2);
|
|
4638
4639
|
const workspaces = Array.isArray(parsed?.workspaces) ? parsed.workspaces : [];
|
|
4639
4640
|
if (workspaces.length > 0 && !wasEncrypted && resolveVaultKey()) {
|
|
4640
|
-
writeSecureJson(
|
|
4641
|
+
writeSecureJson(path2, { workspaces });
|
|
4641
4642
|
}
|
|
4642
4643
|
return workspaces;
|
|
4643
4644
|
} catch {
|
|
@@ -4773,10 +4774,10 @@ function tsNewer(a, b) {
|
|
|
4773
4774
|
return Number(a) > Number(b);
|
|
4774
4775
|
}
|
|
4775
4776
|
function readStore3() {
|
|
4776
|
-
const
|
|
4777
|
-
if (!existsSync11(
|
|
4777
|
+
const path2 = storePath3();
|
|
4778
|
+
if (!existsSync11(path2)) return [];
|
|
4778
4779
|
try {
|
|
4779
|
-
const parsed = isSecureFileEncrypted(
|
|
4780
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse(readFileSync9(path2, "utf8"));
|
|
4780
4781
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
4781
4782
|
} catch {
|
|
4782
4783
|
return [];
|
|
@@ -5140,8 +5141,8 @@ function shouldAutoArchiveOnPrMerge(opts) {
|
|
|
5140
5141
|
// src/git/orphan-cleanup.ts
|
|
5141
5142
|
import { existsSync as existsSync12, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
|
|
5142
5143
|
import { join as join11 } from "path";
|
|
5143
|
-
function isSideboardWorktreePath(
|
|
5144
|
-
return
|
|
5144
|
+
function isSideboardWorktreePath(path2) {
|
|
5145
|
+
return path2.includes("/.sideboard/worktrees/") || path2.includes("/sideboard/workspaces/");
|
|
5145
5146
|
}
|
|
5146
5147
|
async function findOrphanWorktrees(repoPaths) {
|
|
5147
5148
|
const threads = listThreads({ includeArchived: true });
|
|
@@ -5166,18 +5167,18 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
5166
5167
|
try {
|
|
5167
5168
|
const wts = await listWorktrees(repoPath);
|
|
5168
5169
|
for (const wt of wts) {
|
|
5169
|
-
const
|
|
5170
|
-
if (!isSideboardWorktreePath(
|
|
5171
|
-
if (known.has(
|
|
5172
|
-
if (seen.has(
|
|
5173
|
-
seen.add(
|
|
5170
|
+
const path2 = wt.path.replace(/\/$/, "");
|
|
5171
|
+
if (!isSideboardWorktreePath(path2)) continue;
|
|
5172
|
+
if (known.has(path2)) continue;
|
|
5173
|
+
if (seen.has(path2)) continue;
|
|
5174
|
+
seen.add(path2);
|
|
5174
5175
|
let mtimeMs = 0;
|
|
5175
5176
|
try {
|
|
5176
|
-
mtimeMs = statSync5(
|
|
5177
|
+
mtimeMs = statSync5(path2).mtimeMs;
|
|
5177
5178
|
} catch {
|
|
5178
5179
|
mtimeMs = 0;
|
|
5179
5180
|
}
|
|
5180
|
-
orphans.push({ path, repoPath, mtimeMs });
|
|
5181
|
+
orphans.push({ path: path2, repoPath, mtimeMs });
|
|
5181
5182
|
}
|
|
5182
5183
|
} catch {
|
|
5183
5184
|
}
|
|
@@ -5186,17 +5187,17 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
5186
5187
|
if (existsSync12(root)) {
|
|
5187
5188
|
for (const entry of readdirSync4(root, { withFileTypes: true })) {
|
|
5188
5189
|
if (!entry.isDirectory()) continue;
|
|
5189
|
-
const
|
|
5190
|
-
if (known.has(
|
|
5191
|
-
if (!existsSync12(join11(
|
|
5192
|
-
seen.add(
|
|
5190
|
+
const path2 = join11(root, entry.name).replace(/\/$/, "");
|
|
5191
|
+
if (known.has(path2) || seen.has(path2)) continue;
|
|
5192
|
+
if (!existsSync12(join11(path2, ".git"))) continue;
|
|
5193
|
+
seen.add(path2);
|
|
5193
5194
|
let mtimeMs = 0;
|
|
5194
5195
|
try {
|
|
5195
|
-
mtimeMs = statSync5(
|
|
5196
|
+
mtimeMs = statSync5(path2).mtimeMs;
|
|
5196
5197
|
} catch {
|
|
5197
5198
|
mtimeMs = Date.now();
|
|
5198
5199
|
}
|
|
5199
|
-
orphans.push({ path, repoPath, mtimeMs });
|
|
5200
|
+
orphans.push({ path: path2, repoPath, mtimeMs });
|
|
5200
5201
|
}
|
|
5201
5202
|
}
|
|
5202
5203
|
} catch {
|
|
@@ -5579,9 +5580,9 @@ function ensureReviewRequestFile(worktreePath) {
|
|
|
5579
5580
|
const localAbs = join13(worktreePath, REVIEW_REQUEST_PATH);
|
|
5580
5581
|
const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent(join13(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
5581
5582
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
5582
|
-
const
|
|
5583
|
+
const path2 = existsSync14(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
|
|
5583
5584
|
return {
|
|
5584
|
-
path,
|
|
5585
|
+
path: path2,
|
|
5585
5586
|
name: REVIEW_REQUEST_NAME,
|
|
5586
5587
|
content: localContent,
|
|
5587
5588
|
source: "local"
|
|
@@ -5597,13 +5598,13 @@ function ensureReviewRequestFile(worktreePath) {
|
|
|
5597
5598
|
};
|
|
5598
5599
|
}
|
|
5599
5600
|
function buildReviewRequestAttachment(content, opts) {
|
|
5600
|
-
const
|
|
5601
|
-
const name = opts?.name ?? (
|
|
5601
|
+
const path2 = opts?.path ?? REVIEW_REQUEST_PATH;
|
|
5602
|
+
const name = opts?.name ?? (path2 === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
5602
5603
|
return {
|
|
5603
5604
|
id: randomUUID4(),
|
|
5604
5605
|
name,
|
|
5605
5606
|
kind: "file",
|
|
5606
|
-
path,
|
|
5607
|
+
path: path2,
|
|
5607
5608
|
content
|
|
5608
5609
|
};
|
|
5609
5610
|
}
|
|
@@ -5872,7 +5873,7 @@ var Orchestrator = class {
|
|
|
5872
5873
|
orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
|
|
5873
5874
|
});
|
|
5874
5875
|
}
|
|
5875
|
-
const { autoCleanupOrphansEnabled: autoCleanupOrphansEnabled2 } = await import("./app-settings-
|
|
5876
|
+
const { autoCleanupOrphansEnabled: autoCleanupOrphansEnabled2 } = await import("./app-settings-6IOQYGBK.js");
|
|
5876
5877
|
if (autoCleanupOrphansEnabled2() && shouldRunWorktreeCleanup() && orphans.length > 0) {
|
|
5877
5878
|
await cleanupOrphanWorktrees({ repoPaths });
|
|
5878
5879
|
}
|
|
@@ -6029,7 +6030,7 @@ var Orchestrator = class {
|
|
|
6029
6030
|
}
|
|
6030
6031
|
async finishCreateThread(threadId, prompt) {
|
|
6031
6032
|
await this.runSetupAfterCreate(threadId);
|
|
6032
|
-
const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await import("./app-settings-
|
|
6033
|
+
const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await import("./app-settings-6IOQYGBK.js");
|
|
6033
6034
|
if (autoRunAfterSetupEnabled2()) {
|
|
6034
6035
|
try {
|
|
6035
6036
|
await this.startDev(threadId);
|
|
@@ -6307,14 +6308,16 @@ var Orchestrator = class {
|
|
|
6307
6308
|
}
|
|
6308
6309
|
const isBrightsy = fresh.agent === "brightsy";
|
|
6309
6310
|
const isOrchestration = isOrchestratorThread(fresh);
|
|
6311
|
+
const { autoRenameBranchEnabled: autoRenameBranchEnabled2, getGithubGitAuthMode: getGithubGitAuthMode2 } = await import("./app-settings-6IOQYGBK.js");
|
|
6312
|
+
const gitAuthMode = getGithubGitAuthMode2();
|
|
6310
6313
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
6311
6314
|
githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
|
|
6312
6315
|
() => null
|
|
6313
|
-
)
|
|
6316
|
+
),
|
|
6317
|
+
gitAuthMode
|
|
6314
6318
|
});
|
|
6315
6319
|
const artifactDirective = isBrightsy ? null : formatArtifactDirective();
|
|
6316
6320
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
6317
|
-
const { autoRenameBranchEnabled: autoRenameBranchEnabled2 } = await import("./app-settings-3TLA2EJ7.js");
|
|
6318
6321
|
const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled2() ? formatRenameBranchDirective(fresh, {
|
|
6319
6322
|
customPrompt: settings?.prompts?.renameBranch
|
|
6320
6323
|
}) : null;
|
|
@@ -7020,7 +7023,7 @@ var Orchestrator = class {
|
|
|
7020
7023
|
updateThread(thread.id, { title: meta.title });
|
|
7021
7024
|
}
|
|
7022
7025
|
}
|
|
7023
|
-
const { autoArchiveOnMergeEnabled: autoArchiveOnMergeEnabled2 } = await import("./app-settings-
|
|
7026
|
+
const { autoArchiveOnMergeEnabled: autoArchiveOnMergeEnabled2 } = await import("./app-settings-6IOQYGBK.js");
|
|
7024
7027
|
const latest = this.requireThread(thread.id);
|
|
7025
7028
|
if (!shouldAutoArchiveOnPrMerge({
|
|
7026
7029
|
previousPrState: prevState || null,
|
|
@@ -7151,8 +7154,9 @@ var Orchestrator = class {
|
|
|
7151
7154
|
return tab;
|
|
7152
7155
|
}
|
|
7153
7156
|
/**
|
|
7154
|
-
*
|
|
7155
|
-
*
|
|
7157
|
+
* Desktop git buttons + MCP `ask_git`.
|
|
7158
|
+
* When the worktree is clean, push / open the PR here (HTTPS via `gh` if SSH
|
|
7159
|
+
* is missing). When dirty, queue the worktree agent to commit first.
|
|
7156
7160
|
*/
|
|
7157
7161
|
async askGit(threadRef, action) {
|
|
7158
7162
|
if (!AGENT_GIT_ACTIONS.includes(action)) {
|
|
@@ -7170,6 +7174,10 @@ var Orchestrator = class {
|
|
|
7170
7174
|
"No pull request linked. Ask the worktree agent to open a draft PR first (ask_git create-draft)."
|
|
7171
7175
|
);
|
|
7172
7176
|
}
|
|
7177
|
+
if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
|
|
7178
|
+
await this.pushAndMaybeOpenPr(thread, action);
|
|
7179
|
+
return this.requireThread(threadRef);
|
|
7180
|
+
}
|
|
7173
7181
|
let prBase;
|
|
7174
7182
|
if (action === "resolve-conflicts") {
|
|
7175
7183
|
try {
|
|
@@ -7180,6 +7188,34 @@ var Orchestrator = class {
|
|
|
7180
7188
|
}
|
|
7181
7189
|
return this.send(threadRef, agentGitPrompt(action, { prBase }));
|
|
7182
7190
|
}
|
|
7191
|
+
/** Push origin (gh HTTPS fallback) and create/update the PR when requested. */
|
|
7192
|
+
async pushAndMaybeOpenPr(thread, action) {
|
|
7193
|
+
const cwd = thread.worktreePath;
|
|
7194
|
+
const branch = await currentBranch(cwd);
|
|
7195
|
+
await pushBranch(cwd, branch);
|
|
7196
|
+
if (action === "commit-push") return;
|
|
7197
|
+
const base = await resolveDefaultBranch(thread.repoPath);
|
|
7198
|
+
const meta = await suggestPrMetadata(cwd, {
|
|
7199
|
+
base,
|
|
7200
|
+
fallbackTitle: thread.prTitle ?? thread.title
|
|
7201
|
+
});
|
|
7202
|
+
const url = await createOrUpdatePr(cwd, {
|
|
7203
|
+
title: meta.title,
|
|
7204
|
+
body: meta.body,
|
|
7205
|
+
base,
|
|
7206
|
+
head: branch,
|
|
7207
|
+
draft: action === "create-draft",
|
|
7208
|
+
web: action === "create-web"
|
|
7209
|
+
});
|
|
7210
|
+
if (!url) return;
|
|
7211
|
+
const patch = { prUrl: url, prTitle: meta.title };
|
|
7212
|
+
try {
|
|
7213
|
+
const fetched = await getPrMeta(cwd, url);
|
|
7214
|
+
if (fetched?.title) patch.prTitle = fetched.title;
|
|
7215
|
+
} catch {
|
|
7216
|
+
}
|
|
7217
|
+
updateThread(thread.id, patch);
|
|
7218
|
+
}
|
|
7183
7219
|
setThreadOptions(threadRef, patch) {
|
|
7184
7220
|
const thread = this.requireThread(threadRef);
|
|
7185
7221
|
const next = {};
|
|
@@ -7275,7 +7311,7 @@ var Orchestrator = class {
|
|
|
7275
7311
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7276
7312
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7277
7313
|
try {
|
|
7278
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
7314
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-QLRCOXAY.js");
|
|
7279
7315
|
await ensureWorkspace2(thread.repoPath);
|
|
7280
7316
|
} catch {
|
|
7281
7317
|
}
|
|
@@ -7297,7 +7333,7 @@ var Orchestrator = class {
|
|
|
7297
7333
|
await runArchiveScript(thread.repoPath, thread.worktreePath);
|
|
7298
7334
|
} catch {
|
|
7299
7335
|
}
|
|
7300
|
-
const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await import("./app-settings-
|
|
7336
|
+
const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await import("./app-settings-6IOQYGBK.js");
|
|
7301
7337
|
const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled2();
|
|
7302
7338
|
await removeWorktree(thread.repoPath, thread.worktreePath, {
|
|
7303
7339
|
deleteBranch: deleteBranch ? thread.branchName : void 0
|
|
@@ -7318,7 +7354,7 @@ var Orchestrator = class {
|
|
|
7318
7354
|
return restored2;
|
|
7319
7355
|
}
|
|
7320
7356
|
if (!existsSync15(thread.worktreePath)) {
|
|
7321
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
7357
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-5VLLFI5W.js");
|
|
7322
7358
|
const { execa: execa6 } = await import("execa");
|
|
7323
7359
|
const slug = thread.worktreePath.split("/").pop();
|
|
7324
7360
|
const dest = thread.worktreePath;
|
|
@@ -7427,7 +7463,7 @@ async function startOrchestration(opts) {
|
|
|
7427
7463
|
sourceRef: "default",
|
|
7428
7464
|
...createOpts
|
|
7429
7465
|
}).catch(async () => {
|
|
7430
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
7466
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-5VLLFI5W.js");
|
|
7431
7467
|
const repo = await resolveRepoRoot2(repoPath);
|
|
7432
7468
|
const def = await resolveDefaultBranch2(repo);
|
|
7433
7469
|
return createThread({
|
|
@@ -7745,9 +7781,9 @@ function labelGithubUrl(url) {
|
|
|
7745
7781
|
return null;
|
|
7746
7782
|
}
|
|
7747
7783
|
if (!/(^|\.)github\.com$/i.test(parsed.hostname)) return null;
|
|
7748
|
-
const
|
|
7784
|
+
const path2 = parsed.pathname;
|
|
7749
7785
|
const hash = parsed.hash || "";
|
|
7750
|
-
const pr =
|
|
7786
|
+
const pr = path2.match(/\/([^/]+)\/([^/]+)\/pull\/(\d+)/i);
|
|
7751
7787
|
if (pr) {
|
|
7752
7788
|
const n = pr[3];
|
|
7753
7789
|
if (/#discussion_r\d+/i.test(hash) || /#pullrequestreview-\d+/i.test(hash)) {
|
|
@@ -7758,11 +7794,11 @@ function labelGithubUrl(url) {
|
|
|
7758
7794
|
}
|
|
7759
7795
|
return { kind: "pr", label: `PR #${n}`, url: raw };
|
|
7760
7796
|
}
|
|
7761
|
-
const issueComment =
|
|
7797
|
+
const issueComment = path2.match(/\/([^/]+)\/([^/]+)\/issues\/(\d+)/i);
|
|
7762
7798
|
if (issueComment && /#issuecomment-\d+/i.test(hash)) {
|
|
7763
7799
|
return { kind: "comment", label: `Issue #${issueComment[3]} comment`, url: raw };
|
|
7764
7800
|
}
|
|
7765
|
-
const blob =
|
|
7801
|
+
const blob = path2.match(/\/([^/]+)\/([^/]+)\/blob\/[^/]+\/(.+)$/i);
|
|
7766
7802
|
if (blob) {
|
|
7767
7803
|
const filePath = decodeURIComponent(blob[3]);
|
|
7768
7804
|
const fileName = filePath.split("/").pop() || filePath;
|
|
@@ -8179,7 +8215,7 @@ function withTimeout(promise, ms, label) {
|
|
|
8179
8215
|
async function startMcpServer() {
|
|
8180
8216
|
const orch = getOrchestrator();
|
|
8181
8217
|
try {
|
|
8182
|
-
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-
|
|
8218
|
+
const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-6IOQYGBK.js");
|
|
8183
8219
|
orch.setMaxConcurrent(maxConcurrentAgents2());
|
|
8184
8220
|
} catch {
|
|
8185
8221
|
}
|
|
@@ -8324,10 +8360,10 @@ async function startMcpServer() {
|
|
|
8324
8360
|
const t = orch.getThread(thread_id.trim());
|
|
8325
8361
|
if (t?.worktreePath?.trim()) root = t.worktreePath;
|
|
8326
8362
|
}
|
|
8327
|
-
const
|
|
8363
|
+
const path2 = writePlanFile2(root, content);
|
|
8328
8364
|
const payload = {
|
|
8329
8365
|
ok: true,
|
|
8330
|
-
path,
|
|
8366
|
+
path: path2,
|
|
8331
8367
|
title: title?.trim() || "Plan",
|
|
8332
8368
|
message: "Plan saved to .context/attachments/plan.md and shown in Sideboard chat for approval."
|
|
8333
8369
|
};
|
|
@@ -8389,7 +8425,7 @@ async function startMcpServer() {
|
|
|
8389
8425
|
registerLinearTools(server);
|
|
8390
8426
|
if (sideboardMcpProfile() !== "worktree") {
|
|
8391
8427
|
const { getCaffeinateHold: getCaffeinateHold2, setCaffeinateHold: setCaffeinateHold2 } = await import("./caffeinate-hold-EAZNWJBE.js");
|
|
8392
|
-
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-
|
|
8428
|
+
const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-6IOQYGBK.js");
|
|
8393
8429
|
const accountDefaults = resolveThreadDefaults2();
|
|
8394
8430
|
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
8395
8431
|
server.tool(
|
|
@@ -8547,7 +8583,7 @@ async function startMcpServer() {
|
|
|
8547
8583
|
);
|
|
8548
8584
|
server.tool(
|
|
8549
8585
|
"send_to_thread",
|
|
8550
|
-
|
|
8586
|
+
'Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. For commit/push/PR, prefer ask_git (canonical desktop-button phrases). Send "Merge PR." / ask_git merge only when the user explicitly asked to merge. Set force_stop=true to interrupt an in-flight/queued turn (kill + clear queue) before queueing this prompt \u2014 use when the thread is mid-turn or has stale queued prompts you need to replace.',
|
|
8551
8587
|
{
|
|
8552
8588
|
ref: z3.string(),
|
|
8553
8589
|
prompt: z3.string(),
|
|
@@ -8643,7 +8679,7 @@ async function startMcpServer() {
|
|
|
8643
8679
|
);
|
|
8644
8680
|
server.tool(
|
|
8645
8681
|
"archive_thread",
|
|
8646
|
-
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Coordinators commit, push, open PRs
|
|
8682
|
+
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Coordinators commit, push, and open PRs by asking the worktree agent (ask_git). Merge only when the user explicitly asked.",
|
|
8647
8683
|
{ ref: z3.string() },
|
|
8648
8684
|
async ({ ref }) => {
|
|
8649
8685
|
const t = orch.getThread(ref);
|
|
@@ -8751,7 +8787,7 @@ async function startMcpServer() {
|
|
|
8751
8787
|
);
|
|
8752
8788
|
server.tool(
|
|
8753
8789
|
"ask_git",
|
|
8754
|
-
"
|
|
8790
|
+
"Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` if SSH is missing). When dirty, queues the worktree agent to commit; then wait_for_turn. Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd.",
|
|
8755
8791
|
{
|
|
8756
8792
|
ref: z3.string().describe("Worktree thread id/ref"),
|
|
8757
8793
|
action: z3.enum(AGENT_GIT_ACTIONS).describe(
|
|
@@ -9052,7 +9088,7 @@ async function startMcpServer() {
|
|
|
9052
9088
|
);
|
|
9053
9089
|
server.tool(
|
|
9054
9090
|
"get_pr_stack",
|
|
9055
|
-
"Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before ask_git merge on stacked PRs.",
|
|
9091
|
+
"Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before ask_git merge on stacked PRs (and only merge when the user explicitly asked).",
|
|
9056
9092
|
{ ref: z3.string() },
|
|
9057
9093
|
async ({ ref }) => {
|
|
9058
9094
|
const stack = await orch.getPrStack(ref);
|
|
@@ -9219,9 +9255,9 @@ var BrightsySideboardApi = class {
|
|
|
9219
9255
|
get endpoint() {
|
|
9220
9256
|
return (this.cfg.endpoint || "https://brightsy.ai").replace(/\/$/, "");
|
|
9221
9257
|
}
|
|
9222
|
-
async request(
|
|
9258
|
+
async request(path2, init = {}) {
|
|
9223
9259
|
await this.refreshIfNeeded();
|
|
9224
|
-
const url = `${this.endpoint}${
|
|
9260
|
+
const url = `${this.endpoint}${path2}`;
|
|
9225
9261
|
const headers = {
|
|
9226
9262
|
Authorization: `Bearer ${this.cfg.access_token}`,
|
|
9227
9263
|
Accept: "application/json"
|
|
@@ -10809,6 +10845,83 @@ var SlackRelayHub = class {
|
|
|
10809
10845
|
// src/slack/relay-server.ts
|
|
10810
10846
|
import { createServer as createServer3 } from "http";
|
|
10811
10847
|
import { WebSocketServer } from "ws";
|
|
10848
|
+
|
|
10849
|
+
// src/slack/relay-static.ts
|
|
10850
|
+
import { createReadStream } from "fs";
|
|
10851
|
+
import { stat } from "fs/promises";
|
|
10852
|
+
import path from "path";
|
|
10853
|
+
var TYPES = {
|
|
10854
|
+
".css": "text/css; charset=utf-8",
|
|
10855
|
+
".html": "text/html; charset=utf-8",
|
|
10856
|
+
".ico": "image/x-icon",
|
|
10857
|
+
".jpeg": "image/jpeg",
|
|
10858
|
+
".jpg": "image/jpeg",
|
|
10859
|
+
".js": "text/javascript; charset=utf-8",
|
|
10860
|
+
".json": "application/json; charset=utf-8",
|
|
10861
|
+
".png": "image/png",
|
|
10862
|
+
".svg": "image/svg+xml",
|
|
10863
|
+
".txt": "text/plain; charset=utf-8",
|
|
10864
|
+
".webp": "image/webp",
|
|
10865
|
+
".woff2": "font/woff2"
|
|
10866
|
+
};
|
|
10867
|
+
function requestHostname(req) {
|
|
10868
|
+
const raw = req.headers.host ?? "";
|
|
10869
|
+
return raw.split(":")[0]?.toLowerCase() ?? "";
|
|
10870
|
+
}
|
|
10871
|
+
function hostnameAllowed(host, allowed) {
|
|
10872
|
+
if (!allowed || allowed.length === 0) return true;
|
|
10873
|
+
return allowed.includes(host);
|
|
10874
|
+
}
|
|
10875
|
+
function resolveStaticPath(root, requestUrl) {
|
|
10876
|
+
let pathname;
|
|
10877
|
+
try {
|
|
10878
|
+
pathname = decodeURIComponent(new URL(requestUrl, "http://relay.local").pathname);
|
|
10879
|
+
} catch {
|
|
10880
|
+
return null;
|
|
10881
|
+
}
|
|
10882
|
+
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
10883
|
+
const rootResolved = path.resolve(root);
|
|
10884
|
+
const candidate = path.resolve(rootResolved, `.${pathname}`);
|
|
10885
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + path.sep)) {
|
|
10886
|
+
return null;
|
|
10887
|
+
}
|
|
10888
|
+
return candidate;
|
|
10889
|
+
}
|
|
10890
|
+
async function fileSize(file) {
|
|
10891
|
+
try {
|
|
10892
|
+
const st = await stat(file);
|
|
10893
|
+
return st.isFile() ? st.size : null;
|
|
10894
|
+
} catch {
|
|
10895
|
+
return null;
|
|
10896
|
+
}
|
|
10897
|
+
}
|
|
10898
|
+
function sendFile(req, res, file, size) {
|
|
10899
|
+
const ext = path.extname(file).toLowerCase();
|
|
10900
|
+
res.writeHead(200, {
|
|
10901
|
+
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
10902
|
+
"Content-Length": size,
|
|
10903
|
+
"Cache-Control": ext === ".html" ? "no-cache" : "public, max-age=3600"
|
|
10904
|
+
});
|
|
10905
|
+
if (req.method === "HEAD") {
|
|
10906
|
+
res.end();
|
|
10907
|
+
return true;
|
|
10908
|
+
}
|
|
10909
|
+
createReadStream(file).pipe(res);
|
|
10910
|
+
return true;
|
|
10911
|
+
}
|
|
10912
|
+
async function tryServeStatic(req, res, root) {
|
|
10913
|
+
if (req.method !== "GET" && req.method !== "HEAD") return false;
|
|
10914
|
+
const candidate = resolveStaticPath(root, req.url || "/");
|
|
10915
|
+
if (!candidate) return false;
|
|
10916
|
+
const direct = await fileSize(candidate);
|
|
10917
|
+
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
10918
|
+
const asIndex = path.join(candidate, "index.html");
|
|
10919
|
+
const indexSize = await fileSize(asIndex);
|
|
10920
|
+
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
10921
|
+
return false;
|
|
10922
|
+
}
|
|
10923
|
+
|
|
10924
|
+
// src/slack/relay-server.ts
|
|
10812
10925
|
function sendHtml(res, status, title, body) {
|
|
10813
10926
|
res.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
|
|
10814
10927
|
res.end(slackOAuthHtmlPage(title, body));
|
|
@@ -10907,7 +11020,26 @@ async function startSlackRelayServer(opts) {
|
|
|
10907
11020
|
const reqUrl = req.url || "/";
|
|
10908
11021
|
if (await handleCallback(reqUrl, res)) return;
|
|
10909
11022
|
if (handleResult(reqUrl, res)) return;
|
|
10910
|
-
if (req.url === "/health"
|
|
11023
|
+
if (req.url === "/health") {
|
|
11024
|
+
sendJson(res, 200, {
|
|
11025
|
+
ok: true,
|
|
11026
|
+
service: "sideboard-slack-relay",
|
|
11027
|
+
sessions: hub.listSessions().length,
|
|
11028
|
+
oauth: Boolean(clientSecret)
|
|
11029
|
+
});
|
|
11030
|
+
return;
|
|
11031
|
+
}
|
|
11032
|
+
const hostname = requestHostname(req);
|
|
11033
|
+
const canonical = (opts.canonicalSiteHost ?? "www.sideboard.cloud").toLowerCase();
|
|
11034
|
+
if (opts.redirectHosts?.includes(hostname) && hostname !== canonical) {
|
|
11035
|
+
res.writeHead(301, { Location: `https://${canonical}${reqUrl}` });
|
|
11036
|
+
res.end();
|
|
11037
|
+
return;
|
|
11038
|
+
}
|
|
11039
|
+
if (opts.staticRoot && hostnameAllowed(hostname, opts.staticHosts) && await tryServeStatic(req, res, opts.staticRoot)) {
|
|
11040
|
+
return;
|
|
11041
|
+
}
|
|
11042
|
+
if (req.url === "/") {
|
|
10911
11043
|
sendJson(res, 200, {
|
|
10912
11044
|
ok: true,
|
|
10913
11045
|
service: "sideboard-slack-relay",
|
|
@@ -11016,6 +11148,7 @@ export {
|
|
|
11016
11148
|
CONTEXT_MIN_MESSAGES,
|
|
11017
11149
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
11018
11150
|
FAMOUS_SOCCER_TEAMS,
|
|
11151
|
+
GITHUB_GIT_AUTH_MODES,
|
|
11019
11152
|
GLOBAL_WORKSPACE_ID,
|
|
11020
11153
|
HARNESS_ENV_KEYS,
|
|
11021
11154
|
LEGACY_ATTACHMENTS_DIR,
|
|
@@ -11065,10 +11198,12 @@ export {
|
|
|
11065
11198
|
allocateTeamSlug,
|
|
11066
11199
|
appDataDir,
|
|
11067
11200
|
appSettingsPath,
|
|
11201
|
+
appendIndexedGitConfig,
|
|
11068
11202
|
appendMessage,
|
|
11069
11203
|
applyAgentEvent,
|
|
11070
11204
|
applyAppEnvironment,
|
|
11071
11205
|
applyCompaction,
|
|
11206
|
+
applyGithubGitAuthEnv,
|
|
11072
11207
|
applyThreadIntoMain,
|
|
11073
11208
|
applyTurnUsage,
|
|
11074
11209
|
assertOrchestratorCapableAgent,
|
|
@@ -11183,6 +11318,7 @@ export {
|
|
|
11183
11318
|
formatBrightsyFetchError,
|
|
11184
11319
|
formatFetchError,
|
|
11185
11320
|
formatGhLandError,
|
|
11321
|
+
formatGitAuthModeDirective,
|
|
11186
11322
|
formatIpcInvokeError,
|
|
11187
11323
|
formatMessagesAsTranscript,
|
|
11188
11324
|
formatPlanQuestionAnswers,
|
|
@@ -11197,6 +11333,7 @@ export {
|
|
|
11197
11333
|
formatWorkspaceInventory,
|
|
11198
11334
|
formatWorktreeDirective,
|
|
11199
11335
|
formatWorktreeReminder,
|
|
11336
|
+
fromInclusiveInputUsage,
|
|
11200
11337
|
getAdapter,
|
|
11201
11338
|
getAgentSetupInfo,
|
|
11202
11339
|
getBrightsySession,
|
|
@@ -11209,6 +11346,8 @@ export {
|
|
|
11209
11346
|
getDiff,
|
|
11210
11347
|
getDiffSummary,
|
|
11211
11348
|
getGitHubStatus,
|
|
11349
|
+
getGithubGitAuthMode,
|
|
11350
|
+
getGithubPat,
|
|
11212
11351
|
getIssueSource,
|
|
11213
11352
|
getLinearApiKey,
|
|
11214
11353
|
getLinearAuthToken,
|
|
@@ -11227,6 +11366,7 @@ export {
|
|
|
11227
11366
|
ghHeadRef,
|
|
11228
11367
|
ghRepoSelectArgs,
|
|
11229
11368
|
git,
|
|
11369
|
+
githubAgentGitEnv,
|
|
11230
11370
|
globalAgentCwd,
|
|
11231
11371
|
handleSlackInbound,
|
|
11232
11372
|
harnessEnvKey,
|
|
@@ -11449,6 +11589,7 @@ export {
|
|
|
11449
11589
|
startSlackOAuth,
|
|
11450
11590
|
startSlackRelayServer,
|
|
11451
11591
|
stripBrightsyNdjsonNoise,
|
|
11592
|
+
stripNestedElectronEnv,
|
|
11452
11593
|
submitPrStack,
|
|
11453
11594
|
suggestSlug,
|
|
11454
11595
|
summarizeConversation,
|