@sideboard-ai/core 0.1.193 → 0.1.195
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/{abletime-UX53JTIH.js → abletime-HR6P4GJH.js} +3 -3
- package/dist/{abletime-QHKWGTBY.js → abletime-JINF5KJV.js} +3 -3
- package/dist/agents/cursor-runner.js +2 -2
- package/dist/{agents-MN4GSQTL.js → agents-OXDDPH2O.js} +16 -17
- package/dist/{agents-OK5VD25T.js → agents-WQL7SZY6.js} +6 -7
- package/dist/{app-settings-LO7UFHQ6.js → app-settings-5KHVKJKO.js} +2 -2
- package/dist/{app-settings-QYLNKRK4.js → app-settings-J775CYOO.js} +2 -2
- package/dist/{branch-prefix-EVW2KHGQ.js → branch-prefix-7DTIUJT2.js} +1 -1
- package/dist/{branch-prefix-7F37FIPX.js → branch-prefix-N3KTCRCE.js} +1 -1
- package/dist/{chunk-MQC2VA5U.js → chunk-2X6RGKLI.js} +13 -13
- package/dist/{chunk-EBPBGQ4P.js → chunk-6H2XPPPR.js} +9 -9
- package/dist/{chunk-HIX2VDRE.js → chunk-6YTI2HBG.js} +6 -8
- package/dist/{chunk-KORE4WOF.js → chunk-AH6WIBLY.js} +1 -1
- package/dist/{chunk-XPKKCFRT.js → chunk-DP4TKAMZ.js} +864 -7
- package/dist/{chunk-O4BMPY5Y.js → chunk-E37JHCO3.js} +1 -1
- package/dist/{chunk-JTWKGOFI.js → chunk-FJZWM2ON.js} +1 -1
- package/dist/{chunk-3DX2T2KR.js → chunk-GFH3QVAV.js} +188 -95
- package/dist/{chunk-EQXXGOMD.js → chunk-HAVI6AY3.js} +197 -104
- package/dist/{chunk-4OVCJPVI.js → chunk-HZTHWU6A.js} +6 -8
- package/dist/{chunk-4QJRH5DL.js → chunk-KTHRWHA3.js} +1 -1
- package/dist/{chunk-BIKCWYRP.js → chunk-S4QCBBXS.js} +873 -16
- package/dist/{chunk-BWRS6GAS.js → chunk-S5GLSRLP.js} +1 -1
- package/dist/{chunk-PE337IM2.js → chunk-SALM35KD.js} +7 -7
- package/dist/{chunk-7SNJMKD6.js → chunk-WDRMZKVB.js} +1 -1
- package/dist/{connected-teams-SYQQGCXD.js → connected-teams-WK47ATT7.js} +2 -2
- package/dist/{coordinator-prompt-WB65HIZ3.js → coordinator-prompt-IX66YUJ2.js} +5 -6
- package/dist/{coordinator-prompt-GXJIPWNA.js → coordinator-prompt-LYKS3YNG.js} +4 -5
- package/dist/{global-workspace-MMK5UFUZ.js → global-workspace-4QX6UEOY.js} +5 -6
- package/dist/{global-workspace-BZ6V6TEX.js → global-workspace-SNJ2Z6SL.js} +4 -5
- package/dist/index.cjs +1051 -971
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +95 -54
- package/dist/mcp/run-stdio.cjs +218 -140
- package/dist/mcp/run-stdio.js +67 -26
- package/dist/{orchestrator-4KI6VIFG.js → orchestrator-6ESBGMDN.js} +9 -10
- package/dist/{orchestrator-SFOT6Q6F.js → orchestrator-EHRFN3Q6.js} +8 -9
- package/dist/{workspaces-KPJS7GLY.js → workspaces-URMUVGAQ.js} +5 -6
- package/dist/{workspaces-ACMZMKPD.js → workspaces-UTOYGBYB.js} +4 -5
- package/dist/{worktree-6IEVF3GN.js → worktree-R43JOR4V.js} +12 -14
- package/dist/{worktree-UW6DNBIE.js → worktree-RM6UWNGZ.js} +17 -19
- package/package.json +1 -1
- package/dist/chunk-64QSHOKV.js +0 -869
- package/dist/chunk-ILWQT2UN.js +0 -55
- package/dist/chunk-PBEPPXMY.js +0 -57
- package/dist/chunk-RCWHL4TK.js +0 -866
- package/dist/github-DWROJOB7.js +0 -11
- package/dist/github-IIF7AQNO.js +0 -9
- package/dist/worktree-labels-3XDS6O3U.js +0 -22
- package/dist/worktree-labels-PEDOJBMD.js +0 -24
- package/dist/{chunk-7AJ7OZZF.js → chunk-NLHFAMC2.js} +3 -3
package/dist/index.cjs
CHANGED
|
@@ -975,7 +975,7 @@ function sanitizeGitBranchPrefix(raw) {
|
|
|
975
975
|
return slug || null;
|
|
976
976
|
}
|
|
977
977
|
function resolveGitBranchPrefix(opts) {
|
|
978
|
-
return sanitizeGitBranchPrefix(opts.setting)
|
|
978
|
+
return sanitizeGitBranchPrefix(opts.setting);
|
|
979
979
|
}
|
|
980
980
|
function examplePrefixedBranch(prefix, ticket) {
|
|
981
981
|
const head = sanitizeGitBranchPrefix(prefix);
|
|
@@ -2956,762 +2956,10 @@ var init_thread_store = __esm({
|
|
|
2956
2956
|
}
|
|
2957
2957
|
});
|
|
2958
2958
|
|
|
2959
|
-
// src/
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
function emptySetupLog() {
|
|
2964
|
-
return { ...EMPTY };
|
|
2965
|
-
}
|
|
2966
|
-
function mergeSetupOutput(prev, incoming) {
|
|
2967
|
-
if (!prev) return incoming;
|
|
2968
|
-
if (!incoming) return prev;
|
|
2969
|
-
if (prev === incoming) return prev;
|
|
2970
|
-
if (prev.startsWith(incoming) || prev.endsWith(incoming)) return prev;
|
|
2971
|
-
if (incoming.startsWith(prev) || incoming.endsWith(prev)) return incoming;
|
|
2972
|
-
return incoming.length >= prev.length ? incoming : prev;
|
|
2973
|
-
}
|
|
2974
|
-
function clone(snap) {
|
|
2975
|
-
return { ...snap };
|
|
2976
|
-
}
|
|
2977
|
-
function persistNow(threadId) {
|
|
2978
|
-
const timer = persistTimers.get(threadId);
|
|
2979
|
-
if (timer) {
|
|
2980
|
-
clearTimeout(timer);
|
|
2981
|
-
persistTimers.delete(threadId);
|
|
2982
|
-
}
|
|
2983
|
-
const snap = memory.get(threadId);
|
|
2984
|
-
if (!snap) return;
|
|
2985
|
-
try {
|
|
2986
|
-
(0, import_node_fs10.writeFileSync)(setupLogPath(threadId), `${JSON.stringify(snap)}
|
|
2987
|
-
`, "utf8");
|
|
2988
|
-
} catch {
|
|
2989
|
-
}
|
|
2990
|
-
}
|
|
2991
|
-
function schedulePersist(threadId) {
|
|
2992
|
-
if (persistTimers.has(threadId)) return;
|
|
2993
|
-
persistTimers.set(
|
|
2994
|
-
threadId,
|
|
2995
|
-
setTimeout(() => {
|
|
2996
|
-
persistTimers.delete(threadId);
|
|
2997
|
-
persistNow(threadId);
|
|
2998
|
-
}, 100)
|
|
2999
|
-
);
|
|
3000
|
-
}
|
|
3001
|
-
function loadFromDisk(threadId) {
|
|
3002
|
-
const path2 = setupLogPath(threadId);
|
|
3003
|
-
if (!(0, import_node_fs10.existsSync)(path2)) return null;
|
|
3004
|
-
try {
|
|
3005
|
-
const raw = JSON.parse((0, import_node_fs10.readFileSync)(path2, "utf8"));
|
|
3006
|
-
return {
|
|
3007
|
-
output: typeof raw.output === "string" ? raw.output : "",
|
|
3008
|
-
running: Boolean(raw.running),
|
|
3009
|
-
exitCode: typeof raw.exitCode === "number" ? raw.exitCode : null,
|
|
3010
|
-
source: typeof raw.source === "string" ? raw.source : null
|
|
3011
|
-
};
|
|
3012
|
-
} catch {
|
|
3013
|
-
return null;
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
function readSetupLog(threadId) {
|
|
3017
|
-
const cached = memory.get(threadId);
|
|
3018
|
-
if (cached) return clone(cached);
|
|
3019
|
-
const disk = loadFromDisk(threadId);
|
|
3020
|
-
if (disk) {
|
|
3021
|
-
memory.set(threadId, disk);
|
|
3022
|
-
return clone(disk);
|
|
3023
|
-
}
|
|
3024
|
-
return emptySetupLog();
|
|
3025
|
-
}
|
|
3026
|
-
function beginSetupLog(threadId) {
|
|
3027
|
-
const snap = {
|
|
3028
|
-
output: "",
|
|
3029
|
-
running: true,
|
|
3030
|
-
exitCode: null,
|
|
3031
|
-
source: null
|
|
3032
|
-
};
|
|
3033
|
-
memory.set(threadId, snap);
|
|
3034
|
-
persistNow(threadId);
|
|
3035
|
-
return clone(snap);
|
|
3036
|
-
}
|
|
3037
|
-
function appendSetupLog(threadId, line) {
|
|
3038
|
-
const current = memory.get(threadId) ?? readSetupLog(threadId);
|
|
3039
|
-
const snap = {
|
|
3040
|
-
...current,
|
|
3041
|
-
output: current.output ? `${current.output}
|
|
3042
|
-
${line}` : line,
|
|
3043
|
-
running: true
|
|
3044
|
-
};
|
|
3045
|
-
memory.set(threadId, snap);
|
|
3046
|
-
schedulePersist(threadId);
|
|
3047
|
-
return clone(snap);
|
|
3048
|
-
}
|
|
3049
|
-
function finishSetupLog(threadId, exitCode, source) {
|
|
3050
|
-
const current = memory.get(threadId) ?? readSetupLog(threadId);
|
|
3051
|
-
const snap = {
|
|
3052
|
-
...current,
|
|
3053
|
-
running: false,
|
|
3054
|
-
exitCode,
|
|
3055
|
-
source: source ?? current.source
|
|
3056
|
-
};
|
|
3057
|
-
memory.set(threadId, snap);
|
|
3058
|
-
persistNow(threadId);
|
|
3059
|
-
return clone(snap);
|
|
3060
|
-
}
|
|
3061
|
-
var import_node_fs10, import_node_path11, EMPTY, memory, persistTimers;
|
|
3062
|
-
var init_setup_log = __esm({
|
|
3063
|
-
"src/store/setup-log.ts"() {
|
|
3064
|
-
"use strict";
|
|
3065
|
-
import_node_fs10 = require("fs");
|
|
3066
|
-
import_node_path11 = require("path");
|
|
3067
|
-
init_paths();
|
|
3068
|
-
EMPTY = {
|
|
3069
|
-
output: "",
|
|
3070
|
-
running: false,
|
|
3071
|
-
exitCode: null,
|
|
3072
|
-
source: null
|
|
3073
|
-
};
|
|
3074
|
-
memory = /* @__PURE__ */ new Map();
|
|
3075
|
-
persistTimers = /* @__PURE__ */ new Map();
|
|
3076
|
-
}
|
|
3077
|
-
});
|
|
3078
|
-
|
|
3079
|
-
// src/store/schedules.ts
|
|
3080
|
-
function schedulesPath() {
|
|
3081
|
-
return (0, import_node_path12.join)(appDataDir(), "schedules.json");
|
|
3082
|
-
}
|
|
3083
|
-
function parseDurationMs(every) {
|
|
3084
|
-
const m = every.trim().match(DURATION_RE);
|
|
3085
|
-
if (!m) return null;
|
|
3086
|
-
const n = Number.parseInt(m[1], 10);
|
|
3087
|
-
if (!Number.isFinite(n) || n <= 0) return null;
|
|
3088
|
-
const unit = m[2].toLowerCase();
|
|
3089
|
-
return n * UNIT_MS[unit];
|
|
3090
|
-
}
|
|
3091
|
-
function defaultScheduleName(prompt) {
|
|
3092
|
-
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
3093
|
-
if (!line) return "Untitled schedule";
|
|
3094
|
-
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
3095
|
-
}
|
|
3096
|
-
function resolveScheduleThreadId(raw, env = process.env) {
|
|
3097
|
-
const value = raw?.trim() || "";
|
|
3098
|
-
if (!value) return null;
|
|
3099
|
-
if (value.toLowerCase() === "self") {
|
|
3100
|
-
return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
|
|
3101
|
-
}
|
|
3102
|
-
return value;
|
|
3103
|
-
}
|
|
3104
|
-
function computeNextRunAt(when, from = /* @__PURE__ */ new Date()) {
|
|
3105
|
-
if (when.kind === "once") {
|
|
3106
|
-
const at = new Date(when.at);
|
|
3107
|
-
if (Number.isNaN(at.getTime())) {
|
|
3108
|
-
throw new Error(`Invalid once-at datetime: ${when.at}`);
|
|
3109
|
-
}
|
|
3110
|
-
return at;
|
|
3111
|
-
}
|
|
3112
|
-
if (when.kind === "every") {
|
|
3113
|
-
const ms = parseDurationMs(when.every);
|
|
3114
|
-
if (!ms) {
|
|
3115
|
-
throw new Error(`Invalid interval: ${when.every} (use 15m, 1h, 6h, 1d)`);
|
|
3116
|
-
}
|
|
3117
|
-
return new Date(from.getTime() + ms);
|
|
3118
|
-
}
|
|
3119
|
-
try {
|
|
3120
|
-
const job = new import_croner.Cron(when.expr, {
|
|
3121
|
-
timezone: when.tz?.trim() || void 0,
|
|
3122
|
-
paused: true
|
|
3123
|
-
});
|
|
3124
|
-
const next = job.nextRun(from);
|
|
3125
|
-
if (!next) {
|
|
3126
|
-
throw new Error(`Cron expression has no next run: ${when.expr}`);
|
|
3127
|
-
}
|
|
3128
|
-
return next;
|
|
3129
|
-
} catch (err) {
|
|
3130
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
3131
|
-
throw new Error(`Invalid cron: ${message}`);
|
|
3132
|
-
}
|
|
3133
|
-
}
|
|
3134
|
-
function formatScheduleWhen(when) {
|
|
3135
|
-
if (when.kind === "once") return `once at ${when.at}`;
|
|
3136
|
-
if (when.kind === "every") return `every ${when.every}`;
|
|
3137
|
-
const tz = when.tz?.trim();
|
|
3138
|
-
return tz ? `cron ${when.expr} (${tz})` : `cron ${when.expr}`;
|
|
3139
|
-
}
|
|
3140
|
-
function nowIso2(d = /* @__PURE__ */ new Date()) {
|
|
3141
|
-
return d.toISOString();
|
|
3142
|
-
}
|
|
3143
|
-
function normalizeWhen(raw) {
|
|
3144
|
-
if (!raw || typeof raw !== "object") {
|
|
3145
|
-
throw new Error("Schedule is missing `when`");
|
|
3146
|
-
}
|
|
3147
|
-
const rec = raw;
|
|
3148
|
-
const kind = rec.kind;
|
|
3149
|
-
if (kind === "once" && typeof rec.at === "string") {
|
|
3150
|
-
return { kind: "once", at: rec.at };
|
|
3151
|
-
}
|
|
3152
|
-
if (kind === "every" && typeof rec.every === "string") {
|
|
3153
|
-
return { kind: "every", every: rec.every };
|
|
3154
|
-
}
|
|
3155
|
-
if (kind === "cron" && typeof rec.expr === "string") {
|
|
3156
|
-
return {
|
|
3157
|
-
kind: "cron",
|
|
3158
|
-
expr: rec.expr,
|
|
3159
|
-
tz: typeof rec.tz === "string" && rec.tz.trim() ? rec.tz.trim() : void 0
|
|
3160
|
-
};
|
|
3161
|
-
}
|
|
3162
|
-
throw new Error("Schedule `when` must be once, every, or cron");
|
|
3163
|
-
}
|
|
3164
|
-
function normalizeTask(raw) {
|
|
3165
|
-
const when = normalizeWhen(raw.when);
|
|
3166
|
-
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
3167
|
-
return {
|
|
3168
|
-
id: raw.id,
|
|
3169
|
-
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : defaultScheduleName(raw.prompt),
|
|
3170
|
-
prompt: String(raw.prompt ?? ""),
|
|
3171
|
-
enabled: Boolean(raw.enabled),
|
|
3172
|
-
when,
|
|
3173
|
-
threadId: raw.threadId?.trim() || null,
|
|
3174
|
-
agent,
|
|
3175
|
-
model: raw.model?.trim() || null,
|
|
3176
|
-
nextRunAt: raw.nextRunAt,
|
|
3177
|
-
lastRunAt: raw.lastRunAt ?? null,
|
|
3178
|
-
lastThreadId: raw.lastThreadId ?? null,
|
|
3179
|
-
lastError: raw.lastError ?? null,
|
|
3180
|
-
createdBy: raw.createdBy === "mcp" || raw.createdBy === "cli" || raw.createdBy === "ui" ? raw.createdBy : "ui",
|
|
3181
|
-
createdAt: raw.createdAt,
|
|
3182
|
-
updatedAt: raw.updatedAt
|
|
3183
|
-
};
|
|
3184
|
-
}
|
|
3185
|
-
function readAll() {
|
|
3186
|
-
const path2 = schedulesPath();
|
|
3187
|
-
if (!(0, import_node_fs11.existsSync)(path2)) return [];
|
|
3188
|
-
try {
|
|
3189
|
-
const parsed = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
|
|
3190
|
-
if (!Array.isArray(parsed)) return [];
|
|
3191
|
-
return parsed.map((row) => {
|
|
3192
|
-
try {
|
|
3193
|
-
return normalizeTask(row);
|
|
3194
|
-
} catch {
|
|
3195
|
-
return null;
|
|
3196
|
-
}
|
|
3197
|
-
}).filter((row) => Boolean(row?.id && row.prompt));
|
|
3198
|
-
} catch {
|
|
3199
|
-
return [];
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
function writeAll(rows) {
|
|
3203
|
-
writePrivateFile(schedulesPath(), `${JSON.stringify(rows, null, 2)}
|
|
3204
|
-
`);
|
|
3205
|
-
}
|
|
3206
|
-
function buildTask(input, now) {
|
|
3207
|
-
const prompt = input.prompt.trim();
|
|
3208
|
-
if (!prompt) throw new Error("Schedule prompt is required");
|
|
3209
|
-
const when = normalizeWhen(input.when);
|
|
3210
|
-
const nextRunAt = computeNextRunAt(when, now).toISOString();
|
|
3211
|
-
const ts = nowIso2(now);
|
|
3212
|
-
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
3213
|
-
return {
|
|
3214
|
-
id: (0, import_node_crypto4.randomUUID)(),
|
|
3215
|
-
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
3216
|
-
prompt,
|
|
3217
|
-
enabled: input.enabled !== false,
|
|
3218
|
-
when,
|
|
3219
|
-
threadId: input.threadId?.trim() || null,
|
|
3220
|
-
agent,
|
|
3221
|
-
model: input.model?.trim() || null,
|
|
3222
|
-
nextRunAt,
|
|
3223
|
-
lastRunAt: null,
|
|
3224
|
-
lastThreadId: null,
|
|
3225
|
-
lastError: null,
|
|
3226
|
-
createdBy: input.createdBy,
|
|
3227
|
-
createdAt: ts,
|
|
3228
|
-
updatedAt: ts
|
|
3229
|
-
};
|
|
3230
|
-
}
|
|
3231
|
-
function listSchedules() {
|
|
3232
|
-
return readAll().sort((a, b) => a.nextRunAt.localeCompare(b.nextRunAt));
|
|
3233
|
-
}
|
|
3234
|
-
function hasEnabledSchedules() {
|
|
3235
|
-
return listSchedules().some((row) => row.enabled);
|
|
3236
|
-
}
|
|
3237
|
-
function getSchedule(id) {
|
|
3238
|
-
const key = id.trim();
|
|
3239
|
-
if (!key) return null;
|
|
3240
|
-
return readAll().find(
|
|
3241
|
-
(row) => row.id === key || row.id.startsWith(key) && key.length >= 8
|
|
3242
|
-
) ?? null;
|
|
3243
|
-
}
|
|
3244
|
-
function createSchedule(input) {
|
|
3245
|
-
const task = buildTask(input, /* @__PURE__ */ new Date());
|
|
3246
|
-
const rows = readAll();
|
|
3247
|
-
rows.push(task);
|
|
3248
|
-
writeAll(rows);
|
|
3249
|
-
return task;
|
|
3250
|
-
}
|
|
3251
|
-
function updateSchedule(id, patch) {
|
|
3252
|
-
const rows = readAll();
|
|
3253
|
-
const idx = rows.findIndex((row) => row.id === id || id.length >= 8 && row.id.startsWith(id));
|
|
3254
|
-
if (idx < 0) throw new Error(`Schedule not found: ${id}`);
|
|
3255
|
-
const prev = rows[idx];
|
|
3256
|
-
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
3257
|
-
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
3258
|
-
if (!prompt) throw new Error("Schedule prompt is required");
|
|
3259
|
-
const whenChanged = patch.when !== void 0;
|
|
3260
|
-
const next = {
|
|
3261
|
-
...prev,
|
|
3262
|
-
name: patch.name !== void 0 ? patch.name.trim() || defaultScheduleName(prompt) : prev.name,
|
|
3263
|
-
prompt,
|
|
3264
|
-
enabled: patch.enabled ?? prev.enabled,
|
|
3265
|
-
when,
|
|
3266
|
-
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
3267
|
-
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
3268
|
-
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
3269
|
-
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
3270
|
-
lastError: whenChanged ? null : prev.lastError,
|
|
3271
|
-
updatedAt: nowIso2()
|
|
3272
|
-
};
|
|
3273
|
-
rows[idx] = next;
|
|
3274
|
-
writeAll(rows);
|
|
3275
|
-
return next;
|
|
3276
|
-
}
|
|
3277
|
-
function deleteSchedule(id) {
|
|
3278
|
-
const rows = readAll();
|
|
3279
|
-
const next = rows.filter(
|
|
3280
|
-
(row) => row.id !== id && !(id.length >= 8 && row.id.startsWith(id))
|
|
3281
|
-
);
|
|
3282
|
-
if (next.length === rows.length) throw new Error(`Schedule not found: ${id}`);
|
|
3283
|
-
writeAll(next);
|
|
3284
|
-
}
|
|
3285
|
-
function recordScheduleRun(id, result) {
|
|
3286
|
-
const rows = readAll();
|
|
3287
|
-
const idx = rows.findIndex((row) => row.id === id);
|
|
3288
|
-
if (idx < 0) throw new Error(`Schedule not found: ${id}`);
|
|
3289
|
-
const prev = rows[idx];
|
|
3290
|
-
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
3291
|
-
const next = {
|
|
3292
|
-
...prev,
|
|
3293
|
-
enabled: prev.when.kind === "once" ? false : prev.enabled,
|
|
3294
|
-
nextRunAt: prev.when.kind === "once" ? prev.nextRunAt : computeNextRunAt(prev.when, firedAt).toISOString(),
|
|
3295
|
-
lastRunAt: nowIso2(firedAt),
|
|
3296
|
-
lastThreadId: result.lastThreadId !== void 0 ? result.lastThreadId : prev.lastThreadId,
|
|
3297
|
-
lastError: result.lastError ?? null,
|
|
3298
|
-
updatedAt: nowIso2(firedAt)
|
|
3299
|
-
};
|
|
3300
|
-
rows[idx] = next;
|
|
3301
|
-
writeAll(rows);
|
|
3302
|
-
return next;
|
|
3303
|
-
}
|
|
3304
|
-
var import_node_crypto4, import_node_fs11, import_node_path12, import_croner, DURATION_RE, UNIT_MS;
|
|
3305
|
-
var init_schedules = __esm({
|
|
3306
|
-
"src/store/schedules.ts"() {
|
|
3307
|
-
"use strict";
|
|
3308
|
-
import_node_crypto4 = require("crypto");
|
|
3309
|
-
import_node_fs11 = require("fs");
|
|
3310
|
-
import_node_path12 = require("path");
|
|
3311
|
-
import_croner = require("croner");
|
|
3312
|
-
init_orchestrator_capable();
|
|
3313
|
-
init_paths();
|
|
3314
|
-
init_private_file();
|
|
3315
|
-
DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
3316
|
-
UNIT_MS = {
|
|
3317
|
-
s: 1e3,
|
|
3318
|
-
m: 6e4,
|
|
3319
|
-
h: 36e5,
|
|
3320
|
-
d: 864e5
|
|
3321
|
-
};
|
|
3322
|
-
}
|
|
3323
|
-
});
|
|
3324
|
-
|
|
3325
|
-
// src/store/desktop-host.ts
|
|
3326
|
-
function desktopHostPidPath() {
|
|
3327
|
-
return (0, import_node_path13.join)(appDataDir(), "desktop-host.pid");
|
|
3328
|
-
}
|
|
3329
|
-
function claimDesktopHost(pid = process.pid) {
|
|
3330
|
-
(0, import_node_fs12.writeFileSync)(desktopHostPidPath(), `${pid}
|
|
3331
|
-
`, "utf8");
|
|
3332
|
-
}
|
|
3333
|
-
function releaseDesktopHost(pid = process.pid) {
|
|
3334
|
-
if (readDesktopHostPid() !== pid) return;
|
|
3335
|
-
try {
|
|
3336
|
-
(0, import_node_fs12.unlinkSync)(desktopHostPidPath());
|
|
3337
|
-
} catch {
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
function readDesktopHostPid() {
|
|
3341
|
-
try {
|
|
3342
|
-
const pid = Number.parseInt((0, import_node_fs12.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
|
|
3343
|
-
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
3344
|
-
return pid;
|
|
3345
|
-
} catch {
|
|
3346
|
-
return null;
|
|
3347
|
-
}
|
|
3348
|
-
}
|
|
3349
|
-
function pidAlive(pid) {
|
|
3350
|
-
try {
|
|
3351
|
-
process.kill(pid, 0);
|
|
3352
|
-
return true;
|
|
3353
|
-
} catch {
|
|
3354
|
-
return false;
|
|
3355
|
-
}
|
|
3356
|
-
}
|
|
3357
|
-
function isDesktopHostAlive() {
|
|
3358
|
-
const pid = readDesktopHostPid();
|
|
3359
|
-
return pid != null && pidAlive(pid);
|
|
3360
|
-
}
|
|
3361
|
-
function isThisProcessDesktopHost() {
|
|
3362
|
-
return readDesktopHostPid() === process.pid && pidAlive(process.pid);
|
|
3363
|
-
}
|
|
3364
|
-
function thisProcessShouldDrainAgentQueues() {
|
|
3365
|
-
if (isThisProcessDesktopHost()) return true;
|
|
3366
|
-
return !isDesktopHostAlive();
|
|
3367
|
-
}
|
|
3368
|
-
var import_node_fs12, import_node_path13;
|
|
3369
|
-
var init_desktop_host = __esm({
|
|
3370
|
-
"src/store/desktop-host.ts"() {
|
|
3371
|
-
"use strict";
|
|
3372
|
-
import_node_fs12 = require("fs");
|
|
3373
|
-
import_node_path13 = require("path");
|
|
3374
|
-
init_paths();
|
|
3375
|
-
}
|
|
3376
|
-
});
|
|
3377
|
-
|
|
3378
|
-
// src/brightsy/cloud-connect-constants.ts
|
|
3379
|
-
function parseForceStopMessage(message) {
|
|
3380
|
-
const normalized = message.replace(/\r\n/g, "\n");
|
|
3381
|
-
const nl = normalized.indexOf("\n");
|
|
3382
|
-
const firstLine = (nl === -1 ? normalized : normalized.slice(0, nl)).trim();
|
|
3383
|
-
const remainder = (nl === -1 ? "" : normalized.slice(nl + 1)).trim();
|
|
3384
|
-
const forceStop = firstLine.toLowerCase() === SIDEBOARD_FORCE_STOP.toLowerCase();
|
|
3385
|
-
return { forceStop, remainder: forceStop ? remainder : message };
|
|
3386
|
-
}
|
|
3387
|
-
var CLOUD_ORCHESTRATOR_GOAL, SIDEBOARD_FORCE_STOP, CLOUD_COORDINATOR_BUSY_REPLY, CLOUD_COORDINATOR_STOPPED_REPLY, CLOUD_COORDINATOR_TIMEOUT_REPLY;
|
|
3388
|
-
var init_cloud_connect_constants = __esm({
|
|
3389
|
-
"src/brightsy/cloud-connect-constants.ts"() {
|
|
3390
|
-
"use strict";
|
|
3391
|
-
CLOUD_ORCHESTRATOR_GOAL = "Cloud-connected Sideboard orchestrator";
|
|
3392
|
-
SIDEBOARD_FORCE_STOP = "SIDEBOARD_FORCE_STOP";
|
|
3393
|
-
CLOUD_COORDINATOR_BUSY_REPLY = [
|
|
3394
|
-
"Sideboard is busy with an in-progress client/desktop tool turn on the global coordinator.",
|
|
3395
|
-
"I did not start a new orchestration turn.",
|
|
3396
|
-
`To force-stop the in-progress turn, send another desktop request whose first line is exactly ${SIDEBOARD_FORCE_STOP}`,
|
|
3397
|
-
"(optional follow-up request on later lines).",
|
|
3398
|
-
"What do you want me to do? (retry later, wait until idle, force-stop, rephrase, or cancel)"
|
|
3399
|
-
].join(" ");
|
|
3400
|
-
CLOUD_COORDINATOR_STOPPED_REPLY = [
|
|
3401
|
-
"Sideboard force-stopped the in-progress global coordinator turn.",
|
|
3402
|
-
"No new orchestration request was started."
|
|
3403
|
-
].join(" ");
|
|
3404
|
-
CLOUD_COORDINATOR_TIMEOUT_REPLY = [
|
|
3405
|
-
"Sideboard global coordinator timed out waiting for the local agent turn to finish.",
|
|
3406
|
-
"I did not produce a full orchestration result.",
|
|
3407
|
-
`To force-stop the in-progress turn, send another desktop request whose first line is exactly ${SIDEBOARD_FORCE_STOP}`,
|
|
3408
|
-
"(optional follow-up request on later lines).",
|
|
3409
|
-
"What do you want me to do? (retry later, wait, force-stop, rephrase, or cancel)"
|
|
3410
|
-
].join(" ");
|
|
3411
|
-
}
|
|
3412
|
-
});
|
|
3413
|
-
|
|
3414
|
-
// src/paths/workspace-scratch.ts
|
|
3415
|
-
function attachmentsGitignoreBody() {
|
|
3416
|
-
return ATTACHMENTS_GITIGNORE;
|
|
3417
|
-
}
|
|
3418
|
-
function isWorkspaceScratchPath(relativePath) {
|
|
3419
|
-
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
3420
|
-
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === CLI_DIR || p.startsWith(`${CLI_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
|
|
3421
|
-
}
|
|
3422
|
-
var ATTACHMENTS_DIR, CLI_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
|
|
3423
|
-
var init_workspace_scratch = __esm({
|
|
3424
|
-
"src/paths/workspace-scratch.ts"() {
|
|
3425
|
-
"use strict";
|
|
3426
|
-
ATTACHMENTS_DIR = ".context/attachments";
|
|
3427
|
-
CLI_DIR = ".context/cli";
|
|
3428
|
-
DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
|
|
3429
|
-
LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
3430
|
-
LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
|
|
3431
|
-
ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
|
|
3432
|
-
*
|
|
3433
|
-
!.gitignore
|
|
3434
|
-
`;
|
|
3435
|
-
}
|
|
3436
|
-
});
|
|
3437
|
-
|
|
3438
|
-
// src/composer/stage-files.ts
|
|
3439
|
-
function fileExtension(filePath) {
|
|
3440
|
-
const base = (0, import_node_path14.basename)(filePath).toLowerCase();
|
|
3441
|
-
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
3442
|
-
}
|
|
3443
|
-
function isImageFilePath(filePath) {
|
|
3444
|
-
return IMAGE_EXTENSIONS.has(fileExtension(filePath));
|
|
3445
|
-
}
|
|
3446
|
-
function imageMimeType(filePath) {
|
|
3447
|
-
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
3448
|
-
}
|
|
3449
|
-
function ensureAttachmentsDir(worktreePath) {
|
|
3450
|
-
const dir = (0, import_node_path14.join)(worktreePath, ATTACHMENTS_DIR);
|
|
3451
|
-
(0, import_node_fs13.mkdirSync)(dir, { recursive: true });
|
|
3452
|
-
const gi = (0, import_node_path14.join)(dir, ".gitignore");
|
|
3453
|
-
if (!(0, import_node_fs13.existsSync)(gi)) {
|
|
3454
|
-
(0, import_node_fs13.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
3455
|
-
}
|
|
3456
|
-
return dir;
|
|
3457
|
-
}
|
|
3458
|
-
function uniqueAttachmentName(dir, originalName) {
|
|
3459
|
-
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
3460
|
-
if (!(0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, safe))) return safe;
|
|
3461
|
-
const ext = (0, import_node_path14.extname)(safe);
|
|
3462
|
-
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
3463
|
-
for (let i = 1; i < 1e4; i++) {
|
|
3464
|
-
const candidate = `${stem}-${i}${ext}`;
|
|
3465
|
-
if (!(0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, candidate))) return candidate;
|
|
3466
|
-
}
|
|
3467
|
-
return `${stem}-${(0, import_node_crypto5.randomUUID)()}${ext}`;
|
|
3468
|
-
}
|
|
3469
|
-
function previewDataUrlFromBuf(filePath, buf) {
|
|
3470
|
-
if (!isImageFilePath(filePath)) return void 0;
|
|
3471
|
-
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
3472
|
-
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
3473
|
-
}
|
|
3474
|
-
function attachmentFromBuffer(name, buf, opts) {
|
|
3475
|
-
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
3476
|
-
if (isImageFilePath(name)) {
|
|
3477
|
-
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
3478
|
-
return {
|
|
3479
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3480
|
-
name,
|
|
3481
|
-
kind: "file",
|
|
3482
|
-
path: opts.path,
|
|
3483
|
-
previewDataUrl,
|
|
3484
|
-
content: [
|
|
3485
|
-
`Image attached: ${pathHint}`,
|
|
3486
|
-
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
3487
|
-
].join("\n")
|
|
3488
|
-
};
|
|
3489
|
-
}
|
|
3490
|
-
if (buf.length > MAX_INLINE_BYTES) {
|
|
3491
|
-
return {
|
|
3492
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3493
|
-
name,
|
|
3494
|
-
kind: "file",
|
|
3495
|
-
path: opts.path,
|
|
3496
|
-
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
3497
|
-
};
|
|
3498
|
-
}
|
|
3499
|
-
if (buf.includes(0)) {
|
|
3500
|
-
return {
|
|
3501
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3502
|
-
name,
|
|
3503
|
-
kind: "file",
|
|
3504
|
-
path: opts.path,
|
|
3505
|
-
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
3506
|
-
};
|
|
3507
|
-
}
|
|
3508
|
-
return {
|
|
3509
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3510
|
-
name,
|
|
3511
|
-
kind: "file",
|
|
3512
|
-
path: opts.path,
|
|
3513
|
-
content: buf.toString("utf8")
|
|
3514
|
-
};
|
|
3515
|
-
}
|
|
3516
|
-
function attachmentFromAbsolutePath(absolutePath) {
|
|
3517
|
-
const name = (0, import_node_path14.basename)(absolutePath);
|
|
3518
|
-
try {
|
|
3519
|
-
const st = (0, import_node_fs13.statSync)(absolutePath);
|
|
3520
|
-
if (!st.isFile()) {
|
|
3521
|
-
return {
|
|
3522
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3523
|
-
name,
|
|
3524
|
-
kind: "file",
|
|
3525
|
-
content: `(not a file: ${absolutePath})`
|
|
3526
|
-
};
|
|
3527
|
-
}
|
|
3528
|
-
const buf = (0, import_node_fs13.readFileSync)(absolutePath);
|
|
3529
|
-
return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
|
|
3530
|
-
} catch (err) {
|
|
3531
|
-
return {
|
|
3532
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3533
|
-
name,
|
|
3534
|
-
kind: "file",
|
|
3535
|
-
content: `(could not read ${absolutePath}: ${err instanceof Error ? err.message : String(err)})`
|
|
3536
|
-
};
|
|
3537
|
-
}
|
|
3538
|
-
}
|
|
3539
|
-
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
3540
|
-
if (absolutePaths.length === 0) return [];
|
|
3541
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
3542
|
-
const out = [];
|
|
3543
|
-
for (const abs of absolutePaths) {
|
|
3544
|
-
const originalName = (0, import_node_path14.basename)(abs);
|
|
3545
|
-
try {
|
|
3546
|
-
const st = (0, import_node_fs13.statSync)(abs);
|
|
3547
|
-
if (!st.isFile()) continue;
|
|
3548
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
3549
|
-
const destAbs = (0, import_node_path14.join)(dir, name);
|
|
3550
|
-
(0, import_node_fs13.copyFileSync)(abs, destAbs);
|
|
3551
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
3552
|
-
const buf = (0, import_node_fs13.readFileSync)(destAbs);
|
|
3553
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
3554
|
-
} catch (err) {
|
|
3555
|
-
out.push({
|
|
3556
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3557
|
-
name: originalName,
|
|
3558
|
-
kind: "file",
|
|
3559
|
-
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
3560
|
-
});
|
|
3561
|
-
}
|
|
3562
|
-
}
|
|
3563
|
-
return out;
|
|
3564
|
-
}
|
|
3565
|
-
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
3566
|
-
if (buffers2.length === 0) return [];
|
|
3567
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
3568
|
-
const out = [];
|
|
3569
|
-
for (const item of buffers2) {
|
|
3570
|
-
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
3571
|
-
try {
|
|
3572
|
-
const buf = Buffer.from(item.dataBase64, "base64");
|
|
3573
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
3574
|
-
const destAbs = (0, import_node_path14.join)(dir, name);
|
|
3575
|
-
(0, import_node_fs13.writeFileSync)(destAbs, buf);
|
|
3576
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
3577
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
3578
|
-
} catch (err) {
|
|
3579
|
-
out.push({
|
|
3580
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3581
|
-
name: originalName,
|
|
3582
|
-
kind: "file",
|
|
3583
|
-
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
3584
|
-
});
|
|
3585
|
-
}
|
|
3586
|
-
}
|
|
3587
|
-
return out;
|
|
3588
|
-
}
|
|
3589
|
-
function attachmentsFromBuffers(buffers2) {
|
|
3590
|
-
return buffers2.map((item) => {
|
|
3591
|
-
const name = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
3592
|
-
try {
|
|
3593
|
-
const buf = Buffer.from(item.dataBase64, "base64");
|
|
3594
|
-
return attachmentFromBuffer(name, buf, { sourceLabel: name });
|
|
3595
|
-
} catch (err) {
|
|
3596
|
-
return {
|
|
3597
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3598
|
-
name,
|
|
3599
|
-
kind: "file",
|
|
3600
|
-
content: `(could not attach ${name}: ${err instanceof Error ? err.message : String(err)})`
|
|
3601
|
-
};
|
|
3602
|
-
}
|
|
3603
|
-
});
|
|
3604
|
-
}
|
|
3605
|
-
function isWorktreeRelativePath(p) {
|
|
3606
|
-
if (!p || p.includes("..")) return false;
|
|
3607
|
-
if (p.startsWith("/")) return false;
|
|
3608
|
-
if (/^[A-Za-z]:[\\/]/.test(p)) return false;
|
|
3609
|
-
return true;
|
|
3610
|
-
}
|
|
3611
|
-
function dataUrlToBase64(url) {
|
|
3612
|
-
if (!url) return null;
|
|
3613
|
-
const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
|
|
3614
|
-
return m?.[1] ?? null;
|
|
3615
|
-
}
|
|
3616
|
-
function persistPendingFileAttachments(worktreePath, attachments) {
|
|
3617
|
-
if (attachments.length === 0) return attachments;
|
|
3618
|
-
const keep = [];
|
|
3619
|
-
const buffers2 = [];
|
|
3620
|
-
for (const att of attachments) {
|
|
3621
|
-
if (att.kind !== "file") {
|
|
3622
|
-
keep.push(att);
|
|
3623
|
-
continue;
|
|
3624
|
-
}
|
|
3625
|
-
if (att.path && isWorktreeRelativePath(att.path)) {
|
|
3626
|
-
keep.push(att);
|
|
3627
|
-
continue;
|
|
3628
|
-
}
|
|
3629
|
-
const fromPreview = dataUrlToBase64(att.previewDataUrl);
|
|
3630
|
-
if (fromPreview) {
|
|
3631
|
-
buffers2.push({ name: att.name, dataBase64: fromPreview });
|
|
3632
|
-
continue;
|
|
3633
|
-
}
|
|
3634
|
-
if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
|
|
3635
|
-
buffers2.push({
|
|
3636
|
-
name: att.name,
|
|
3637
|
-
dataBase64: Buffer.from(att.content, "utf8").toString("base64")
|
|
3638
|
-
});
|
|
3639
|
-
continue;
|
|
3640
|
-
}
|
|
3641
|
-
keep.push(att);
|
|
3642
|
-
}
|
|
3643
|
-
if (buffers2.length === 0) return attachments;
|
|
3644
|
-
return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers2)];
|
|
3645
|
-
}
|
|
3646
|
-
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
3647
|
-
const out = [];
|
|
3648
|
-
for (const rel of relativePaths) {
|
|
3649
|
-
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
3650
|
-
out.push({
|
|
3651
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3652
|
-
name: (0, import_node_path14.basename)(rel) || "file",
|
|
3653
|
-
kind: "file",
|
|
3654
|
-
content: `(invalid path: ${rel})`
|
|
3655
|
-
});
|
|
3656
|
-
continue;
|
|
3657
|
-
}
|
|
3658
|
-
const name = (0, import_node_path14.basename)(rel);
|
|
3659
|
-
try {
|
|
3660
|
-
const abs = (0, import_node_path14.join)(worktreePath, rel);
|
|
3661
|
-
const st = (0, import_node_fs13.statSync)(abs);
|
|
3662
|
-
if (!st.isFile()) continue;
|
|
3663
|
-
const buf = (0, import_node_fs13.readFileSync)(abs);
|
|
3664
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
3665
|
-
} catch (err) {
|
|
3666
|
-
out.push({
|
|
3667
|
-
id: (0, import_node_crypto5.randomUUID)(),
|
|
3668
|
-
name,
|
|
3669
|
-
kind: "file",
|
|
3670
|
-
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
3671
|
-
});
|
|
3672
|
-
}
|
|
3673
|
-
}
|
|
3674
|
-
return out;
|
|
3675
|
-
}
|
|
3676
|
-
var import_node_fs13, import_node_path14, import_node_crypto5, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
3677
|
-
var init_stage_files = __esm({
|
|
3678
|
-
"src/composer/stage-files.ts"() {
|
|
3679
|
-
"use strict";
|
|
3680
|
-
import_node_fs13 = require("fs");
|
|
3681
|
-
import_node_path14 = require("path");
|
|
3682
|
-
import_node_crypto5 = require("crypto");
|
|
3683
|
-
init_workspace_scratch();
|
|
3684
|
-
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
3685
|
-
"png",
|
|
3686
|
-
"jpg",
|
|
3687
|
-
"jpeg",
|
|
3688
|
-
"gif",
|
|
3689
|
-
"webp",
|
|
3690
|
-
"svg",
|
|
3691
|
-
"bmp",
|
|
3692
|
-
"ico"
|
|
3693
|
-
]);
|
|
3694
|
-
IMAGE_MIME_BY_EXT = {
|
|
3695
|
-
png: "image/png",
|
|
3696
|
-
jpg: "image/jpeg",
|
|
3697
|
-
jpeg: "image/jpeg",
|
|
3698
|
-
gif: "image/gif",
|
|
3699
|
-
webp: "image/webp",
|
|
3700
|
-
svg: "image/svg+xml",
|
|
3701
|
-
bmp: "image/bmp",
|
|
3702
|
-
ico: "image/x-icon"
|
|
3703
|
-
};
|
|
3704
|
-
MAX_INLINE_BYTES = 4e5;
|
|
3705
|
-
MAX_PREVIEW_BYTES = 5e6;
|
|
3706
|
-
IMAGE_HINT_RE = /^Image attached:/;
|
|
3707
|
-
PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
|
|
3708
|
-
}
|
|
3709
|
-
});
|
|
3710
|
-
|
|
3711
|
-
// src/git/team-meta.ts
|
|
3712
|
-
var SOCCER_TEAM_META;
|
|
3713
|
-
var init_team_meta = __esm({
|
|
3714
|
-
"src/git/team-meta.ts"() {
|
|
2959
|
+
// src/git/team-meta.ts
|
|
2960
|
+
var SOCCER_TEAM_META;
|
|
2961
|
+
var init_team_meta = __esm({
|
|
2962
|
+
"src/git/team-meta.ts"() {
|
|
3715
2963
|
"use strict";
|
|
3716
2964
|
SOCCER_TEAM_META = {
|
|
3717
2965
|
"aalborg": { location: "Aalborg, Denmark", league: "Danish Superliga" },
|
|
@@ -4502,89 +3750,835 @@ var init_teams = __esm({
|
|
|
4502
3750
|
}
|
|
4503
3751
|
});
|
|
4504
3752
|
|
|
4505
|
-
// src/git/worktree-labels.ts
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
}
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
const
|
|
4522
|
-
const
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
3753
|
+
// src/git/worktree-labels.ts
|
|
3754
|
+
function normalizeWorktreePath(worktreePath) {
|
|
3755
|
+
const trimmed = (worktreePath ?? "").replace(/\/+$/, "") || "/";
|
|
3756
|
+
const absolute = trimmed.startsWith("/");
|
|
3757
|
+
const parts = trimmed.split("/").filter((p) => p && p !== ".");
|
|
3758
|
+
const out = [];
|
|
3759
|
+
for (const p of parts) {
|
|
3760
|
+
if (p === "..") {
|
|
3761
|
+
out.pop();
|
|
3762
|
+
continue;
|
|
3763
|
+
}
|
|
3764
|
+
out.push(p);
|
|
3765
|
+
}
|
|
3766
|
+
return (absolute ? "/" : "") + out.join("/");
|
|
3767
|
+
}
|
|
3768
|
+
function worktreeNameFromPath(worktreePath) {
|
|
3769
|
+
const normalized = worktreePath.replace(/\/+$/, "");
|
|
3770
|
+
const parts = normalized.split("/");
|
|
3771
|
+
return parts[parts.length - 1] || worktreePath;
|
|
3772
|
+
}
|
|
3773
|
+
function ticketSlugForBranch(sourceRef) {
|
|
3774
|
+
const raw = sourceRef.trim();
|
|
3775
|
+
if (!raw) return null;
|
|
3776
|
+
const linear = raw.match(/\b([A-Za-z]{2,8}-\d{1,6})\b/);
|
|
3777
|
+
if (linear) return linear[1].toLowerCase();
|
|
3778
|
+
const hashed = raw.match(/^#(\d{1,8})$/);
|
|
3779
|
+
if (hashed) return hashed[1];
|
|
3780
|
+
const digits = raw.match(/^(\d{1,8})$/);
|
|
3781
|
+
if (digits) return digits[1];
|
|
3782
|
+
const slug = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
3783
|
+
return slug || null;
|
|
3784
|
+
}
|
|
3785
|
+
function worktreeSlugForTicket(ticketRef, teamSlug) {
|
|
3786
|
+
const ticket = ticketSlugForBranch(ticketRef);
|
|
3787
|
+
const team = teamSlug.trim().replace(/^thread\//, "");
|
|
3788
|
+
if (!ticket) return team;
|
|
3789
|
+
if (!team) return ticket;
|
|
3790
|
+
return `${ticket}-${team}`;
|
|
3791
|
+
}
|
|
3792
|
+
function isPlaceholderBranch(branchName, worktreePath) {
|
|
3793
|
+
const branch = branchName.trim();
|
|
3794
|
+
if (!branch || branch === "HEAD") return true;
|
|
3795
|
+
if (branch.startsWith("thread/")) return true;
|
|
3796
|
+
const dir = worktreeNameFromPath(worktreePath).toLowerCase();
|
|
3797
|
+
return branch.toLowerCase() === dir;
|
|
3798
|
+
}
|
|
3799
|
+
function branchDisplayLabel(branchName, worktreePath) {
|
|
3800
|
+
const dir = worktreeNameFromPath(worktreePath);
|
|
3801
|
+
if (isPlaceholderBranch(branchName, worktreePath)) {
|
|
3802
|
+
const slug = branchName.replace(/^thread\//, "") || dir;
|
|
3803
|
+
return teamNameFromSlug(slug);
|
|
3804
|
+
}
|
|
3805
|
+
return branchName.trim();
|
|
3806
|
+
}
|
|
3807
|
+
function threadDisplayLabel(thread) {
|
|
3808
|
+
if (thread.userSetTitle && thread.title?.trim()) return thread.title.trim();
|
|
3809
|
+
if (thread.prTitle?.trim()) return thread.prTitle.trim();
|
|
3810
|
+
return branchDisplayLabel(thread.branchName, thread.worktreePath);
|
|
3811
|
+
}
|
|
3812
|
+
function worktreeDisplayLabel(thread) {
|
|
3813
|
+
return threadDisplayLabel(thread);
|
|
3814
|
+
}
|
|
3815
|
+
function worktreeDisplayLabelForGroup(threads) {
|
|
3816
|
+
if (threads.length === 0) return "Worktree";
|
|
3817
|
+
const canonical = [...threads].sort((a, b) => a.createdAt.localeCompare(b.createdAt))[0];
|
|
3818
|
+
return threadDisplayLabel(canonical);
|
|
3819
|
+
}
|
|
3820
|
+
var init_worktree_labels = __esm({
|
|
3821
|
+
"src/git/worktree-labels.ts"() {
|
|
3822
|
+
"use strict";
|
|
3823
|
+
init_teams();
|
|
3824
|
+
}
|
|
3825
|
+
});
|
|
3826
|
+
|
|
3827
|
+
// src/store/setup-log.ts
|
|
3828
|
+
function setupLogPath(threadId) {
|
|
3829
|
+
return (0, import_node_path11.join)(threadsDir(), `${threadId}.setup.log.json`);
|
|
3830
|
+
}
|
|
3831
|
+
function setupLogKeyForWorktree(worktreePath) {
|
|
3832
|
+
const norm = normalizeWorktreePath(worktreePath);
|
|
3833
|
+
return `wt-${(0, import_node_crypto4.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
|
|
3834
|
+
}
|
|
3835
|
+
function emptySetupLog() {
|
|
3836
|
+
return { ...EMPTY };
|
|
3837
|
+
}
|
|
3838
|
+
function mergeSetupOutput(prev, incoming) {
|
|
3839
|
+
if (!prev) return incoming;
|
|
3840
|
+
if (!incoming) return prev;
|
|
3841
|
+
if (prev === incoming) return prev;
|
|
3842
|
+
if (prev.startsWith(incoming) || prev.endsWith(incoming)) return prev;
|
|
3843
|
+
if (incoming.startsWith(prev) || incoming.endsWith(prev)) return incoming;
|
|
3844
|
+
return incoming.length >= prev.length ? incoming : prev;
|
|
3845
|
+
}
|
|
3846
|
+
function clone(snap) {
|
|
3847
|
+
return { ...snap };
|
|
3848
|
+
}
|
|
3849
|
+
function persistNow(threadId) {
|
|
3850
|
+
const timer = persistTimers.get(threadId);
|
|
3851
|
+
if (timer) {
|
|
3852
|
+
clearTimeout(timer);
|
|
3853
|
+
persistTimers.delete(threadId);
|
|
3854
|
+
}
|
|
3855
|
+
const snap = memory.get(threadId);
|
|
3856
|
+
if (!snap) return;
|
|
3857
|
+
try {
|
|
3858
|
+
(0, import_node_fs10.writeFileSync)(setupLogPath(threadId), `${JSON.stringify(snap)}
|
|
3859
|
+
`, "utf8");
|
|
3860
|
+
} catch {
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
function schedulePersist(threadId) {
|
|
3864
|
+
if (persistTimers.has(threadId)) return;
|
|
3865
|
+
persistTimers.set(
|
|
3866
|
+
threadId,
|
|
3867
|
+
setTimeout(() => {
|
|
3868
|
+
persistTimers.delete(threadId);
|
|
3869
|
+
persistNow(threadId);
|
|
3870
|
+
}, 100)
|
|
3871
|
+
);
|
|
3872
|
+
}
|
|
3873
|
+
function loadFromDisk(threadId) {
|
|
3874
|
+
const path2 = setupLogPath(threadId);
|
|
3875
|
+
if (!(0, import_node_fs10.existsSync)(path2)) return null;
|
|
3876
|
+
try {
|
|
3877
|
+
const raw = JSON.parse((0, import_node_fs10.readFileSync)(path2, "utf8"));
|
|
3878
|
+
return {
|
|
3879
|
+
output: typeof raw.output === "string" ? raw.output : "",
|
|
3880
|
+
running: Boolean(raw.running),
|
|
3881
|
+
exitCode: typeof raw.exitCode === "number" ? raw.exitCode : null,
|
|
3882
|
+
source: typeof raw.source === "string" ? raw.source : null
|
|
3883
|
+
};
|
|
3884
|
+
} catch {
|
|
3885
|
+
return null;
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3888
|
+
function readSetupLog(threadId) {
|
|
3889
|
+
const cached = memory.get(threadId);
|
|
3890
|
+
if (cached) return clone(cached);
|
|
3891
|
+
const disk = loadFromDisk(threadId);
|
|
3892
|
+
if (disk) {
|
|
3893
|
+
memory.set(threadId, disk);
|
|
3894
|
+
return clone(disk);
|
|
3895
|
+
}
|
|
3896
|
+
return emptySetupLog();
|
|
3897
|
+
}
|
|
3898
|
+
function beginSetupLog(threadId) {
|
|
3899
|
+
const snap = {
|
|
3900
|
+
output: "",
|
|
3901
|
+
running: true,
|
|
3902
|
+
exitCode: null,
|
|
3903
|
+
source: null
|
|
3904
|
+
};
|
|
3905
|
+
memory.set(threadId, snap);
|
|
3906
|
+
persistNow(threadId);
|
|
3907
|
+
return clone(snap);
|
|
3908
|
+
}
|
|
3909
|
+
function appendSetupLog(threadId, line) {
|
|
3910
|
+
const current = memory.get(threadId) ?? readSetupLog(threadId);
|
|
3911
|
+
const snap = {
|
|
3912
|
+
...current,
|
|
3913
|
+
output: current.output ? `${current.output}
|
|
3914
|
+
${line}` : line,
|
|
3915
|
+
running: true
|
|
3916
|
+
};
|
|
3917
|
+
memory.set(threadId, snap);
|
|
3918
|
+
schedulePersist(threadId);
|
|
3919
|
+
return clone(snap);
|
|
3920
|
+
}
|
|
3921
|
+
function finishSetupLog(threadId, exitCode, source) {
|
|
3922
|
+
const current = memory.get(threadId) ?? readSetupLog(threadId);
|
|
3923
|
+
const snap = {
|
|
3924
|
+
...current,
|
|
3925
|
+
running: false,
|
|
3926
|
+
exitCode,
|
|
3927
|
+
source: source ?? current.source
|
|
3928
|
+
};
|
|
3929
|
+
memory.set(threadId, snap);
|
|
3930
|
+
persistNow(threadId);
|
|
3931
|
+
return clone(snap);
|
|
3932
|
+
}
|
|
3933
|
+
var import_node_crypto4, import_node_fs10, import_node_path11, EMPTY, memory, persistTimers;
|
|
3934
|
+
var init_setup_log = __esm({
|
|
3935
|
+
"src/store/setup-log.ts"() {
|
|
3936
|
+
"use strict";
|
|
3937
|
+
import_node_crypto4 = require("crypto");
|
|
3938
|
+
import_node_fs10 = require("fs");
|
|
3939
|
+
import_node_path11 = require("path");
|
|
3940
|
+
init_worktree_labels();
|
|
3941
|
+
init_paths();
|
|
3942
|
+
EMPTY = {
|
|
3943
|
+
output: "",
|
|
3944
|
+
running: false,
|
|
3945
|
+
exitCode: null,
|
|
3946
|
+
source: null
|
|
3947
|
+
};
|
|
3948
|
+
memory = /* @__PURE__ */ new Map();
|
|
3949
|
+
persistTimers = /* @__PURE__ */ new Map();
|
|
3950
|
+
}
|
|
3951
|
+
});
|
|
3952
|
+
|
|
3953
|
+
// src/store/schedules.ts
|
|
3954
|
+
function schedulesPath() {
|
|
3955
|
+
return (0, import_node_path12.join)(appDataDir(), "schedules.json");
|
|
3956
|
+
}
|
|
3957
|
+
function parseDurationMs(every) {
|
|
3958
|
+
const m = every.trim().match(DURATION_RE);
|
|
3959
|
+
if (!m) return null;
|
|
3960
|
+
const n = Number.parseInt(m[1], 10);
|
|
3961
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
3962
|
+
const unit = m[2].toLowerCase();
|
|
3963
|
+
return n * UNIT_MS[unit];
|
|
3964
|
+
}
|
|
3965
|
+
function defaultScheduleName(prompt) {
|
|
3966
|
+
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
3967
|
+
if (!line) return "Untitled schedule";
|
|
3968
|
+
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
3969
|
+
}
|
|
3970
|
+
function resolveScheduleThreadId(raw, env = process.env) {
|
|
3971
|
+
const value = raw?.trim() || "";
|
|
3972
|
+
if (!value) return null;
|
|
3973
|
+
if (value.toLowerCase() === "self") {
|
|
3974
|
+
return env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
|
|
3975
|
+
}
|
|
3976
|
+
return value;
|
|
3977
|
+
}
|
|
3978
|
+
function computeNextRunAt(when, from = /* @__PURE__ */ new Date()) {
|
|
3979
|
+
if (when.kind === "once") {
|
|
3980
|
+
const at = new Date(when.at);
|
|
3981
|
+
if (Number.isNaN(at.getTime())) {
|
|
3982
|
+
throw new Error(`Invalid once-at datetime: ${when.at}`);
|
|
3983
|
+
}
|
|
3984
|
+
return at;
|
|
3985
|
+
}
|
|
3986
|
+
if (when.kind === "every") {
|
|
3987
|
+
const ms = parseDurationMs(when.every);
|
|
3988
|
+
if (!ms) {
|
|
3989
|
+
throw new Error(`Invalid interval: ${when.every} (use 15m, 1h, 6h, 1d)`);
|
|
3990
|
+
}
|
|
3991
|
+
return new Date(from.getTime() + ms);
|
|
3992
|
+
}
|
|
3993
|
+
try {
|
|
3994
|
+
const job = new import_croner.Cron(when.expr, {
|
|
3995
|
+
timezone: when.tz?.trim() || void 0,
|
|
3996
|
+
paused: true
|
|
3997
|
+
});
|
|
3998
|
+
const next = job.nextRun(from);
|
|
3999
|
+
if (!next) {
|
|
4000
|
+
throw new Error(`Cron expression has no next run: ${when.expr}`);
|
|
4001
|
+
}
|
|
4002
|
+
return next;
|
|
4003
|
+
} catch (err) {
|
|
4004
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4005
|
+
throw new Error(`Invalid cron: ${message}`);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
function formatScheduleWhen(when) {
|
|
4009
|
+
if (when.kind === "once") return `once at ${when.at}`;
|
|
4010
|
+
if (when.kind === "every") return `every ${when.every}`;
|
|
4011
|
+
const tz = when.tz?.trim();
|
|
4012
|
+
return tz ? `cron ${when.expr} (${tz})` : `cron ${when.expr}`;
|
|
4013
|
+
}
|
|
4014
|
+
function nowIso2(d = /* @__PURE__ */ new Date()) {
|
|
4015
|
+
return d.toISOString();
|
|
4016
|
+
}
|
|
4017
|
+
function normalizeWhen(raw) {
|
|
4018
|
+
if (!raw || typeof raw !== "object") {
|
|
4019
|
+
throw new Error("Schedule is missing `when`");
|
|
4020
|
+
}
|
|
4021
|
+
const rec = raw;
|
|
4022
|
+
const kind = rec.kind;
|
|
4023
|
+
if (kind === "once" && typeof rec.at === "string") {
|
|
4024
|
+
return { kind: "once", at: rec.at };
|
|
4025
|
+
}
|
|
4026
|
+
if (kind === "every" && typeof rec.every === "string") {
|
|
4027
|
+
return { kind: "every", every: rec.every };
|
|
4028
|
+
}
|
|
4029
|
+
if (kind === "cron" && typeof rec.expr === "string") {
|
|
4030
|
+
return {
|
|
4031
|
+
kind: "cron",
|
|
4032
|
+
expr: rec.expr,
|
|
4033
|
+
tz: typeof rec.tz === "string" && rec.tz.trim() ? rec.tz.trim() : void 0
|
|
4034
|
+
};
|
|
4035
|
+
}
|
|
4036
|
+
throw new Error("Schedule `when` must be once, every, or cron");
|
|
4037
|
+
}
|
|
4038
|
+
function normalizeTask(raw) {
|
|
4039
|
+
const when = normalizeWhen(raw.when);
|
|
4040
|
+
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
4041
|
+
return {
|
|
4042
|
+
id: raw.id,
|
|
4043
|
+
name: typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : defaultScheduleName(raw.prompt),
|
|
4044
|
+
prompt: String(raw.prompt ?? ""),
|
|
4045
|
+
enabled: Boolean(raw.enabled),
|
|
4046
|
+
when,
|
|
4047
|
+
threadId: raw.threadId?.trim() || null,
|
|
4048
|
+
agent,
|
|
4049
|
+
model: raw.model?.trim() || null,
|
|
4050
|
+
nextRunAt: raw.nextRunAt,
|
|
4051
|
+
lastRunAt: raw.lastRunAt ?? null,
|
|
4052
|
+
lastThreadId: raw.lastThreadId ?? null,
|
|
4053
|
+
lastError: raw.lastError ?? null,
|
|
4054
|
+
createdBy: raw.createdBy === "mcp" || raw.createdBy === "cli" || raw.createdBy === "ui" ? raw.createdBy : "ui",
|
|
4055
|
+
createdAt: raw.createdAt,
|
|
4056
|
+
updatedAt: raw.updatedAt
|
|
4057
|
+
};
|
|
4058
|
+
}
|
|
4059
|
+
function readAll() {
|
|
4060
|
+
const path2 = schedulesPath();
|
|
4061
|
+
if (!(0, import_node_fs11.existsSync)(path2)) return [];
|
|
4062
|
+
try {
|
|
4063
|
+
const parsed = JSON.parse((0, import_node_fs11.readFileSync)(path2, "utf8"));
|
|
4064
|
+
if (!Array.isArray(parsed)) return [];
|
|
4065
|
+
return parsed.map((row) => {
|
|
4066
|
+
try {
|
|
4067
|
+
return normalizeTask(row);
|
|
4068
|
+
} catch {
|
|
4069
|
+
return null;
|
|
4070
|
+
}
|
|
4071
|
+
}).filter((row) => Boolean(row?.id && row.prompt));
|
|
4072
|
+
} catch {
|
|
4073
|
+
return [];
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
function writeAll(rows) {
|
|
4077
|
+
writePrivateFile(schedulesPath(), `${JSON.stringify(rows, null, 2)}
|
|
4078
|
+
`);
|
|
4079
|
+
}
|
|
4080
|
+
function buildTask(input, now) {
|
|
4081
|
+
const prompt = input.prompt.trim();
|
|
4082
|
+
if (!prompt) throw new Error("Schedule prompt is required");
|
|
4083
|
+
const when = normalizeWhen(input.when);
|
|
4084
|
+
const nextRunAt = computeNextRunAt(when, now).toISOString();
|
|
4085
|
+
const ts = nowIso2(now);
|
|
4086
|
+
const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
|
|
4087
|
+
return {
|
|
4088
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
4089
|
+
name: input.name?.trim() || defaultScheduleName(prompt),
|
|
4090
|
+
prompt,
|
|
4091
|
+
enabled: input.enabled !== false,
|
|
4092
|
+
when,
|
|
4093
|
+
threadId: input.threadId?.trim() || null,
|
|
4094
|
+
agent,
|
|
4095
|
+
model: input.model?.trim() || null,
|
|
4096
|
+
nextRunAt,
|
|
4097
|
+
lastRunAt: null,
|
|
4098
|
+
lastThreadId: null,
|
|
4099
|
+
lastError: null,
|
|
4100
|
+
createdBy: input.createdBy,
|
|
4101
|
+
createdAt: ts,
|
|
4102
|
+
updatedAt: ts
|
|
4103
|
+
};
|
|
4104
|
+
}
|
|
4105
|
+
function listSchedules() {
|
|
4106
|
+
return readAll().sort((a, b) => a.nextRunAt.localeCompare(b.nextRunAt));
|
|
4107
|
+
}
|
|
4108
|
+
function hasEnabledSchedules() {
|
|
4109
|
+
return listSchedules().some((row) => row.enabled);
|
|
4110
|
+
}
|
|
4111
|
+
function getSchedule(id) {
|
|
4112
|
+
const key = id.trim();
|
|
4113
|
+
if (!key) return null;
|
|
4114
|
+
return readAll().find(
|
|
4115
|
+
(row) => row.id === key || row.id.startsWith(key) && key.length >= 8
|
|
4116
|
+
) ?? null;
|
|
4117
|
+
}
|
|
4118
|
+
function createSchedule(input) {
|
|
4119
|
+
const task = buildTask(input, /* @__PURE__ */ new Date());
|
|
4120
|
+
const rows = readAll();
|
|
4121
|
+
rows.push(task);
|
|
4122
|
+
writeAll(rows);
|
|
4123
|
+
return task;
|
|
4124
|
+
}
|
|
4125
|
+
function updateSchedule(id, patch) {
|
|
4126
|
+
const rows = readAll();
|
|
4127
|
+
const idx = rows.findIndex((row) => row.id === id || id.length >= 8 && row.id.startsWith(id));
|
|
4128
|
+
if (idx < 0) throw new Error(`Schedule not found: ${id}`);
|
|
4129
|
+
const prev = rows[idx];
|
|
4130
|
+
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
4131
|
+
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
4132
|
+
if (!prompt) throw new Error("Schedule prompt is required");
|
|
4133
|
+
const whenChanged = patch.when !== void 0;
|
|
4134
|
+
const next = {
|
|
4135
|
+
...prev,
|
|
4136
|
+
name: patch.name !== void 0 ? patch.name.trim() || defaultScheduleName(prompt) : prev.name,
|
|
4137
|
+
prompt,
|
|
4138
|
+
enabled: patch.enabled ?? prev.enabled,
|
|
4139
|
+
when,
|
|
4140
|
+
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
4141
|
+
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
4142
|
+
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
4143
|
+
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
4144
|
+
lastError: whenChanged ? null : prev.lastError,
|
|
4145
|
+
updatedAt: nowIso2()
|
|
4146
|
+
};
|
|
4147
|
+
rows[idx] = next;
|
|
4148
|
+
writeAll(rows);
|
|
4149
|
+
return next;
|
|
4150
|
+
}
|
|
4151
|
+
function deleteSchedule(id) {
|
|
4152
|
+
const rows = readAll();
|
|
4153
|
+
const next = rows.filter(
|
|
4154
|
+
(row) => row.id !== id && !(id.length >= 8 && row.id.startsWith(id))
|
|
4155
|
+
);
|
|
4156
|
+
if (next.length === rows.length) throw new Error(`Schedule not found: ${id}`);
|
|
4157
|
+
writeAll(next);
|
|
4158
|
+
}
|
|
4159
|
+
function recordScheduleRun(id, result) {
|
|
4160
|
+
const rows = readAll();
|
|
4161
|
+
const idx = rows.findIndex((row) => row.id === id);
|
|
4162
|
+
if (idx < 0) throw new Error(`Schedule not found: ${id}`);
|
|
4163
|
+
const prev = rows[idx];
|
|
4164
|
+
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
4165
|
+
const next = {
|
|
4166
|
+
...prev,
|
|
4167
|
+
enabled: prev.when.kind === "once" ? false : prev.enabled,
|
|
4168
|
+
nextRunAt: prev.when.kind === "once" ? prev.nextRunAt : computeNextRunAt(prev.when, firedAt).toISOString(),
|
|
4169
|
+
lastRunAt: nowIso2(firedAt),
|
|
4170
|
+
lastThreadId: result.lastThreadId !== void 0 ? result.lastThreadId : prev.lastThreadId,
|
|
4171
|
+
lastError: result.lastError ?? null,
|
|
4172
|
+
updatedAt: nowIso2(firedAt)
|
|
4173
|
+
};
|
|
4174
|
+
rows[idx] = next;
|
|
4175
|
+
writeAll(rows);
|
|
4176
|
+
return next;
|
|
4177
|
+
}
|
|
4178
|
+
var import_node_crypto5, import_node_fs11, import_node_path12, import_croner, DURATION_RE, UNIT_MS;
|
|
4179
|
+
var init_schedules = __esm({
|
|
4180
|
+
"src/store/schedules.ts"() {
|
|
4181
|
+
"use strict";
|
|
4182
|
+
import_node_crypto5 = require("crypto");
|
|
4183
|
+
import_node_fs11 = require("fs");
|
|
4184
|
+
import_node_path12 = require("path");
|
|
4185
|
+
import_croner = require("croner");
|
|
4186
|
+
init_orchestrator_capable();
|
|
4187
|
+
init_paths();
|
|
4188
|
+
init_private_file();
|
|
4189
|
+
DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
4190
|
+
UNIT_MS = {
|
|
4191
|
+
s: 1e3,
|
|
4192
|
+
m: 6e4,
|
|
4193
|
+
h: 36e5,
|
|
4194
|
+
d: 864e5
|
|
4195
|
+
};
|
|
4196
|
+
}
|
|
4197
|
+
});
|
|
4198
|
+
|
|
4199
|
+
// src/store/desktop-host.ts
|
|
4200
|
+
function desktopHostPidPath() {
|
|
4201
|
+
return (0, import_node_path13.join)(appDataDir(), "desktop-host.pid");
|
|
4202
|
+
}
|
|
4203
|
+
function claimDesktopHost(pid = process.pid) {
|
|
4204
|
+
(0, import_node_fs12.writeFileSync)(desktopHostPidPath(), `${pid}
|
|
4205
|
+
`, "utf8");
|
|
4206
|
+
}
|
|
4207
|
+
function releaseDesktopHost(pid = process.pid) {
|
|
4208
|
+
if (readDesktopHostPid() !== pid) return;
|
|
4209
|
+
try {
|
|
4210
|
+
(0, import_node_fs12.unlinkSync)(desktopHostPidPath());
|
|
4211
|
+
} catch {
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
function readDesktopHostPid() {
|
|
4215
|
+
try {
|
|
4216
|
+
const pid = Number.parseInt((0, import_node_fs12.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
|
|
4217
|
+
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
4218
|
+
return pid;
|
|
4219
|
+
} catch {
|
|
4220
|
+
return null;
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
function pidAlive(pid) {
|
|
4224
|
+
try {
|
|
4225
|
+
process.kill(pid, 0);
|
|
4226
|
+
return true;
|
|
4227
|
+
} catch {
|
|
4228
|
+
return false;
|
|
4229
|
+
}
|
|
4230
|
+
}
|
|
4231
|
+
function isDesktopHostAlive() {
|
|
4232
|
+
const pid = readDesktopHostPid();
|
|
4233
|
+
return pid != null && pidAlive(pid);
|
|
4234
|
+
}
|
|
4235
|
+
function isThisProcessDesktopHost() {
|
|
4236
|
+
return readDesktopHostPid() === process.pid && pidAlive(process.pid);
|
|
4237
|
+
}
|
|
4238
|
+
function thisProcessShouldDrainAgentQueues() {
|
|
4239
|
+
if (isThisProcessDesktopHost()) return true;
|
|
4240
|
+
return !isDesktopHostAlive();
|
|
4241
|
+
}
|
|
4242
|
+
var import_node_fs12, import_node_path13;
|
|
4243
|
+
var init_desktop_host = __esm({
|
|
4244
|
+
"src/store/desktop-host.ts"() {
|
|
4245
|
+
"use strict";
|
|
4246
|
+
import_node_fs12 = require("fs");
|
|
4247
|
+
import_node_path13 = require("path");
|
|
4248
|
+
init_paths();
|
|
4249
|
+
}
|
|
4250
|
+
});
|
|
4251
|
+
|
|
4252
|
+
// src/brightsy/cloud-connect-constants.ts
|
|
4253
|
+
function parseForceStopMessage(message) {
|
|
4254
|
+
const normalized = message.replace(/\r\n/g, "\n");
|
|
4255
|
+
const nl = normalized.indexOf("\n");
|
|
4256
|
+
const firstLine = (nl === -1 ? normalized : normalized.slice(0, nl)).trim();
|
|
4257
|
+
const remainder = (nl === -1 ? "" : normalized.slice(nl + 1)).trim();
|
|
4258
|
+
const forceStop = firstLine.toLowerCase() === SIDEBOARD_FORCE_STOP.toLowerCase();
|
|
4259
|
+
return { forceStop, remainder: forceStop ? remainder : message };
|
|
4260
|
+
}
|
|
4261
|
+
var CLOUD_ORCHESTRATOR_GOAL, SIDEBOARD_FORCE_STOP, CLOUD_COORDINATOR_BUSY_REPLY, CLOUD_COORDINATOR_STOPPED_REPLY, CLOUD_COORDINATOR_TIMEOUT_REPLY;
|
|
4262
|
+
var init_cloud_connect_constants = __esm({
|
|
4263
|
+
"src/brightsy/cloud-connect-constants.ts"() {
|
|
4264
|
+
"use strict";
|
|
4265
|
+
CLOUD_ORCHESTRATOR_GOAL = "Cloud-connected Sideboard orchestrator";
|
|
4266
|
+
SIDEBOARD_FORCE_STOP = "SIDEBOARD_FORCE_STOP";
|
|
4267
|
+
CLOUD_COORDINATOR_BUSY_REPLY = [
|
|
4268
|
+
"Sideboard is busy with an in-progress client/desktop tool turn on the global coordinator.",
|
|
4269
|
+
"I did not start a new orchestration turn.",
|
|
4270
|
+
`To force-stop the in-progress turn, send another desktop request whose first line is exactly ${SIDEBOARD_FORCE_STOP}`,
|
|
4271
|
+
"(optional follow-up request on later lines).",
|
|
4272
|
+
"What do you want me to do? (retry later, wait until idle, force-stop, rephrase, or cancel)"
|
|
4273
|
+
].join(" ");
|
|
4274
|
+
CLOUD_COORDINATOR_STOPPED_REPLY = [
|
|
4275
|
+
"Sideboard force-stopped the in-progress global coordinator turn.",
|
|
4276
|
+
"No new orchestration request was started."
|
|
4277
|
+
].join(" ");
|
|
4278
|
+
CLOUD_COORDINATOR_TIMEOUT_REPLY = [
|
|
4279
|
+
"Sideboard global coordinator timed out waiting for the local agent turn to finish.",
|
|
4280
|
+
"I did not produce a full orchestration result.",
|
|
4281
|
+
`To force-stop the in-progress turn, send another desktop request whose first line is exactly ${SIDEBOARD_FORCE_STOP}`,
|
|
4282
|
+
"(optional follow-up request on later lines).",
|
|
4283
|
+
"What do you want me to do? (retry later, wait, force-stop, rephrase, or cancel)"
|
|
4284
|
+
].join(" ");
|
|
4285
|
+
}
|
|
4286
|
+
});
|
|
4287
|
+
|
|
4288
|
+
// src/paths/workspace-scratch.ts
|
|
4289
|
+
function attachmentsGitignoreBody() {
|
|
4290
|
+
return ATTACHMENTS_GITIGNORE;
|
|
4291
|
+
}
|
|
4292
|
+
function isWorkspaceScratchPath(relativePath) {
|
|
4293
|
+
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
4294
|
+
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === CLI_DIR || p.startsWith(`${CLI_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
|
|
4295
|
+
}
|
|
4296
|
+
var ATTACHMENTS_DIR, CLI_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
|
|
4297
|
+
var init_workspace_scratch = __esm({
|
|
4298
|
+
"src/paths/workspace-scratch.ts"() {
|
|
4299
|
+
"use strict";
|
|
4300
|
+
ATTACHMENTS_DIR = ".context/attachments";
|
|
4301
|
+
CLI_DIR = ".context/cli";
|
|
4302
|
+
DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
|
|
4303
|
+
LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
4304
|
+
LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
|
|
4305
|
+
ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
|
|
4306
|
+
*
|
|
4307
|
+
!.gitignore
|
|
4308
|
+
`;
|
|
4309
|
+
}
|
|
4310
|
+
});
|
|
4311
|
+
|
|
4312
|
+
// src/composer/stage-files.ts
|
|
4313
|
+
function fileExtension(filePath) {
|
|
4314
|
+
const base = (0, import_node_path14.basename)(filePath).toLowerCase();
|
|
4315
|
+
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
4316
|
+
}
|
|
4317
|
+
function isImageFilePath(filePath) {
|
|
4318
|
+
return IMAGE_EXTENSIONS.has(fileExtension(filePath));
|
|
4319
|
+
}
|
|
4320
|
+
function imageMimeType(filePath) {
|
|
4321
|
+
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
4322
|
+
}
|
|
4323
|
+
function ensureAttachmentsDir(worktreePath) {
|
|
4324
|
+
const dir = (0, import_node_path14.join)(worktreePath, ATTACHMENTS_DIR);
|
|
4325
|
+
(0, import_node_fs13.mkdirSync)(dir, { recursive: true });
|
|
4326
|
+
const gi = (0, import_node_path14.join)(dir, ".gitignore");
|
|
4327
|
+
if (!(0, import_node_fs13.existsSync)(gi)) {
|
|
4328
|
+
(0, import_node_fs13.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
4529
4329
|
}
|
|
4530
|
-
return
|
|
4330
|
+
return dir;
|
|
4531
4331
|
}
|
|
4532
|
-
function
|
|
4533
|
-
const
|
|
4534
|
-
|
|
4535
|
-
|
|
4332
|
+
function uniqueAttachmentName(dir, originalName) {
|
|
4333
|
+
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
4334
|
+
if (!(0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, safe))) return safe;
|
|
4335
|
+
const ext = (0, import_node_path14.extname)(safe);
|
|
4336
|
+
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
4337
|
+
for (let i = 1; i < 1e4; i++) {
|
|
4338
|
+
const candidate = `${stem}-${i}${ext}`;
|
|
4339
|
+
if (!(0, import_node_fs13.existsSync)((0, import_node_path14.join)(dir, candidate))) return candidate;
|
|
4340
|
+
}
|
|
4341
|
+
return `${stem}-${(0, import_node_crypto6.randomUUID)()}${ext}`;
|
|
4536
4342
|
}
|
|
4537
|
-
function
|
|
4538
|
-
|
|
4539
|
-
if (
|
|
4540
|
-
|
|
4541
|
-
if (linear) return linear[1].toLowerCase();
|
|
4542
|
-
const hashed = raw.match(/^#(\d{1,8})$/);
|
|
4543
|
-
if (hashed) return hashed[1];
|
|
4544
|
-
const digits = raw.match(/^(\d{1,8})$/);
|
|
4545
|
-
if (digits) return digits[1];
|
|
4546
|
-
const slug = raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
4547
|
-
return slug || null;
|
|
4343
|
+
function previewDataUrlFromBuf(filePath, buf) {
|
|
4344
|
+
if (!isImageFilePath(filePath)) return void 0;
|
|
4345
|
+
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
4346
|
+
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
4548
4347
|
}
|
|
4549
|
-
function
|
|
4550
|
-
const
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4348
|
+
function attachmentFromBuffer(name, buf, opts) {
|
|
4349
|
+
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
4350
|
+
if (isImageFilePath(name)) {
|
|
4351
|
+
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
4352
|
+
return {
|
|
4353
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4354
|
+
name,
|
|
4355
|
+
kind: "file",
|
|
4356
|
+
path: opts.path,
|
|
4357
|
+
previewDataUrl,
|
|
4358
|
+
content: [
|
|
4359
|
+
`Image attached: ${pathHint}`,
|
|
4360
|
+
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
4361
|
+
].join("\n")
|
|
4362
|
+
};
|
|
4363
|
+
}
|
|
4364
|
+
if (buf.length > MAX_INLINE_BYTES) {
|
|
4365
|
+
return {
|
|
4366
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4367
|
+
name,
|
|
4368
|
+
kind: "file",
|
|
4369
|
+
path: opts.path,
|
|
4370
|
+
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
4371
|
+
};
|
|
4372
|
+
}
|
|
4373
|
+
if (buf.includes(0)) {
|
|
4374
|
+
return {
|
|
4375
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4376
|
+
name,
|
|
4377
|
+
kind: "file",
|
|
4378
|
+
path: opts.path,
|
|
4379
|
+
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
4380
|
+
};
|
|
4381
|
+
}
|
|
4382
|
+
return {
|
|
4383
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4384
|
+
name,
|
|
4385
|
+
kind: "file",
|
|
4386
|
+
path: opts.path,
|
|
4387
|
+
content: buf.toString("utf8")
|
|
4388
|
+
};
|
|
4555
4389
|
}
|
|
4556
|
-
function
|
|
4557
|
-
const
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4390
|
+
function attachmentFromAbsolutePath(absolutePath) {
|
|
4391
|
+
const name = (0, import_node_path14.basename)(absolutePath);
|
|
4392
|
+
try {
|
|
4393
|
+
const st = (0, import_node_fs13.statSync)(absolutePath);
|
|
4394
|
+
if (!st.isFile()) {
|
|
4395
|
+
return {
|
|
4396
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4397
|
+
name,
|
|
4398
|
+
kind: "file",
|
|
4399
|
+
content: `(not a file: ${absolutePath})`
|
|
4400
|
+
};
|
|
4401
|
+
}
|
|
4402
|
+
const buf = (0, import_node_fs13.readFileSync)(absolutePath);
|
|
4403
|
+
return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
|
|
4404
|
+
} catch (err) {
|
|
4405
|
+
return {
|
|
4406
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4407
|
+
name,
|
|
4408
|
+
kind: "file",
|
|
4409
|
+
content: `(could not read ${absolutePath}: ${err instanceof Error ? err.message : String(err)})`
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4562
4412
|
}
|
|
4563
|
-
function
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4413
|
+
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
4414
|
+
if (absolutePaths.length === 0) return [];
|
|
4415
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
4416
|
+
const out = [];
|
|
4417
|
+
for (const abs of absolutePaths) {
|
|
4418
|
+
const originalName = (0, import_node_path14.basename)(abs);
|
|
4419
|
+
try {
|
|
4420
|
+
const st = (0, import_node_fs13.statSync)(abs);
|
|
4421
|
+
if (!st.isFile()) continue;
|
|
4422
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
4423
|
+
const destAbs = (0, import_node_path14.join)(dir, name);
|
|
4424
|
+
(0, import_node_fs13.copyFileSync)(abs, destAbs);
|
|
4425
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
4426
|
+
const buf = (0, import_node_fs13.readFileSync)(destAbs);
|
|
4427
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
4428
|
+
} catch (err) {
|
|
4429
|
+
out.push({
|
|
4430
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4431
|
+
name: originalName,
|
|
4432
|
+
kind: "file",
|
|
4433
|
+
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
4434
|
+
});
|
|
4435
|
+
}
|
|
4568
4436
|
}
|
|
4569
|
-
return
|
|
4437
|
+
return out;
|
|
4570
4438
|
}
|
|
4571
|
-
function
|
|
4572
|
-
if (
|
|
4573
|
-
|
|
4574
|
-
|
|
4439
|
+
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
4440
|
+
if (buffers2.length === 0) return [];
|
|
4441
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
4442
|
+
const out = [];
|
|
4443
|
+
for (const item of buffers2) {
|
|
4444
|
+
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
4445
|
+
try {
|
|
4446
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
4447
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
4448
|
+
const destAbs = (0, import_node_path14.join)(dir, name);
|
|
4449
|
+
(0, import_node_fs13.writeFileSync)(destAbs, buf);
|
|
4450
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
4451
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
4452
|
+
} catch (err) {
|
|
4453
|
+
out.push({
|
|
4454
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4455
|
+
name: originalName,
|
|
4456
|
+
kind: "file",
|
|
4457
|
+
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
4458
|
+
});
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
return out;
|
|
4575
4462
|
}
|
|
4576
|
-
function
|
|
4577
|
-
return
|
|
4463
|
+
function attachmentsFromBuffers(buffers2) {
|
|
4464
|
+
return buffers2.map((item) => {
|
|
4465
|
+
const name = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
4466
|
+
try {
|
|
4467
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
4468
|
+
return attachmentFromBuffer(name, buf, { sourceLabel: name });
|
|
4469
|
+
} catch (err) {
|
|
4470
|
+
return {
|
|
4471
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4472
|
+
name,
|
|
4473
|
+
kind: "file",
|
|
4474
|
+
content: `(could not attach ${name}: ${err instanceof Error ? err.message : String(err)})`
|
|
4475
|
+
};
|
|
4476
|
+
}
|
|
4477
|
+
});
|
|
4478
|
+
}
|
|
4479
|
+
function isWorktreeRelativePath(p) {
|
|
4480
|
+
if (!p || p.includes("..")) return false;
|
|
4481
|
+
if (p.startsWith("/")) return false;
|
|
4482
|
+
if (/^[A-Za-z]:[\\/]/.test(p)) return false;
|
|
4483
|
+
return true;
|
|
4484
|
+
}
|
|
4485
|
+
function dataUrlToBase64(url) {
|
|
4486
|
+
if (!url) return null;
|
|
4487
|
+
const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
|
|
4488
|
+
return m?.[1] ?? null;
|
|
4489
|
+
}
|
|
4490
|
+
function persistPendingFileAttachments(worktreePath, attachments) {
|
|
4491
|
+
if (attachments.length === 0) return attachments;
|
|
4492
|
+
const keep = [];
|
|
4493
|
+
const buffers2 = [];
|
|
4494
|
+
for (const att of attachments) {
|
|
4495
|
+
if (att.kind !== "file") {
|
|
4496
|
+
keep.push(att);
|
|
4497
|
+
continue;
|
|
4498
|
+
}
|
|
4499
|
+
if (att.path && isWorktreeRelativePath(att.path)) {
|
|
4500
|
+
keep.push(att);
|
|
4501
|
+
continue;
|
|
4502
|
+
}
|
|
4503
|
+
const fromPreview = dataUrlToBase64(att.previewDataUrl);
|
|
4504
|
+
if (fromPreview) {
|
|
4505
|
+
buffers2.push({ name: att.name, dataBase64: fromPreview });
|
|
4506
|
+
continue;
|
|
4507
|
+
}
|
|
4508
|
+
if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
|
|
4509
|
+
buffers2.push({
|
|
4510
|
+
name: att.name,
|
|
4511
|
+
dataBase64: Buffer.from(att.content, "utf8").toString("base64")
|
|
4512
|
+
});
|
|
4513
|
+
continue;
|
|
4514
|
+
}
|
|
4515
|
+
keep.push(att);
|
|
4516
|
+
}
|
|
4517
|
+
if (buffers2.length === 0) return attachments;
|
|
4518
|
+
return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers2)];
|
|
4578
4519
|
}
|
|
4579
|
-
function
|
|
4580
|
-
|
|
4581
|
-
const
|
|
4582
|
-
|
|
4520
|
+
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
4521
|
+
const out = [];
|
|
4522
|
+
for (const rel of relativePaths) {
|
|
4523
|
+
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
4524
|
+
out.push({
|
|
4525
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4526
|
+
name: (0, import_node_path14.basename)(rel) || "file",
|
|
4527
|
+
kind: "file",
|
|
4528
|
+
content: `(invalid path: ${rel})`
|
|
4529
|
+
});
|
|
4530
|
+
continue;
|
|
4531
|
+
}
|
|
4532
|
+
const name = (0, import_node_path14.basename)(rel);
|
|
4533
|
+
try {
|
|
4534
|
+
const abs = (0, import_node_path14.join)(worktreePath, rel);
|
|
4535
|
+
const st = (0, import_node_fs13.statSync)(abs);
|
|
4536
|
+
if (!st.isFile()) continue;
|
|
4537
|
+
const buf = (0, import_node_fs13.readFileSync)(abs);
|
|
4538
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
4539
|
+
} catch (err) {
|
|
4540
|
+
out.push({
|
|
4541
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
4542
|
+
name,
|
|
4543
|
+
kind: "file",
|
|
4544
|
+
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
4545
|
+
});
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
return out;
|
|
4583
4549
|
}
|
|
4584
|
-
var
|
|
4585
|
-
|
|
4550
|
+
var import_node_fs13, import_node_path14, import_node_crypto6, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
4551
|
+
var init_stage_files = __esm({
|
|
4552
|
+
"src/composer/stage-files.ts"() {
|
|
4586
4553
|
"use strict";
|
|
4587
|
-
|
|
4554
|
+
import_node_fs13 = require("fs");
|
|
4555
|
+
import_node_path14 = require("path");
|
|
4556
|
+
import_node_crypto6 = require("crypto");
|
|
4557
|
+
init_workspace_scratch();
|
|
4558
|
+
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4559
|
+
"png",
|
|
4560
|
+
"jpg",
|
|
4561
|
+
"jpeg",
|
|
4562
|
+
"gif",
|
|
4563
|
+
"webp",
|
|
4564
|
+
"svg",
|
|
4565
|
+
"bmp",
|
|
4566
|
+
"ico"
|
|
4567
|
+
]);
|
|
4568
|
+
IMAGE_MIME_BY_EXT = {
|
|
4569
|
+
png: "image/png",
|
|
4570
|
+
jpg: "image/jpeg",
|
|
4571
|
+
jpeg: "image/jpeg",
|
|
4572
|
+
gif: "image/gif",
|
|
4573
|
+
webp: "image/webp",
|
|
4574
|
+
svg: "image/svg+xml",
|
|
4575
|
+
bmp: "image/bmp",
|
|
4576
|
+
ico: "image/x-icon"
|
|
4577
|
+
};
|
|
4578
|
+
MAX_INLINE_BYTES = 4e5;
|
|
4579
|
+
MAX_PREVIEW_BYTES = 5e6;
|
|
4580
|
+
IMAGE_HINT_RE = /^Image attached:/;
|
|
4581
|
+
PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
|
|
4588
4582
|
}
|
|
4589
4583
|
});
|
|
4590
4584
|
|
|
@@ -7294,7 +7288,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
7294
7288
|
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
7295
7289
|
const bodyFile = (0, import_node_path20.join)(
|
|
7296
7290
|
(0, import_node_os6.tmpdir)(),
|
|
7297
|
-
`sideboard-pr-body-${process.pid}-${(0,
|
|
7291
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto7.randomBytes)(6).toString("hex")}.md`
|
|
7298
7292
|
);
|
|
7299
7293
|
(0, import_node_fs18.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
7300
7294
|
`, "utf8");
|
|
@@ -7435,11 +7429,11 @@ function allocateTeamSlug(repoPath) {
|
|
|
7435
7429
|
}
|
|
7436
7430
|
throw new Error("No available soccer team worktree directories left");
|
|
7437
7431
|
}
|
|
7438
|
-
var
|
|
7432
|
+
var import_node_crypto7, import_node_fs18, import_node_os6, import_node_path20, PR_DETAILS_JSON_FIELDS;
|
|
7439
7433
|
var init_worktree = __esm({
|
|
7440
7434
|
"src/git/worktree.ts"() {
|
|
7441
7435
|
"use strict";
|
|
7442
|
-
|
|
7436
|
+
import_node_crypto7 = require("crypto");
|
|
7443
7437
|
import_node_fs18 = require("fs");
|
|
7444
7438
|
import_node_os6 = require("os");
|
|
7445
7439
|
import_node_path20 = require("path");
|
|
@@ -14805,6 +14799,59 @@ var init_context_compact = __esm({
|
|
|
14805
14799
|
}
|
|
14806
14800
|
});
|
|
14807
14801
|
|
|
14802
|
+
// src/threads/worktree-runtime.ts
|
|
14803
|
+
function worktreeProcessPrefix(worktreePath) {
|
|
14804
|
+
return `wt:${normalizeWorktreePath(worktreePath)}`;
|
|
14805
|
+
}
|
|
14806
|
+
function worktreeSetupProcessKey(worktreePath) {
|
|
14807
|
+
return `${worktreeProcessPrefix(worktreePath)}:setup`;
|
|
14808
|
+
}
|
|
14809
|
+
function worktreeRunProcessKey(worktreePath, scriptName) {
|
|
14810
|
+
return `${worktreeProcessPrefix(worktreePath)}:run:${scriptName}`;
|
|
14811
|
+
}
|
|
14812
|
+
function worktreeDevProcessKey(worktreePath) {
|
|
14813
|
+
return `${worktreeProcessPrefix(worktreePath)}:dev`;
|
|
14814
|
+
}
|
|
14815
|
+
function isWorktreeRunProcessKey(key, worktreePath) {
|
|
14816
|
+
const prefix = worktreeProcessPrefix(worktreePath);
|
|
14817
|
+
return key.startsWith(`${prefix}:run:`) || key === `${prefix}:dev`;
|
|
14818
|
+
}
|
|
14819
|
+
function pickRichestSetupLog(snaps) {
|
|
14820
|
+
let best;
|
|
14821
|
+
for (const snap of snaps) {
|
|
14822
|
+
if (!snap.output && !snap.running && snap.exitCode == null) continue;
|
|
14823
|
+
if (!best) {
|
|
14824
|
+
best = snap;
|
|
14825
|
+
continue;
|
|
14826
|
+
}
|
|
14827
|
+
if (snap.running && !best.running) {
|
|
14828
|
+
best = snap;
|
|
14829
|
+
continue;
|
|
14830
|
+
}
|
|
14831
|
+
if (snap.running === best.running && snap.output.length > best.output.length) {
|
|
14832
|
+
best = snap;
|
|
14833
|
+
}
|
|
14834
|
+
}
|
|
14835
|
+
return best;
|
|
14836
|
+
}
|
|
14837
|
+
function mergeWorktreeActiveRuns(threads) {
|
|
14838
|
+
const byName = /* @__PURE__ */ new Map();
|
|
14839
|
+
let devPort = null;
|
|
14840
|
+
for (const thread of threads) {
|
|
14841
|
+
if (thread.devPort != null && devPort == null) devPort = thread.devPort;
|
|
14842
|
+
for (const run2 of thread.activeRuns ?? []) {
|
|
14843
|
+
if (!byName.has(run2.scriptName)) byName.set(run2.scriptName, run2);
|
|
14844
|
+
}
|
|
14845
|
+
}
|
|
14846
|
+
return { activeRuns: [...byName.values()], devPort };
|
|
14847
|
+
}
|
|
14848
|
+
var init_worktree_runtime = __esm({
|
|
14849
|
+
"src/threads/worktree-runtime.ts"() {
|
|
14850
|
+
"use strict";
|
|
14851
|
+
init_worktree_labels();
|
|
14852
|
+
}
|
|
14853
|
+
});
|
|
14854
|
+
|
|
14808
14855
|
// src/threads/chat-tabs.ts
|
|
14809
14856
|
function sameWorktreePath(a, b) {
|
|
14810
14857
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
@@ -14867,7 +14914,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
14867
14914
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
14868
14915
|
const title = baseTitle || "Chat";
|
|
14869
14916
|
return {
|
|
14870
|
-
id: (0,
|
|
14917
|
+
id: (0, import_node_crypto8.randomUUID)(),
|
|
14871
14918
|
name: `Transcript of ${title}.md`,
|
|
14872
14919
|
kind: "transcript",
|
|
14873
14920
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -14901,7 +14948,8 @@ function createChatTab(input) {
|
|
|
14901
14948
|
planMode: from.planMode,
|
|
14902
14949
|
autonomy: input.autonomy ?? from.autonomy,
|
|
14903
14950
|
attachments: input.attachments ?? [],
|
|
14904
|
-
status: "idle"
|
|
14951
|
+
status: "idle",
|
|
14952
|
+
...mergeWorktreeActiveRuns(threadsSharingWorktree(binding.worktreePath))
|
|
14905
14953
|
});
|
|
14906
14954
|
writeThread(thread);
|
|
14907
14955
|
return thread;
|
|
@@ -14924,17 +14972,18 @@ function forkChatTab(input) {
|
|
|
14924
14972
|
}
|
|
14925
14973
|
return tab;
|
|
14926
14974
|
}
|
|
14927
|
-
var
|
|
14975
|
+
var import_node_crypto8;
|
|
14928
14976
|
var init_chat_tabs = __esm({
|
|
14929
14977
|
"src/threads/chat-tabs.ts"() {
|
|
14930
14978
|
"use strict";
|
|
14931
|
-
|
|
14979
|
+
import_node_crypto8 = require("crypto");
|
|
14932
14980
|
init_context_compact();
|
|
14933
14981
|
init_teams();
|
|
14934
14982
|
init_worktree_labels();
|
|
14935
14983
|
init_global_workspace();
|
|
14936
14984
|
init_orchestrator_capable();
|
|
14937
14985
|
init_thread_store();
|
|
14986
|
+
init_worktree_runtime();
|
|
14938
14987
|
init_worktree_labels();
|
|
14939
14988
|
}
|
|
14940
14989
|
});
|
|
@@ -15194,7 +15243,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
15194
15243
|
const path2 = opts?.path ?? REVIEW_SKILL_PATH;
|
|
15195
15244
|
const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH || path2 === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
15196
15245
|
return {
|
|
15197
|
-
id: (0,
|
|
15246
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
15198
15247
|
name,
|
|
15199
15248
|
kind: "file",
|
|
15200
15249
|
path: path2,
|
|
@@ -15229,11 +15278,11 @@ async function requestReview(threadRef, send2) {
|
|
|
15229
15278
|
const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
|
|
15230
15279
|
return { tab: started, from };
|
|
15231
15280
|
}
|
|
15232
|
-
var
|
|
15281
|
+
var import_node_crypto9, import_node_fs38, import_node_path38, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
|
|
15233
15282
|
var init_request_review = __esm({
|
|
15234
15283
|
"src/review/request-review.ts"() {
|
|
15235
15284
|
"use strict";
|
|
15236
|
-
|
|
15285
|
+
import_node_crypto9 = require("crypto");
|
|
15237
15286
|
import_node_fs38 = require("fs");
|
|
15238
15287
|
import_node_path38 = require("path");
|
|
15239
15288
|
init_global_workspace();
|
|
@@ -18104,7 +18153,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
18104
18153
|
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
18105
18154
|
].join("\n");
|
|
18106
18155
|
return {
|
|
18107
|
-
id: (0,
|
|
18156
|
+
id: (0, import_node_crypto10.randomUUID)(),
|
|
18108
18157
|
name: "Orchestration quota handoff.md",
|
|
18109
18158
|
kind: "transcript",
|
|
18110
18159
|
content: body
|
|
@@ -18125,11 +18174,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
18125
18174
|
sourceType: "orchestration"
|
|
18126
18175
|
});
|
|
18127
18176
|
}
|
|
18128
|
-
var
|
|
18177
|
+
var import_node_crypto10, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
|
|
18129
18178
|
var init_quota_failover = __esm({
|
|
18130
18179
|
"src/orchestrator/quota-failover.ts"() {
|
|
18131
18180
|
"use strict";
|
|
18132
|
-
|
|
18181
|
+
import_node_crypto10 = require("crypto");
|
|
18133
18182
|
init_session_quota();
|
|
18134
18183
|
init_app_settings();
|
|
18135
18184
|
init_global_workspace();
|
|
@@ -20785,64 +20834,6 @@ var init_sync_branch = __esm({
|
|
|
20785
20834
|
}
|
|
20786
20835
|
});
|
|
20787
20836
|
|
|
20788
|
-
// src/integrations/github.ts
|
|
20789
|
-
var github_exports = {};
|
|
20790
|
-
__export(github_exports, {
|
|
20791
|
-
getGitHubStatus: () => getGitHubStatus,
|
|
20792
|
-
refreshGitHubAuth: () => refreshGitHubAuth
|
|
20793
|
-
});
|
|
20794
|
-
async function getGitHubStatus() {
|
|
20795
|
-
const which = await run("which", ["gh"], { reject: false });
|
|
20796
|
-
if (which.exitCode !== 0 || !which.stdout.trim()) {
|
|
20797
|
-
return {
|
|
20798
|
-
connected: false,
|
|
20799
|
-
login: null,
|
|
20800
|
-
hosts: [],
|
|
20801
|
-
reason: "gh CLI not found on PATH"
|
|
20802
|
-
};
|
|
20803
|
-
}
|
|
20804
|
-
const loginResult = await run(
|
|
20805
|
-
"gh",
|
|
20806
|
-
["api", "user", "--jq", ".login"],
|
|
20807
|
-
{ reject: false }
|
|
20808
|
-
);
|
|
20809
|
-
if (loginResult.exitCode === 0 && loginResult.stdout.trim()) {
|
|
20810
|
-
return {
|
|
20811
|
-
connected: true,
|
|
20812
|
-
login: loginResult.stdout.trim(),
|
|
20813
|
-
hosts: ["github.com"],
|
|
20814
|
-
reason: null
|
|
20815
|
-
};
|
|
20816
|
-
}
|
|
20817
|
-
const status = await run("gh", ["auth", "status"], { reject: false });
|
|
20818
|
-
const text7 = `${status.stdout}
|
|
20819
|
-
${status.stderr}`;
|
|
20820
|
-
const loginMatch = text7.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text7.match(/Logged in to ([^\s]+) as (\S+)/i);
|
|
20821
|
-
if (loginMatch) {
|
|
20822
|
-
return {
|
|
20823
|
-
connected: true,
|
|
20824
|
-
login: loginMatch[2].replace(/['"]/g, ""),
|
|
20825
|
-
hosts: [loginMatch[1]],
|
|
20826
|
-
reason: null
|
|
20827
|
-
};
|
|
20828
|
-
}
|
|
20829
|
-
return {
|
|
20830
|
-
connected: false,
|
|
20831
|
-
login: null,
|
|
20832
|
-
hosts: [],
|
|
20833
|
-
reason: status.stderr.trim() || status.stdout.trim() || "Not logged in to GitHub (run: gh auth login)"
|
|
20834
|
-
};
|
|
20835
|
-
}
|
|
20836
|
-
async function refreshGitHubAuth() {
|
|
20837
|
-
return getGitHubStatus();
|
|
20838
|
-
}
|
|
20839
|
-
var init_github = __esm({
|
|
20840
|
-
"src/integrations/github.ts"() {
|
|
20841
|
-
"use strict";
|
|
20842
|
-
init_run();
|
|
20843
|
-
}
|
|
20844
|
-
});
|
|
20845
|
-
|
|
20846
20837
|
// src/agents/cursor-store.ts
|
|
20847
20838
|
function cursorSdkStoreDir(threadId) {
|
|
20848
20839
|
const root = (0, import_node_path49.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
|
|
@@ -21109,6 +21100,7 @@ var init_orchestrator = __esm({
|
|
|
21109
21100
|
init_setup_last_error();
|
|
21110
21101
|
init_request_review();
|
|
21111
21102
|
init_fork_worktree();
|
|
21103
|
+
init_worktree_runtime();
|
|
21112
21104
|
init_quota_failover();
|
|
21113
21105
|
init_adopt();
|
|
21114
21106
|
init_stack_layers();
|
|
@@ -21907,21 +21899,11 @@ var init_orchestrator = __esm({
|
|
|
21907
21899
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
21908
21900
|
let renameBranchDirective = null;
|
|
21909
21901
|
if (!isBrightsy && !isOrchestration && autoRenameBranchEnabled2()) {
|
|
21910
|
-
const { isPlaceholderBranch: isPlaceholderBranch2 } = await Promise.resolve().then(() => (init_worktree_labels(), worktree_labels_exports));
|
|
21911
|
-
let githubLogin = null;
|
|
21912
|
-
if (isPlaceholderBranch2(fresh.branchName, fresh.worktreePath) && !gitBranchPrefixSetting2()) {
|
|
21913
|
-
try {
|
|
21914
|
-
const { getGitHubStatus: getGitHubStatus2 } = await Promise.resolve().then(() => (init_github(), github_exports));
|
|
21915
|
-
githubLogin = (await getGitHubStatus2()).login;
|
|
21916
|
-
} catch {
|
|
21917
|
-
}
|
|
21918
|
-
}
|
|
21919
21902
|
const { resolveGitBranchPrefix: resolveGitBranchPrefix2 } = await Promise.resolve().then(() => (init_branch_prefix(), branch_prefix_exports));
|
|
21920
21903
|
renameBranchDirective = formatRenameBranchDirective(fresh, {
|
|
21921
21904
|
customPrompt: settings?.prompts?.renameBranch,
|
|
21922
21905
|
branchPrefix: resolveGitBranchPrefix2({
|
|
21923
|
-
setting: gitBranchPrefixSetting2()
|
|
21924
|
-
githubLogin
|
|
21906
|
+
setting: gitBranchPrefixSetting2()
|
|
21925
21907
|
})
|
|
21926
21908
|
});
|
|
21927
21909
|
}
|
|
@@ -22284,22 +22266,25 @@ var init_orchestrator = __esm({
|
|
|
22284
22266
|
"No run script found for this worktree. Add [scripts.run.*] in the worktree\u2019s .sideboard/settings.toml or .conductor/settings.toml (or settings.local.toml on the main repo)."
|
|
22285
22267
|
);
|
|
22286
22268
|
}
|
|
22287
|
-
const
|
|
22288
|
-
const
|
|
22289
|
-
const
|
|
22269
|
+
const siblings = threadsSharingWorktree(thread.worktreePath);
|
|
22270
|
+
const shared = mergeWorktreeActiveRuns(siblings);
|
|
22271
|
+
const runKey = worktreeRunProcessKey(thread.worktreePath, resolvedName);
|
|
22272
|
+
const existing = this.processes.get(runKey) ?? siblings.map((t) => this.processes.get(`${t.id}:run:${resolvedName}`)).find(Boolean);
|
|
22273
|
+
const active = shared.activeRuns.find((r) => r.scriptName === resolvedName);
|
|
22290
22274
|
if (existing && active) {
|
|
22291
22275
|
return { port: active.port, scriptName: resolvedName, ports: active.ports };
|
|
22292
22276
|
}
|
|
22293
22277
|
if (!scriptName) {
|
|
22294
|
-
const legacy = this.processes.get(`${
|
|
22295
|
-
if (legacy &&
|
|
22296
|
-
return { port:
|
|
22278
|
+
const legacy = this.processes.get(worktreeDevProcessKey(thread.worktreePath)) ?? siblings.map((t) => this.processes.get(`${t.id}:dev`)).find(Boolean);
|
|
22279
|
+
if (legacy && shared.devPort) {
|
|
22280
|
+
return { port: shared.devPort, scriptName: resolvedName, ports: [shared.devPort] };
|
|
22297
22281
|
}
|
|
22298
22282
|
}
|
|
22299
22283
|
const mode = getRunMode(thread.worktreePath, thread.repoPath);
|
|
22300
22284
|
if (mode === "nonconcurrent") {
|
|
22285
|
+
const here = normalizeWorktreePath(thread.worktreePath);
|
|
22301
22286
|
for (const t of listThreads()) {
|
|
22302
|
-
if (t.
|
|
22287
|
+
if (normalizeWorktreePath(t.worktreePath) === here) continue;
|
|
22303
22288
|
const runs = t.activeRuns ?? [];
|
|
22304
22289
|
if (runs.length > 0 || t.devPort) {
|
|
22305
22290
|
throw new Error(
|
|
@@ -22334,7 +22319,7 @@ var init_orchestrator = __esm({
|
|
|
22334
22319
|
});
|
|
22335
22320
|
const isDefault = scripts.find((s) => s.default)?.name === resolvedName || !scripts.some((s) => s.default) && (resolvedName === "dev" || resolvedName === scripts[0]?.name);
|
|
22336
22321
|
if (isDefault) {
|
|
22337
|
-
this.processes.set(
|
|
22322
|
+
this.processes.set(worktreeDevProcessKey(thread.worktreePath), {
|
|
22338
22323
|
kind: "dev",
|
|
22339
22324
|
pid: handle.pid,
|
|
22340
22325
|
startedAt,
|
|
@@ -22349,13 +22334,14 @@ var init_orchestrator = __esm({
|
|
|
22349
22334
|
startedAt
|
|
22350
22335
|
};
|
|
22351
22336
|
const nextRuns = [
|
|
22352
|
-
...
|
|
22337
|
+
...shared.activeRuns.filter((r) => r.scriptName !== resolvedName),
|
|
22353
22338
|
run2
|
|
22354
22339
|
];
|
|
22355
|
-
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
|
|
22340
|
+
this.syncWorktreeRuns(
|
|
22341
|
+
thread.worktreePath,
|
|
22342
|
+
nextRuns,
|
|
22343
|
+
isDefault ? handle.port : shared.devPort
|
|
22344
|
+
);
|
|
22359
22345
|
this.emit({
|
|
22360
22346
|
type: "dev_server_started",
|
|
22361
22347
|
threadId: thread.id,
|
|
@@ -22364,15 +22350,14 @@ var init_orchestrator = __esm({
|
|
|
22364
22350
|
});
|
|
22365
22351
|
void handle.done.then(() => {
|
|
22366
22352
|
this.processes.delete(runKey);
|
|
22367
|
-
if (isDefault) this.processes.delete(
|
|
22368
|
-
const latest =
|
|
22369
|
-
const remaining =
|
|
22370
|
-
|
|
22353
|
+
if (isDefault) this.processes.delete(worktreeDevProcessKey(thread.worktreePath));
|
|
22354
|
+
const latest = mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath));
|
|
22355
|
+
const remaining = latest.activeRuns.filter((r) => r.scriptName !== resolvedName);
|
|
22356
|
+
this.syncWorktreeRuns(
|
|
22357
|
+
thread.worktreePath,
|
|
22358
|
+
remaining,
|
|
22359
|
+
isDefault ? null : latest.devPort
|
|
22371
22360
|
);
|
|
22372
|
-
updateThread(thread.id, {
|
|
22373
|
-
activeRuns: remaining,
|
|
22374
|
-
devPort: isDefault ? null : latest?.devPort ?? null
|
|
22375
|
-
});
|
|
22376
22361
|
this.emit({
|
|
22377
22362
|
type: "dev_server_stopped",
|
|
22378
22363
|
threadId: thread.id,
|
|
@@ -22383,51 +22368,82 @@ var init_orchestrator = __esm({
|
|
|
22383
22368
|
}
|
|
22384
22369
|
stopDev(threadRef, scriptName) {
|
|
22385
22370
|
const thread = this.requireThread(threadRef);
|
|
22371
|
+
const siblings = threadsSharingWorktree(thread.worktreePath);
|
|
22372
|
+
const shared = mergeWorktreeActiveRuns(siblings);
|
|
22386
22373
|
if (scriptName) {
|
|
22387
|
-
const
|
|
22388
|
-
|
|
22389
|
-
|
|
22390
|
-
|
|
22391
|
-
const
|
|
22392
|
-
|
|
22393
|
-
|
|
22394
|
-
|
|
22395
|
-
|
|
22396
|
-
|
|
22374
|
+
const keys = [
|
|
22375
|
+
worktreeRunProcessKey(thread.worktreePath, scriptName),
|
|
22376
|
+
...siblings.map((t) => `${t.id}:run:${scriptName}`)
|
|
22377
|
+
];
|
|
22378
|
+
for (const key of keys) {
|
|
22379
|
+
const proc = this.processes.get(key);
|
|
22380
|
+
if (proc) proc.kill();
|
|
22381
|
+
this.processes.delete(key);
|
|
22382
|
+
}
|
|
22383
|
+
const remaining = shared.activeRuns.filter((r) => r.scriptName !== scriptName);
|
|
22384
|
+
const isPrimary = shared.devPort != null && shared.activeRuns.find((r) => r.scriptName === scriptName)?.port === shared.devPort;
|
|
22385
|
+
this.syncWorktreeRuns(
|
|
22386
|
+
thread.worktreePath,
|
|
22387
|
+
remaining,
|
|
22388
|
+
isPrimary ? null : shared.devPort
|
|
22389
|
+
);
|
|
22397
22390
|
this.emit({ type: "dev_server_stopped", threadId: thread.id, scriptName });
|
|
22398
22391
|
return;
|
|
22399
22392
|
}
|
|
22400
22393
|
for (const [key, proc] of [...this.processes.entries()]) {
|
|
22401
|
-
if (key.startsWith(`${
|
|
22394
|
+
if (isWorktreeRunProcessKey(key, thread.worktreePath) || siblings.some((t) => key.startsWith(`${t.id}:run:`) || key === `${t.id}:dev`)) {
|
|
22402
22395
|
proc.kill();
|
|
22403
22396
|
this.processes.delete(key);
|
|
22404
22397
|
}
|
|
22405
22398
|
}
|
|
22406
|
-
|
|
22399
|
+
this.syncWorktreeRuns(thread.worktreePath, [], null);
|
|
22407
22400
|
this.emit({ type: "dev_server_stopped", threadId: thread.id });
|
|
22408
22401
|
}
|
|
22402
|
+
syncWorktreeRuns(worktreePath, activeRuns, devPort) {
|
|
22403
|
+
for (const sibling of threadsSharingWorktree(worktreePath)) {
|
|
22404
|
+
updateThread(sibling.id, { activeRuns, devPort });
|
|
22405
|
+
}
|
|
22406
|
+
}
|
|
22409
22407
|
listThreadRunScripts(threadRef) {
|
|
22410
22408
|
const thread = this.requireThread(threadRef);
|
|
22411
22409
|
return listRunScripts(thread.worktreePath, thread.repoPath);
|
|
22412
22410
|
}
|
|
22413
22411
|
getActiveRuns(threadRef) {
|
|
22414
|
-
|
|
22412
|
+
const thread = this.requireThread(threadRef);
|
|
22413
|
+
return mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath)).activeRuns;
|
|
22415
22414
|
}
|
|
22416
22415
|
getSetupLog(threadRef) {
|
|
22417
22416
|
const thread = this.getThread(threadRef);
|
|
22418
22417
|
if (!thread) return readSetupLog(threadRef);
|
|
22419
|
-
const
|
|
22420
|
-
|
|
22418
|
+
const siblingIds = [
|
|
22419
|
+
thread.id,
|
|
22420
|
+
...threadsSharingWorktree(thread.worktreePath).map((t) => t.id)
|
|
22421
|
+
];
|
|
22422
|
+
const snap = pickRichestSetupLog([
|
|
22423
|
+
readSetupLog(setupLogKeyForWorktree(thread.worktreePath)),
|
|
22424
|
+
...[...new Set(siblingIds)].map((id) => readSetupLog(id))
|
|
22425
|
+
]) ?? readSetupLog(thread.id);
|
|
22426
|
+
if (snap.running && !this.hasWorktreeSetupProcess(thread.worktreePath)) {
|
|
22421
22427
|
return { ...snap, running: false };
|
|
22422
22428
|
}
|
|
22423
22429
|
return snap;
|
|
22424
22430
|
}
|
|
22431
|
+
hasWorktreeSetupProcess(worktreePath) {
|
|
22432
|
+
if (this.processes.has(worktreeSetupProcessKey(worktreePath))) return true;
|
|
22433
|
+
return threadsSharingWorktree(worktreePath).some(
|
|
22434
|
+
(t) => this.processes.has(`${t.id}:setup`)
|
|
22435
|
+
);
|
|
22436
|
+
}
|
|
22437
|
+
writeSetupLog(threadId, worktreePath, fn) {
|
|
22438
|
+
fn(setupLogKeyForWorktree(worktreePath));
|
|
22439
|
+
fn(threadId);
|
|
22440
|
+
}
|
|
22425
22441
|
async runSetup(threadRef, opts) {
|
|
22426
22442
|
const thread = this.requireThread(threadRef);
|
|
22427
22443
|
this.assertNotGlobal(thread, "Setup");
|
|
22428
|
-
const key =
|
|
22429
|
-
if (this.
|
|
22430
|
-
throw new Error("Setup already running for this
|
|
22444
|
+
const key = worktreeSetupProcessKey(thread.worktreePath);
|
|
22445
|
+
if (this.hasWorktreeSetupProcess(thread.worktreePath)) {
|
|
22446
|
+
throw new Error("Setup already running for this worktree");
|
|
22431
22447
|
}
|
|
22432
22448
|
const abort = new AbortController();
|
|
22433
22449
|
this.processes.set(key, {
|
|
@@ -22435,13 +22451,17 @@ var init_orchestrator = __esm({
|
|
|
22435
22451
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22436
22452
|
kill: () => abort.abort()
|
|
22437
22453
|
});
|
|
22438
|
-
|
|
22454
|
+
this.writeSetupLog(thread.id, thread.worktreePath, beginSetupLog);
|
|
22439
22455
|
this.emit({ type: "setup_started", threadId: thread.id });
|
|
22440
22456
|
let finished = false;
|
|
22441
22457
|
const finish = (exitCode, source) => {
|
|
22442
22458
|
if (finished) return;
|
|
22443
22459
|
finished = true;
|
|
22444
|
-
|
|
22460
|
+
this.writeSetupLog(
|
|
22461
|
+
thread.id,
|
|
22462
|
+
thread.worktreePath,
|
|
22463
|
+
(logKey) => finishSetupLog(logKey, exitCode, source)
|
|
22464
|
+
);
|
|
22445
22465
|
this.emit({ type: "setup_finished", threadId: thread.id, exitCode });
|
|
22446
22466
|
};
|
|
22447
22467
|
try {
|
|
@@ -22449,14 +22469,22 @@ var init_orchestrator = __esm({
|
|
|
22449
22469
|
thread.repoPath,
|
|
22450
22470
|
thread.worktreePath,
|
|
22451
22471
|
(line) => {
|
|
22452
|
-
|
|
22472
|
+
this.writeSetupLog(
|
|
22473
|
+
thread.id,
|
|
22474
|
+
thread.worktreePath,
|
|
22475
|
+
(logKey) => appendSetupLog(logKey, line)
|
|
22476
|
+
);
|
|
22453
22477
|
this.emit({ type: "setup_output", threadId: thread.id, line });
|
|
22454
22478
|
},
|
|
22455
22479
|
{ signal: abort.signal }
|
|
22456
22480
|
);
|
|
22457
22481
|
if (!setup.ran) {
|
|
22458
22482
|
const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
|
|
22459
|
-
|
|
22483
|
+
this.writeSetupLog(
|
|
22484
|
+
thread.id,
|
|
22485
|
+
thread.worktreePath,
|
|
22486
|
+
(logKey) => appendSetupLog(logKey, line)
|
|
22487
|
+
);
|
|
22460
22488
|
this.emit({ type: "setup_output", threadId: thread.id, line });
|
|
22461
22489
|
finish(null, null);
|
|
22462
22490
|
throw new Error(line);
|
|
@@ -22484,8 +22512,14 @@ var init_orchestrator = __esm({
|
|
|
22484
22512
|
}
|
|
22485
22513
|
cancelSetup(threadRef) {
|
|
22486
22514
|
const thread = this.requireThread(threadRef);
|
|
22487
|
-
const
|
|
22488
|
-
|
|
22515
|
+
const keys = [
|
|
22516
|
+
worktreeSetupProcessKey(thread.worktreePath),
|
|
22517
|
+
...threadsSharingWorktree(thread.worktreePath).map((t) => `${t.id}:setup`)
|
|
22518
|
+
];
|
|
22519
|
+
for (const key of [...new Set(keys)]) {
|
|
22520
|
+
const proc = this.processes.get(key);
|
|
22521
|
+
if (proc) proc.kill();
|
|
22522
|
+
}
|
|
22489
22523
|
}
|
|
22490
22524
|
async applyIntoMain(threadRef, opts) {
|
|
22491
22525
|
const thread = this.requireThread(threadRef);
|
|
@@ -24162,7 +24196,54 @@ init_worktree();
|
|
|
24162
24196
|
init_stack();
|
|
24163
24197
|
init_branch_prefix();
|
|
24164
24198
|
init_agent_git_actions();
|
|
24165
|
-
|
|
24199
|
+
|
|
24200
|
+
// src/integrations/github.ts
|
|
24201
|
+
init_run();
|
|
24202
|
+
async function getGitHubStatus() {
|
|
24203
|
+
const which = await run("which", ["gh"], { reject: false });
|
|
24204
|
+
if (which.exitCode !== 0 || !which.stdout.trim()) {
|
|
24205
|
+
return {
|
|
24206
|
+
connected: false,
|
|
24207
|
+
login: null,
|
|
24208
|
+
hosts: [],
|
|
24209
|
+
reason: "gh CLI not found on PATH"
|
|
24210
|
+
};
|
|
24211
|
+
}
|
|
24212
|
+
const loginResult = await run(
|
|
24213
|
+
"gh",
|
|
24214
|
+
["api", "user", "--jq", ".login"],
|
|
24215
|
+
{ reject: false }
|
|
24216
|
+
);
|
|
24217
|
+
if (loginResult.exitCode === 0 && loginResult.stdout.trim()) {
|
|
24218
|
+
return {
|
|
24219
|
+
connected: true,
|
|
24220
|
+
login: loginResult.stdout.trim(),
|
|
24221
|
+
hosts: ["github.com"],
|
|
24222
|
+
reason: null
|
|
24223
|
+
};
|
|
24224
|
+
}
|
|
24225
|
+
const status = await run("gh", ["auth", "status"], { reject: false });
|
|
24226
|
+
const text7 = `${status.stdout}
|
|
24227
|
+
${status.stderr}`;
|
|
24228
|
+
const loginMatch = text7.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text7.match(/Logged in to ([^\s]+) as (\S+)/i);
|
|
24229
|
+
if (loginMatch) {
|
|
24230
|
+
return {
|
|
24231
|
+
connected: true,
|
|
24232
|
+
login: loginMatch[2].replace(/['"]/g, ""),
|
|
24233
|
+
hosts: [loginMatch[1]],
|
|
24234
|
+
reason: null
|
|
24235
|
+
};
|
|
24236
|
+
}
|
|
24237
|
+
return {
|
|
24238
|
+
connected: false,
|
|
24239
|
+
login: null,
|
|
24240
|
+
hosts: [],
|
|
24241
|
+
reason: status.stderr.trim() || status.stdout.trim() || "Not logged in to GitHub (run: gh auth login)"
|
|
24242
|
+
};
|
|
24243
|
+
}
|
|
24244
|
+
async function refreshGitHubAuth() {
|
|
24245
|
+
return getGitHubStatus();
|
|
24246
|
+
}
|
|
24166
24247
|
|
|
24167
24248
|
// src/integrations/linear.ts
|
|
24168
24249
|
init_fetch();
|
|
@@ -24238,7 +24319,7 @@ function issueActivityKind(issue, sinceIso) {
|
|
|
24238
24319
|
}
|
|
24239
24320
|
|
|
24240
24321
|
// src/integrations/linear-oauth.ts
|
|
24241
|
-
var
|
|
24322
|
+
var import_node_crypto11 = require("crypto");
|
|
24242
24323
|
var import_node_http = require("http");
|
|
24243
24324
|
init_app_settings();
|
|
24244
24325
|
init_fetch();
|
|
@@ -24270,8 +24351,8 @@ function linearOAuthCredentials() {
|
|
|
24270
24351
|
return { clientId, clientSecret };
|
|
24271
24352
|
}
|
|
24272
24353
|
function createLinearPkce() {
|
|
24273
|
-
const verifier = (0,
|
|
24274
|
-
const challenge = (0,
|
|
24354
|
+
const verifier = (0, import_node_crypto11.randomBytes)(32).toString("base64url");
|
|
24355
|
+
const challenge = (0, import_node_crypto11.createHash)("sha256").update(verifier).digest("base64url");
|
|
24275
24356
|
return { verifier, challenge };
|
|
24276
24357
|
}
|
|
24277
24358
|
function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
|
|
@@ -24402,7 +24483,7 @@ async function startLinearOAuth(opts) {
|
|
|
24402
24483
|
throw new LinearOAuthCancelledError();
|
|
24403
24484
|
}
|
|
24404
24485
|
const { clientId, clientSecret } = linearOAuthCredentials();
|
|
24405
|
-
const state = (0,
|
|
24486
|
+
const state = (0, import_node_crypto11.randomBytes)(16).toString("hex");
|
|
24406
24487
|
const pkce = createLinearPkce();
|
|
24407
24488
|
const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
|
|
24408
24489
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
@@ -26255,7 +26336,7 @@ function buildPathRefAttachment(input) {
|
|
|
26255
26336
|
init_stage_files();
|
|
26256
26337
|
|
|
26257
26338
|
// src/composer/pasted-text.ts
|
|
26258
|
-
var
|
|
26339
|
+
var import_node_crypto12 = require("crypto");
|
|
26259
26340
|
var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
26260
26341
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
26261
26342
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
@@ -26282,7 +26363,7 @@ function nextPastedTextName(existing) {
|
|
|
26282
26363
|
}
|
|
26283
26364
|
function buildPastedTextAttachment(text7, opts) {
|
|
26284
26365
|
return {
|
|
26285
|
-
id: opts?.id ?? (0,
|
|
26366
|
+
id: opts?.id ?? (0, import_node_crypto12.randomUUID)(),
|
|
26286
26367
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
26287
26368
|
kind: "file",
|
|
26288
26369
|
path: opts?.path,
|
|
@@ -26436,7 +26517,7 @@ init_orphan_cleanup();
|
|
|
26436
26517
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
26437
26518
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
26438
26519
|
var import_zod9 = require("zod");
|
|
26439
|
-
var
|
|
26520
|
+
var import_node_crypto14 = require("crypto");
|
|
26440
26521
|
var import_node_path52 = require("path");
|
|
26441
26522
|
init_orchestrator();
|
|
26442
26523
|
init_worktree();
|
|
@@ -28163,7 +28244,7 @@ init_worktree();
|
|
|
28163
28244
|
init_paths();
|
|
28164
28245
|
|
|
28165
28246
|
// src/board/board-pins.ts
|
|
28166
|
-
var
|
|
28247
|
+
var import_node_crypto13 = require("crypto");
|
|
28167
28248
|
var import_node_fs54 = require("fs");
|
|
28168
28249
|
var import_node_path50 = require("path");
|
|
28169
28250
|
init_paths();
|
|
@@ -28195,7 +28276,7 @@ function addBoardPin(input) {
|
|
|
28195
28276
|
const ref = input.ref.trim();
|
|
28196
28277
|
if (!ref) throw new Error("Board item needs a ref");
|
|
28197
28278
|
const pin = {
|
|
28198
|
-
id: (0,
|
|
28279
|
+
id: (0, import_node_crypto13.randomUUID)(),
|
|
28199
28280
|
kind: input.kind,
|
|
28200
28281
|
ref,
|
|
28201
28282
|
repoPath: input.repoPath.trim(),
|
|
@@ -28440,7 +28521,6 @@ async function getHomeBoardInputs(workspaces, opts) {
|
|
|
28440
28521
|
|
|
28441
28522
|
// src/mcp/server.ts
|
|
28442
28523
|
init_home_board();
|
|
28443
|
-
init_github();
|
|
28444
28524
|
|
|
28445
28525
|
// src/mcp/create-thread-agent.ts
|
|
28446
28526
|
init_cursor();
|
|
@@ -29030,7 +29110,7 @@ async function startMcpServer() {
|
|
|
29030
29110
|
const ident = issue?.identifier ?? ref.trim();
|
|
29031
29111
|
const attachments = issue ? [
|
|
29032
29112
|
{
|
|
29033
|
-
id: (0,
|
|
29113
|
+
id: (0, import_node_crypto14.randomUUID)(),
|
|
29034
29114
|
name: issue.identifier,
|
|
29035
29115
|
kind: "issue",
|
|
29036
29116
|
content: [
|
|
@@ -29985,7 +30065,7 @@ init_orch_mcp_isolation();
|
|
|
29985
30065
|
init_workspaces2();
|
|
29986
30066
|
|
|
29987
30067
|
// src/slack/oauth.ts
|
|
29988
|
-
var
|
|
30068
|
+
var import_node_crypto15 = require("crypto");
|
|
29989
30069
|
init_app_settings();
|
|
29990
30070
|
init_workspaces2();
|
|
29991
30071
|
|
|
@@ -30209,7 +30289,7 @@ async function startSlackOAuth(opts) {
|
|
|
30209
30289
|
throw new SlackOAuthCancelledError();
|
|
30210
30290
|
}
|
|
30211
30291
|
const { clientId } = slackOAuthCredentials();
|
|
30212
|
-
const state = (0,
|
|
30292
|
+
const state = (0, import_node_crypto15.randomBytes)(16).toString("hex");
|
|
30213
30293
|
const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
|
|
30214
30294
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
30215
30295
|
const pollIntervalMs = opts?.pollIntervalMs ?? 400;
|
|
@@ -30491,7 +30571,7 @@ init_workspaces2();
|
|
|
30491
30571
|
init_reply_target();
|
|
30492
30572
|
|
|
30493
30573
|
// src/slack/relay-protocol.ts
|
|
30494
|
-
var
|
|
30574
|
+
var import_node_crypto16 = require("crypto");
|
|
30495
30575
|
var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
|
|
30496
30576
|
var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
|
|
30497
30577
|
function slackRelaySessionKey(teamId, userId, deviceId) {
|
|
@@ -30501,7 +30581,7 @@ function slackRelayUserKey(teamId, userId) {
|
|
|
30501
30581
|
return `${teamId.trim()}:${userId.trim()}`;
|
|
30502
30582
|
}
|
|
30503
30583
|
function newSlackRelayEventId() {
|
|
30504
|
-
return (0,
|
|
30584
|
+
return (0, import_node_crypto16.randomBytes)(12).toString("hex");
|
|
30505
30585
|
}
|
|
30506
30586
|
function parseSlackRelayClientMessage(raw) {
|
|
30507
30587
|
try {
|