@sideboard-ai/core 0.1.67 → 0.1.71
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-OTBZVTZO.js → agents-GB7XL2LI.js} +8 -7
- package/dist/{agents-TS3EI2YI.js → agents-TCAK3MXN.js} +8 -7
- package/dist/{app-settings-ONKMFSEJ.js → app-settings-3TLA2EJ7.js} +16 -1
- package/dist/{app-settings-GJVZGU3M.js → app-settings-P42Z3VOB.js} +16 -1
- package/dist/caffeinate-hold-BEJIYPJ7.js +107 -0
- package/dist/caffeinate-hold-KLC6SABD.js +14 -0
- package/dist/{chunk-WAFIF22N.js → chunk-3CY6WJ7O.js} +2 -2
- package/dist/{chunk-7ZOQY4A7.js → chunk-57ROTAFD.js} +62 -3
- package/dist/{chunk-57WWNMFP.js → chunk-7NCIHRAU.js} +22 -4
- package/dist/{chunk-FGDJOJ2L.js → chunk-AE5VBOFE.js} +1 -1
- package/dist/{chunk-DB3I75FI.js → chunk-BTL7EMGT.js} +4 -4
- package/dist/{chunk-4UIYN56C.js → chunk-D4DPQ552.js} +1 -1
- package/dist/{chunk-JWZNK3CQ.js → chunk-DGPUAZA4.js} +62 -3
- package/dist/{chunk-ZRFAZVGL.js → chunk-H2IXNFQ2.js} +22 -4
- package/dist/chunk-JAWEDVVA.js +106 -0
- package/dist/chunk-JT7R45JB.js +20 -0
- package/dist/{chunk-4BUCGNZS.js → chunk-MF2YMEGD.js} +83 -29
- package/dist/{chunk-K7LM4CLD.js → chunk-NG7S3OPX.js} +12 -6
- package/dist/chunk-NSTQ6QKD.js +23 -0
- package/dist/{chunk-LW5CMQGZ.js → chunk-OE7YBB5X.js} +83 -29
- package/dist/{chunk-BPOTVI5J.js → chunk-PTJJIQK7.js} +472 -18
- package/dist/{chunk-B4PRRKMA.js → chunk-S25IHL5H.js} +12 -6
- package/dist/{chunk-5HTTCYWA.js → chunk-UH57WVFP.js} +2 -2
- package/dist/{chunk-M5V4QIWF.js → chunk-VROPG6QF.js} +1 -1
- package/dist/{chunk-MHR4OGZ4.js → chunk-W7YOTDVO.js} +493 -18
- package/dist/{connected-teams-RUNMOCG5.js → connected-teams-35EIRJCP.js} +2 -2
- package/dist/{connected-teams-OMDHTL6A.js → connected-teams-ZRS53OAT.js} +2 -2
- package/dist/{coordinator-prompt-6HMTOX4G.js → coordinator-prompt-2J4PIMUF.js} +7 -4
- package/dist/{coordinator-prompt-3BSMKZL4.js → coordinator-prompt-QYYG2IBB.js} +7 -4
- package/dist/{global-workspace-YZ2NJVLL.js → global-workspace-KHIFQUUM.js} +12 -5
- package/dist/{global-workspace-QS7A23CB.js → global-workspace-SVRYNJZA.js} +12 -5
- package/dist/index.cjs +4805 -1262
- package/dist/index.d.cts +570 -22
- package/dist/index.d.ts +570 -22
- package/dist/index.js +3084 -340
- package/dist/mcp/run-stdio.cjs +2339 -617
- package/dist/mcp/run-stdio.js +1289 -290
- package/dist/{run-Y2MI3EVV.js → run-A4RHY7HH.js} +1 -1
- package/dist/{run-JLD2Y52J.js → run-V2WZUMJA.js} +1 -1
- package/dist/{workspaces-EBFW7I7S.js → workspaces-AHFTHVBT.js} +7 -6
- package/dist/{workspaces-AIUYUXB7.js → workspaces-SVQIEVIZ.js} +7 -6
- package/dist/{worktree-WMDJW2BL.js → worktree-KWXHMKRN.js} +2 -2
- package/dist/{worktree-7NBPIVFZ.js → worktree-VOCH3WS3.js} +2 -2
- package/package.json +3 -1
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
chmodOwnerOnly,
|
|
5
|
+
writePrivateFile
|
|
6
|
+
} from "./chunk-NSTQ6QKD.js";
|
|
3
7
|
import {
|
|
4
8
|
normalizeThinkingEffort
|
|
5
9
|
} from "./chunk-KGZBYWZ3.js";
|
|
@@ -8,9 +12,179 @@ import {
|
|
|
8
12
|
} from "./chunk-7MV3RXSC.js";
|
|
9
13
|
|
|
10
14
|
// src/store/app-settings.ts
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
15
|
+
import { randomUUID } from "crypto";
|
|
16
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
17
|
+
import { homedir, hostname } from "os";
|
|
18
|
+
import { join as join2 } from "path";
|
|
19
|
+
|
|
20
|
+
// src/store/secret-vault.ts
|
|
13
21
|
import { join } from "path";
|
|
22
|
+
|
|
23
|
+
// src/store/secure-file.ts
|
|
24
|
+
import { execFileSync } from "child_process";
|
|
25
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
26
|
+
import { existsSync, readFileSync } from "fs";
|
|
27
|
+
var KEYCHAIN_SERVICE = "ai.sideboard.app";
|
|
28
|
+
var KEYCHAIN_ACCOUNT = "secret-vault-v1";
|
|
29
|
+
var ALG = "aes-256-gcm";
|
|
30
|
+
var injectedKey = null;
|
|
31
|
+
function persistVaultKeyInKeychain(key) {
|
|
32
|
+
if (process.platform !== "darwin" || key.length !== 32) return;
|
|
33
|
+
try {
|
|
34
|
+
execFileSync(
|
|
35
|
+
"security",
|
|
36
|
+
[
|
|
37
|
+
"add-generic-password",
|
|
38
|
+
"-s",
|
|
39
|
+
KEYCHAIN_SERVICE,
|
|
40
|
+
"-a",
|
|
41
|
+
KEYCHAIN_ACCOUNT,
|
|
42
|
+
"-w",
|
|
43
|
+
key.toString("hex"),
|
|
44
|
+
"-U"
|
|
45
|
+
],
|
|
46
|
+
{ encoding: "utf8", timeout: 8e3, stdio: ["ignore", "pipe", "pipe"] }
|
|
47
|
+
);
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function hexKey(value) {
|
|
52
|
+
const trimmed = value?.trim() ?? "";
|
|
53
|
+
if (!/^[0-9a-f]{64}$/i.test(trimmed)) return null;
|
|
54
|
+
return Buffer.from(trimmed, "hex");
|
|
55
|
+
}
|
|
56
|
+
function keychainKey(create) {
|
|
57
|
+
if (process.platform !== "darwin") return null;
|
|
58
|
+
try {
|
|
59
|
+
const out = execFileSync(
|
|
60
|
+
"security",
|
|
61
|
+
["find-generic-password", "-s", KEYCHAIN_SERVICE, "-a", KEYCHAIN_ACCOUNT, "-w"],
|
|
62
|
+
{ encoding: "utf8", timeout: 5e3, stdio: ["ignore", "pipe", "pipe"] }
|
|
63
|
+
).trim();
|
|
64
|
+
const key2 = hexKey(out);
|
|
65
|
+
if (key2) return key2;
|
|
66
|
+
} catch {
|
|
67
|
+
}
|
|
68
|
+
if (!create) return null;
|
|
69
|
+
const key = randomBytes(32);
|
|
70
|
+
persistVaultKeyInKeychain(key);
|
|
71
|
+
return key;
|
|
72
|
+
}
|
|
73
|
+
function resolveVaultKey() {
|
|
74
|
+
if (process.env.SIDEBOARD_SECRET_VAULT === "plain") return null;
|
|
75
|
+
if (injectedKey) return injectedKey;
|
|
76
|
+
const fromEnv = hexKey(process.env.SIDEBOARD_VAULT_KEY);
|
|
77
|
+
if (fromEnv) return fromEnv;
|
|
78
|
+
if (process.env.VITEST) return null;
|
|
79
|
+
return keychainKey(true);
|
|
80
|
+
}
|
|
81
|
+
function isEnvelope(value) {
|
|
82
|
+
if (!value || typeof value !== "object") return false;
|
|
83
|
+
const o = value;
|
|
84
|
+
return o.v === 1 && o.alg === ALG && typeof o.iv === "string" && typeof o.tag === "string" && typeof o.data === "string";
|
|
85
|
+
}
|
|
86
|
+
function encryptJson(value, key) {
|
|
87
|
+
const iv = randomBytes(12);
|
|
88
|
+
const cipher = createCipheriv(ALG, key, iv);
|
|
89
|
+
const plaintext = Buffer.from(`${JSON.stringify(value)}
|
|
90
|
+
`, "utf8");
|
|
91
|
+
const data = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
92
|
+
const tag = cipher.getAuthTag();
|
|
93
|
+
return {
|
|
94
|
+
v: 1,
|
|
95
|
+
alg: ALG,
|
|
96
|
+
iv: iv.toString("base64"),
|
|
97
|
+
tag: tag.toString("base64"),
|
|
98
|
+
data: data.toString("base64")
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function decryptEnvelope(envelope, key) {
|
|
102
|
+
const decipher = createDecipheriv(ALG, key, Buffer.from(envelope.iv, "base64"));
|
|
103
|
+
decipher.setAuthTag(Buffer.from(envelope.tag, "base64"));
|
|
104
|
+
const plaintext = Buffer.concat([
|
|
105
|
+
decipher.update(Buffer.from(envelope.data, "base64")),
|
|
106
|
+
decipher.final()
|
|
107
|
+
]);
|
|
108
|
+
return JSON.parse(plaintext.toString("utf8"));
|
|
109
|
+
}
|
|
110
|
+
function readSecureJson(path) {
|
|
111
|
+
if (!existsSync(path)) return null;
|
|
112
|
+
chmodOwnerOnly(path);
|
|
113
|
+
let parsed;
|
|
114
|
+
try {
|
|
115
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
116
|
+
} catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (!isEnvelope(parsed)) return parsed;
|
|
120
|
+
const key = resolveVaultKey();
|
|
121
|
+
if (!key) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"Encrypted Sideboard secrets need a vault key (desktop Keychain / safeStorage, or SIDEBOARD_VAULT_KEY)."
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return decryptEnvelope(parsed, key);
|
|
127
|
+
}
|
|
128
|
+
function writeSecureJson(path, value) {
|
|
129
|
+
const key = resolveVaultKey();
|
|
130
|
+
const body = key ? encryptJson(value, key) : value;
|
|
131
|
+
writePrivateFile(path, `${JSON.stringify(body, null, 2)}
|
|
132
|
+
`);
|
|
133
|
+
}
|
|
134
|
+
function isSecureFileEncrypted(path) {
|
|
135
|
+
if (!existsSync(path)) return false;
|
|
136
|
+
try {
|
|
137
|
+
return isEnvelope(JSON.parse(readFileSync(path, "utf8")));
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/store/secret-vault.ts
|
|
144
|
+
function secretVaultPath() {
|
|
145
|
+
return join(appDataDir(), "secrets.json");
|
|
146
|
+
}
|
|
147
|
+
function loadSecretVault() {
|
|
148
|
+
const parsed = readSecureJson(secretVaultPath());
|
|
149
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
150
|
+
return normalizeVault(parsed);
|
|
151
|
+
}
|
|
152
|
+
function saveSecretVault(vault) {
|
|
153
|
+
writeSecureJson(secretVaultPath(), normalizeVault(vault));
|
|
154
|
+
}
|
|
155
|
+
function normalizeVault(raw) {
|
|
156
|
+
const out = {};
|
|
157
|
+
if (typeof raw.linearApiKey === "string" && raw.linearApiKey.trim()) {
|
|
158
|
+
out.linearApiKey = raw.linearApiKey.trim();
|
|
159
|
+
}
|
|
160
|
+
if (typeof raw.linearAccessToken === "string" && raw.linearAccessToken.trim()) {
|
|
161
|
+
out.linearAccessToken = raw.linearAccessToken.trim();
|
|
162
|
+
}
|
|
163
|
+
if (typeof raw.linearRefreshToken === "string" && raw.linearRefreshToken.trim()) {
|
|
164
|
+
out.linearRefreshToken = raw.linearRefreshToken.trim();
|
|
165
|
+
}
|
|
166
|
+
if (typeof raw.linearClientSecret === "string" && raw.linearClientSecret.trim()) {
|
|
167
|
+
out.linearClientSecret = raw.linearClientSecret.trim();
|
|
168
|
+
}
|
|
169
|
+
if (typeof raw.slackClientSecret === "string" && raw.slackClientSecret.trim()) {
|
|
170
|
+
out.slackClientSecret = raw.slackClientSecret.trim();
|
|
171
|
+
}
|
|
172
|
+
if (typeof raw.slackAppToken === "string" && raw.slackAppToken.trim()) {
|
|
173
|
+
out.slackAppToken = raw.slackAppToken.trim();
|
|
174
|
+
}
|
|
175
|
+
if (raw.environment && typeof raw.environment === "object") {
|
|
176
|
+
const environment = {};
|
|
177
|
+
for (const [key, value] of Object.entries(raw.environment)) {
|
|
178
|
+
const k = key.trim();
|
|
179
|
+
const v = typeof value === "string" ? value.trim() : "";
|
|
180
|
+
if (k && v) environment[k] = v;
|
|
181
|
+
}
|
|
182
|
+
if (Object.keys(environment).length > 0) out.environment = environment;
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/store/app-settings.ts
|
|
14
188
|
var HARNESS_ENV_KEYS = {
|
|
15
189
|
claude: "ANTHROPIC_API_KEY",
|
|
16
190
|
codex: "CODEX_API_KEY",
|
|
@@ -25,11 +199,45 @@ var DEFAULT_AGENTS = /* @__PURE__ */ new Set([
|
|
|
25
199
|
"brightsy",
|
|
26
200
|
"cursor"
|
|
27
201
|
]);
|
|
202
|
+
function hasLinearOAuth(integrations) {
|
|
203
|
+
return Boolean(
|
|
204
|
+
integrations.linearAccessToken?.trim() || integrations.linearRefreshToken?.trim()
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
function hasLinearCredentials(integrations) {
|
|
208
|
+
return Boolean(integrations.linearApiKey?.trim()) || hasLinearOAuth(integrations);
|
|
209
|
+
}
|
|
210
|
+
function toPublicAppSettings(settings) {
|
|
211
|
+
const environment = {};
|
|
212
|
+
for (const key of Object.keys(settings.environment)) {
|
|
213
|
+
if (key.trim()) environment[key] = "";
|
|
214
|
+
}
|
|
215
|
+
const integrations = { ...settings.integrations };
|
|
216
|
+
const slackClientSecret = integrations.slackClientSecret;
|
|
217
|
+
const slackAppToken = integrations.slackAppToken;
|
|
218
|
+
delete integrations.linearApiKey;
|
|
219
|
+
delete integrations.linearAccessToken;
|
|
220
|
+
delete integrations.linearRefreshToken;
|
|
221
|
+
delete integrations.linearClientSecret;
|
|
222
|
+
delete integrations.slackClientSecret;
|
|
223
|
+
delete integrations.slackAppToken;
|
|
224
|
+
return {
|
|
225
|
+
...settings,
|
|
226
|
+
environment,
|
|
227
|
+
integrations: {
|
|
228
|
+
...integrations,
|
|
229
|
+
hasLinearApiKey: hasLinearCredentials(settings.integrations),
|
|
230
|
+
hasLinearOAuth: hasLinearOAuth(settings.integrations),
|
|
231
|
+
hasSlackClientSecret: Boolean(slackClientSecret?.trim()),
|
|
232
|
+
hasSlackAppToken: Boolean(slackAppToken?.trim())
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
28
236
|
function appSettingsPath() {
|
|
29
|
-
return
|
|
237
|
+
return join2(appDataDir(), "settings.json");
|
|
30
238
|
}
|
|
31
239
|
function claudeUserSettingsPath() {
|
|
32
|
-
return
|
|
240
|
+
return join2(homedir(), ".claude", "settings.json");
|
|
33
241
|
}
|
|
34
242
|
function normalizeClaude(raw) {
|
|
35
243
|
if (!raw || typeof raw !== "object") return {};
|
|
@@ -88,9 +296,62 @@ function normalizeIntegrations(raw) {
|
|
|
88
296
|
const key = source.linearApiKey.trim();
|
|
89
297
|
if (key) out.linearApiKey = key;
|
|
90
298
|
}
|
|
299
|
+
if (typeof source.linearAccessToken === "string") {
|
|
300
|
+
const token = source.linearAccessToken.trim();
|
|
301
|
+
if (token) out.linearAccessToken = token;
|
|
302
|
+
}
|
|
303
|
+
if (typeof source.linearRefreshToken === "string") {
|
|
304
|
+
const token = source.linearRefreshToken.trim();
|
|
305
|
+
if (token) out.linearRefreshToken = token;
|
|
306
|
+
}
|
|
307
|
+
if (typeof source.linearTokenExpiresAt === "number" && Number.isFinite(source.linearTokenExpiresAt)) {
|
|
308
|
+
out.linearTokenExpiresAt = source.linearTokenExpiresAt;
|
|
309
|
+
} else if (typeof source.linearTokenExpiresAt === "string") {
|
|
310
|
+
const n = Number(source.linearTokenExpiresAt);
|
|
311
|
+
if (Number.isFinite(n)) out.linearTokenExpiresAt = n;
|
|
312
|
+
}
|
|
313
|
+
if (typeof source.linearClientId === "string") {
|
|
314
|
+
const id = source.linearClientId.trim();
|
|
315
|
+
if (id) out.linearClientId = id;
|
|
316
|
+
}
|
|
317
|
+
if (typeof source.linearClientSecret === "string") {
|
|
318
|
+
const secret = source.linearClientSecret.trim();
|
|
319
|
+
if (secret) out.linearClientSecret = secret;
|
|
320
|
+
}
|
|
321
|
+
if (typeof source.linearViewerName === "string") {
|
|
322
|
+
const name = source.linearViewerName.trim().slice(0, 120);
|
|
323
|
+
if (name) out.linearViewerName = name;
|
|
324
|
+
}
|
|
325
|
+
if (typeof source.linearOrganizationName === "string") {
|
|
326
|
+
const name = source.linearOrganizationName.trim().slice(0, 120);
|
|
327
|
+
if (name) out.linearOrganizationName = name;
|
|
328
|
+
}
|
|
91
329
|
if (typeof source.issueSource === "string" && ISSUE_SOURCES.has(source.issueSource)) {
|
|
92
330
|
out.issueSource = source.issueSource;
|
|
93
331
|
}
|
|
332
|
+
if (typeof source.slackClientId === "string") {
|
|
333
|
+
const id = source.slackClientId.trim();
|
|
334
|
+
if (id) out.slackClientId = id;
|
|
335
|
+
}
|
|
336
|
+
if (typeof source.slackClientSecret === "string") {
|
|
337
|
+
const secret = source.slackClientSecret.trim();
|
|
338
|
+
if (secret) out.slackClientSecret = secret;
|
|
339
|
+
}
|
|
340
|
+
if (typeof source.slackAppToken === "string") {
|
|
341
|
+
const token = source.slackAppToken.trim();
|
|
342
|
+
if (token) out.slackAppToken = token;
|
|
343
|
+
}
|
|
344
|
+
if (typeof source.slackListenEnabled === "boolean") {
|
|
345
|
+
out.slackListenEnabled = source.slackListenEnabled;
|
|
346
|
+
}
|
|
347
|
+
if (typeof source.slackDeviceId === "string") {
|
|
348
|
+
const id = source.slackDeviceId.trim();
|
|
349
|
+
if (id) out.slackDeviceId = id;
|
|
350
|
+
}
|
|
351
|
+
if (typeof source.slackDeviceLabel === "string") {
|
|
352
|
+
const label = source.slackDeviceLabel.trim().slice(0, 64);
|
|
353
|
+
if (label) out.slackDeviceLabel = label;
|
|
354
|
+
}
|
|
94
355
|
return out;
|
|
95
356
|
}
|
|
96
357
|
function normalizeDefaults(raw) {
|
|
@@ -125,8 +386,10 @@ function normalizeAdvanced(raw) {
|
|
|
125
386
|
if (typeof source.caffeinateWhileRunning === "boolean") {
|
|
126
387
|
out.caffeinateWhileRunning = source.caffeinateWhileRunning;
|
|
127
388
|
}
|
|
128
|
-
if (typeof source.
|
|
129
|
-
out.
|
|
389
|
+
if (typeof source.caffeinateWhileSlackListen === "boolean") {
|
|
390
|
+
out.caffeinateWhileSlackListen = source.caffeinateWhileSlackListen;
|
|
391
|
+
} else if (typeof source.caffeinateWhileCloudConnect === "boolean") {
|
|
392
|
+
out.caffeinateWhileSlackListen = source.caffeinateWhileCloudConnect;
|
|
130
393
|
}
|
|
131
394
|
if (typeof source.deleteBranchOnPurge === "boolean") {
|
|
132
395
|
out.deleteBranchOnPurge = source.deleteBranchOnPurge;
|
|
@@ -225,23 +488,84 @@ var EMPTY_SETTINGS = {
|
|
|
225
488
|
defaults: {},
|
|
226
489
|
advanced: {}
|
|
227
490
|
};
|
|
228
|
-
function
|
|
491
|
+
function readSettingsFile() {
|
|
229
492
|
const path = appSettingsPath();
|
|
230
|
-
if (!
|
|
231
|
-
return { ...EMPTY_SETTINGS };
|
|
232
|
-
}
|
|
493
|
+
if (!existsSync2(path)) return { ...EMPTY_SETTINGS };
|
|
233
494
|
try {
|
|
234
|
-
|
|
495
|
+
chmodOwnerOnly(path);
|
|
496
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
235
497
|
return normalizeSettings(parsed);
|
|
236
498
|
} catch {
|
|
237
499
|
return { ...EMPTY_SETTINGS };
|
|
238
500
|
}
|
|
239
501
|
}
|
|
502
|
+
function diskHoldsSecrets(disk) {
|
|
503
|
+
return Boolean(
|
|
504
|
+
disk.integrations.linearApiKey || disk.integrations.linearAccessToken || disk.integrations.linearRefreshToken || disk.integrations.linearClientSecret || disk.integrations.slackClientSecret || disk.integrations.slackAppToken || Object.keys(disk.environment).length > 0
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
function mergeVault(disk) {
|
|
508
|
+
const vault = loadSecretVault();
|
|
509
|
+
const environment = { ...vault.environment ?? {}, ...disk.environment };
|
|
510
|
+
const integrations = { ...disk.integrations };
|
|
511
|
+
if (vault.linearApiKey && !integrations.linearApiKey) {
|
|
512
|
+
integrations.linearApiKey = vault.linearApiKey;
|
|
513
|
+
}
|
|
514
|
+
if (vault.linearAccessToken && !integrations.linearAccessToken) {
|
|
515
|
+
integrations.linearAccessToken = vault.linearAccessToken;
|
|
516
|
+
}
|
|
517
|
+
if (vault.linearRefreshToken && !integrations.linearRefreshToken) {
|
|
518
|
+
integrations.linearRefreshToken = vault.linearRefreshToken;
|
|
519
|
+
}
|
|
520
|
+
if (vault.linearClientSecret && !integrations.linearClientSecret) {
|
|
521
|
+
integrations.linearClientSecret = vault.linearClientSecret;
|
|
522
|
+
}
|
|
523
|
+
if (vault.slackClientSecret && !integrations.slackClientSecret) {
|
|
524
|
+
integrations.slackClientSecret = vault.slackClientSecret;
|
|
525
|
+
}
|
|
526
|
+
if (vault.slackAppToken && !integrations.slackAppToken) {
|
|
527
|
+
integrations.slackAppToken = vault.slackAppToken;
|
|
528
|
+
}
|
|
529
|
+
return { ...disk, environment, integrations };
|
|
530
|
+
}
|
|
531
|
+
function persistSplit(settings) {
|
|
532
|
+
const integrations = { ...settings.integrations };
|
|
533
|
+
const linearApiKey = integrations.linearApiKey;
|
|
534
|
+
const linearAccessToken = integrations.linearAccessToken;
|
|
535
|
+
const linearRefreshToken = integrations.linearRefreshToken;
|
|
536
|
+
const linearClientSecret = integrations.linearClientSecret;
|
|
537
|
+
const slackClientSecret = integrations.slackClientSecret;
|
|
538
|
+
const slackAppToken = integrations.slackAppToken;
|
|
539
|
+
delete integrations.linearApiKey;
|
|
540
|
+
delete integrations.linearAccessToken;
|
|
541
|
+
delete integrations.linearRefreshToken;
|
|
542
|
+
delete integrations.linearClientSecret;
|
|
543
|
+
delete integrations.slackClientSecret;
|
|
544
|
+
delete integrations.slackAppToken;
|
|
545
|
+
writePrivateFile(
|
|
546
|
+
appSettingsPath(),
|
|
547
|
+
`${JSON.stringify({ ...settings, environment: {}, integrations }, null, 2)}
|
|
548
|
+
`
|
|
549
|
+
);
|
|
550
|
+
saveSecretVault({
|
|
551
|
+
linearApiKey,
|
|
552
|
+
linearAccessToken,
|
|
553
|
+
linearRefreshToken,
|
|
554
|
+
linearClientSecret,
|
|
555
|
+
slackClientSecret,
|
|
556
|
+
slackAppToken,
|
|
557
|
+
environment: settings.environment
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
function loadAppSettings() {
|
|
561
|
+
const disk = readSettingsFile();
|
|
562
|
+
const merged = mergeVault(disk);
|
|
563
|
+
if (diskHoldsSecrets(disk)) persistSplit(merged);
|
|
564
|
+
return merged;
|
|
565
|
+
}
|
|
240
566
|
function saveAppSettings(settings) {
|
|
241
567
|
const normalized = normalizeSettings(settings);
|
|
242
|
-
|
|
243
|
-
writeFileSync(appSettingsPath(), `${JSON.stringify(normalized, null, 2)}
|
|
244
|
-
`, "utf8");
|
|
568
|
+
persistSplit(normalized);
|
|
245
569
|
return normalized;
|
|
246
570
|
}
|
|
247
571
|
function updateAppEnvironment(patch) {
|
|
@@ -332,6 +656,20 @@ function updateIntegrationsSettings(patch) {
|
|
|
332
656
|
integrations.linearApiKey = patch.linearApiKey.trim();
|
|
333
657
|
}
|
|
334
658
|
}
|
|
659
|
+
if ("linearClientId" in patch) {
|
|
660
|
+
if (patch.linearClientId == null || patch.linearClientId.trim() === "") {
|
|
661
|
+
delete integrations.linearClientId;
|
|
662
|
+
} else {
|
|
663
|
+
integrations.linearClientId = patch.linearClientId.trim();
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if ("linearClientSecret" in patch) {
|
|
667
|
+
if (patch.linearClientSecret == null || patch.linearClientSecret.trim() === "") {
|
|
668
|
+
delete integrations.linearClientSecret;
|
|
669
|
+
} else {
|
|
670
|
+
integrations.linearClientSecret = patch.linearClientSecret.trim();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
335
673
|
if ("issueSource" in patch) {
|
|
336
674
|
if (patch.issueSource == null) {
|
|
337
675
|
delete integrations.issueSource;
|
|
@@ -339,6 +677,48 @@ function updateIntegrationsSettings(patch) {
|
|
|
339
677
|
integrations.issueSource = patch.issueSource;
|
|
340
678
|
}
|
|
341
679
|
}
|
|
680
|
+
if ("slackClientId" in patch) {
|
|
681
|
+
if (patch.slackClientId == null || patch.slackClientId.trim() === "") {
|
|
682
|
+
delete integrations.slackClientId;
|
|
683
|
+
} else {
|
|
684
|
+
integrations.slackClientId = patch.slackClientId.trim();
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if ("slackClientSecret" in patch) {
|
|
688
|
+
if (patch.slackClientSecret == null || patch.slackClientSecret.trim() === "") {
|
|
689
|
+
delete integrations.slackClientSecret;
|
|
690
|
+
} else {
|
|
691
|
+
integrations.slackClientSecret = patch.slackClientSecret.trim();
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
if ("slackAppToken" in patch) {
|
|
695
|
+
if (patch.slackAppToken == null || patch.slackAppToken.trim() === "") {
|
|
696
|
+
delete integrations.slackAppToken;
|
|
697
|
+
} else {
|
|
698
|
+
integrations.slackAppToken = patch.slackAppToken.trim();
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
if ("slackListenEnabled" in patch) {
|
|
702
|
+
if (patch.slackListenEnabled == null) {
|
|
703
|
+
delete integrations.slackListenEnabled;
|
|
704
|
+
} else {
|
|
705
|
+
integrations.slackListenEnabled = Boolean(patch.slackListenEnabled);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if ("slackDeviceId" in patch) {
|
|
709
|
+
if (patch.slackDeviceId == null || patch.slackDeviceId.trim() === "") {
|
|
710
|
+
delete integrations.slackDeviceId;
|
|
711
|
+
} else {
|
|
712
|
+
integrations.slackDeviceId = patch.slackDeviceId.trim();
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if ("slackDeviceLabel" in patch) {
|
|
716
|
+
if (patch.slackDeviceLabel == null || patch.slackDeviceLabel.trim() === "") {
|
|
717
|
+
delete integrations.slackDeviceLabel;
|
|
718
|
+
} else {
|
|
719
|
+
integrations.slackDeviceLabel = patch.slackDeviceLabel.trim().slice(0, 64);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
342
722
|
return saveAppSettings({ ...current, integrations });
|
|
343
723
|
}
|
|
344
724
|
function updateDefaultsSettings(patch) {
|
|
@@ -412,7 +792,36 @@ function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
|
|
|
412
792
|
};
|
|
413
793
|
}
|
|
414
794
|
function isLinearConnected(settings = loadAppSettings()) {
|
|
415
|
-
return
|
|
795
|
+
return hasLinearCredentials(settings.integrations);
|
|
796
|
+
}
|
|
797
|
+
function saveLinearOAuth(input) {
|
|
798
|
+
const current = loadAppSettings();
|
|
799
|
+
const integrations = { ...current.integrations };
|
|
800
|
+
integrations.linearAccessToken = input.accessToken.trim();
|
|
801
|
+
if (input.refreshToken?.trim()) {
|
|
802
|
+
integrations.linearRefreshToken = input.refreshToken.trim();
|
|
803
|
+
}
|
|
804
|
+
if (typeof input.expiresIn === "number" && Number.isFinite(input.expiresIn)) {
|
|
805
|
+
integrations.linearTokenExpiresAt = Date.now() + Math.max(0, input.expiresIn) * 1e3;
|
|
806
|
+
}
|
|
807
|
+
if (input.viewerName?.trim()) {
|
|
808
|
+
integrations.linearViewerName = input.viewerName.trim().slice(0, 120);
|
|
809
|
+
}
|
|
810
|
+
if (input.organizationName?.trim()) {
|
|
811
|
+
integrations.linearOrganizationName = input.organizationName.trim().slice(0, 120);
|
|
812
|
+
}
|
|
813
|
+
return saveAppSettings({ ...current, integrations });
|
|
814
|
+
}
|
|
815
|
+
function disconnectLinearConnection() {
|
|
816
|
+
const current = loadAppSettings();
|
|
817
|
+
const integrations = { ...current.integrations };
|
|
818
|
+
delete integrations.linearApiKey;
|
|
819
|
+
delete integrations.linearAccessToken;
|
|
820
|
+
delete integrations.linearRefreshToken;
|
|
821
|
+
delete integrations.linearTokenExpiresAt;
|
|
822
|
+
delete integrations.linearViewerName;
|
|
823
|
+
delete integrations.linearOrganizationName;
|
|
824
|
+
return saveAppSettings({ ...current, integrations });
|
|
416
825
|
}
|
|
417
826
|
function getIssueSource(settings = loadAppSettings()) {
|
|
418
827
|
return settings.integrations.issueSource ?? "github";
|
|
@@ -429,6 +838,33 @@ function getLinearApiKey(settings = loadAppSettings()) {
|
|
|
429
838
|
function brightsyCloudConnectEnabled(settings = loadAppSettings()) {
|
|
430
839
|
return Boolean(settings.brightsy.cloudConnectEnabled);
|
|
431
840
|
}
|
|
841
|
+
function slackListenEnabled(settings = loadAppSettings()) {
|
|
842
|
+
return settings.integrations.slackListenEnabled === true;
|
|
843
|
+
}
|
|
844
|
+
function ensureSlackDeviceIdentity(settings = loadAppSettings()) {
|
|
845
|
+
let deviceId = settings.integrations.slackDeviceId?.trim() ?? "";
|
|
846
|
+
let deviceLabel = settings.integrations.slackDeviceLabel?.trim() ?? "";
|
|
847
|
+
const patch = {};
|
|
848
|
+
if (!deviceId) {
|
|
849
|
+
deviceId = randomUUID();
|
|
850
|
+
patch.slackDeviceId = deviceId;
|
|
851
|
+
}
|
|
852
|
+
if (!deviceLabel) {
|
|
853
|
+
try {
|
|
854
|
+
deviceLabel = hostname().split(".")[0]?.trim() || "This Mac";
|
|
855
|
+
} catch {
|
|
856
|
+
deviceLabel = "This Mac";
|
|
857
|
+
}
|
|
858
|
+
patch.slackDeviceLabel = deviceLabel;
|
|
859
|
+
}
|
|
860
|
+
if (Object.keys(patch).length > 0) {
|
|
861
|
+
updateIntegrationsSettings(patch);
|
|
862
|
+
}
|
|
863
|
+
return { deviceId, deviceLabel };
|
|
864
|
+
}
|
|
865
|
+
function slackAppLevelToken(settings = loadAppSettings()) {
|
|
866
|
+
return process.env.SIDEBOARD_SLACK_APP_TOKEN?.trim() || settings.integrations.slackAppToken?.trim() || "";
|
|
867
|
+
}
|
|
432
868
|
function brightsyInjectWorktreeMcpEnabled(settings = loadAppSettings()) {
|
|
433
869
|
return Boolean(settings.brightsy.injectWorktreeMcp);
|
|
434
870
|
}
|
|
@@ -452,8 +888,12 @@ function updateAdvancedSettings(patch) {
|
|
|
452
888
|
if (typeof patch.caffeinateWhileRunning === "boolean") {
|
|
453
889
|
advanced.caffeinateWhileRunning = patch.caffeinateWhileRunning;
|
|
454
890
|
}
|
|
455
|
-
if (typeof patch.
|
|
456
|
-
advanced.
|
|
891
|
+
if (typeof patch.caffeinateWhileSlackListen === "boolean") {
|
|
892
|
+
advanced.caffeinateWhileSlackListen = patch.caffeinateWhileSlackListen;
|
|
893
|
+
delete advanced.caffeinateWhileCloudConnect;
|
|
894
|
+
} else if (typeof patch.caffeinateWhileCloudConnect === "boolean") {
|
|
895
|
+
advanced.caffeinateWhileSlackListen = patch.caffeinateWhileCloudConnect;
|
|
896
|
+
delete advanced.caffeinateWhileCloudConnect;
|
|
457
897
|
}
|
|
458
898
|
if (typeof patch.deleteBranchOnPurge === "boolean") {
|
|
459
899
|
advanced.deleteBranchOnPurge = patch.deleteBranchOnPurge;
|
|
@@ -496,8 +936,11 @@ function autoRunAfterSetupEnabled(settings = loadAppSettings()) {
|
|
|
496
936
|
function caffeinateWhileRunningEnabled(settings = loadAppSettings()) {
|
|
497
937
|
return Boolean(settings.advanced.caffeinateWhileRunning);
|
|
498
938
|
}
|
|
939
|
+
function caffeinateWhileSlackListenEnabled(settings = loadAppSettings()) {
|
|
940
|
+
return Boolean(settings.advanced.caffeinateWhileSlackListen);
|
|
941
|
+
}
|
|
499
942
|
function caffeinateWhileCloudConnectEnabled(settings = loadAppSettings()) {
|
|
500
|
-
return
|
|
943
|
+
return caffeinateWhileSlackListenEnabled(settings);
|
|
501
944
|
}
|
|
502
945
|
function deleteBranchOnPurgeEnabled(settings = loadAppSettings()) {
|
|
503
946
|
return Boolean(settings.advanced.deleteBranchOnPurge);
|
|
@@ -591,7 +1034,12 @@ function harnessEnvKey(harness) {
|
|
|
591
1034
|
}
|
|
592
1035
|
|
|
593
1036
|
export {
|
|
1037
|
+
resolveVaultKey,
|
|
1038
|
+
readSecureJson,
|
|
1039
|
+
writeSecureJson,
|
|
1040
|
+
isSecureFileEncrypted,
|
|
594
1041
|
HARNESS_ENV_KEYS,
|
|
1042
|
+
toPublicAppSettings,
|
|
595
1043
|
appSettingsPath,
|
|
596
1044
|
claudeUserSettingsPath,
|
|
597
1045
|
loadAppSettings,
|
|
@@ -610,16 +1058,22 @@ export {
|
|
|
610
1058
|
resolveThreadDefaults,
|
|
611
1059
|
resolveNewThreadOptions,
|
|
612
1060
|
isLinearConnected,
|
|
1061
|
+
saveLinearOAuth,
|
|
1062
|
+
disconnectLinearConnection,
|
|
613
1063
|
getIssueSource,
|
|
614
1064
|
resolveEffectiveIssueSource,
|
|
615
1065
|
getLinearApiKey,
|
|
616
1066
|
brightsyCloudConnectEnabled,
|
|
1067
|
+
slackListenEnabled,
|
|
1068
|
+
ensureSlackDeviceIdentity,
|
|
1069
|
+
slackAppLevelToken,
|
|
617
1070
|
brightsyInjectWorktreeMcpEnabled,
|
|
618
1071
|
brightsyCloudConnectAgent,
|
|
619
1072
|
updateAdvancedSettings,
|
|
620
1073
|
autoRenameBranchEnabled,
|
|
621
1074
|
autoRunAfterSetupEnabled,
|
|
622
1075
|
caffeinateWhileRunningEnabled,
|
|
1076
|
+
caffeinateWhileSlackListenEnabled,
|
|
623
1077
|
caffeinateWhileCloudConnectEnabled,
|
|
624
1078
|
deleteBranchOnPurgeEnabled,
|
|
625
1079
|
autoArchiveOnMergeEnabled,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isOrchestratorThread
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-57ROTAFD.js";
|
|
4
4
|
import {
|
|
5
5
|
applyConnectedTeamToCli,
|
|
6
6
|
brightsyMcpServerName,
|
|
7
7
|
ensureCliTeamTracked,
|
|
8
8
|
ensureConnectedBrightsyTeamTokens,
|
|
9
9
|
loadBrightsyConfig
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-BTL7EMGT.js";
|
|
11
11
|
import {
|
|
12
12
|
extractJsonErrorMessage,
|
|
13
13
|
formatUnknownDetail,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
loadAppSettings,
|
|
20
20
|
resolveAgentExecutable,
|
|
21
21
|
resolveClaudeExecutable
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-W7YOTDVO.js";
|
|
23
23
|
import {
|
|
24
24
|
appDataDir
|
|
25
25
|
} from "./chunk-M37RITA6.js";
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
resolveCommandBinarySync,
|
|
30
30
|
run,
|
|
31
31
|
withExportedPath
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-D4DPQ552.js";
|
|
33
33
|
|
|
34
34
|
// src/agents/brightsy.ts
|
|
35
35
|
import { existsSync } from "fs";
|
|
@@ -513,7 +513,13 @@ var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
|
|
|
513
513
|
"mcp__sideboard__present_schema",
|
|
514
514
|
"mcp__sideboard__present_files",
|
|
515
515
|
"mcp__sideboard__ask_user",
|
|
516
|
-
"mcp__sideboard__present_plan"
|
|
516
|
+
"mcp__sideboard__present_plan",
|
|
517
|
+
"mcp__sideboard__list_teams",
|
|
518
|
+
"mcp__sideboard__slack_list_channels",
|
|
519
|
+
"mcp__sideboard__slack_list_users",
|
|
520
|
+
"mcp__sideboard__slack_search",
|
|
521
|
+
"mcp__sideboard__slack_read",
|
|
522
|
+
"mcp__sideboard__slack_post"
|
|
517
523
|
];
|
|
518
524
|
var BRIGHTSY_MCP_ALLOWED_TOOLS = [
|
|
519
525
|
"mcp__brightsy",
|
|
@@ -940,7 +946,7 @@ var claudeAdapter = {
|
|
|
940
946
|
);
|
|
941
947
|
}
|
|
942
948
|
const mode = permissionMode(thread);
|
|
943
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
949
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-SVRYNJZA.js");
|
|
944
950
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
945
951
|
const injectedServers = await buildInjectedMcpServers({
|
|
946
952
|
includeSideboard: true,
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
isGlobalRepoPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DGPUAZA4.js";
|
|
6
6
|
import {
|
|
7
7
|
ensureGhPreferOrigin,
|
|
8
8
|
resolveRepoRoot
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-OE7YBB5X.js";
|
|
10
10
|
import {
|
|
11
11
|
appDataDir
|
|
12
12
|
} from "./chunk-7MV3RXSC.js";
|