whipped 0.1.0 → 0.1.2
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/cli.js +26 -20
- package/dist/web-ui/assets/{index-rpsRpaUU.js → index-BOR6PC8f.js} +1663 -1598
- package/dist/web-ui/index.html +1 -1
- package/package.json +14 -25
|
@@ -27169,389 +27169,953 @@ const ZodIssueCode = {
|
|
|
27169
27169
|
function number$1(params) {
|
|
27170
27170
|
return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
|
|
27171
27171
|
}
|
|
27172
|
-
const
|
|
27173
|
-
|
|
27174
|
-
|
|
27175
|
-
|
|
27172
|
+
const runtimeAgentIdSchema = _enum(["claude", "codex", "opencode", "cursor"]);
|
|
27173
|
+
const AGENT_BINARY_OPTIONS = [
|
|
27174
|
+
{ value: "claude", label: "claude" },
|
|
27175
|
+
{ value: "codex", label: "codex" },
|
|
27176
|
+
{ value: "opencode", label: "opencode" },
|
|
27177
|
+
{ value: "cursor", label: "cursor" }
|
|
27178
|
+
];
|
|
27179
|
+
const effortLevelSchema = _enum(["low", "medium", "high", "xhigh", "max"]);
|
|
27180
|
+
const EFFORT_OPTIONS = [
|
|
27181
|
+
{ value: "low", label: "Low" },
|
|
27182
|
+
{ value: "medium", label: "Medium" },
|
|
27183
|
+
{ value: "high", label: "High" },
|
|
27184
|
+
{ value: "xhigh", label: "Extra High" },
|
|
27185
|
+
{ value: "max", label: "Max" }
|
|
27186
|
+
];
|
|
27187
|
+
const MODEL_OPTIONS = {
|
|
27188
|
+
claude: [
|
|
27189
|
+
{ value: "claude-opus-4-8", label: "Opus 4.8" },
|
|
27190
|
+
{ value: "claude-opus-4-7", label: "Opus 4.7" },
|
|
27191
|
+
{ value: "claude-opus-4-6", label: "Opus 4.6" },
|
|
27192
|
+
{ value: "claude-sonnet-4-6", label: "Sonnet 4.6" },
|
|
27193
|
+
{ value: "claude-sonnet-4-5", label: "Sonnet 4.5" },
|
|
27194
|
+
{ value: "claude-haiku-4-5", label: "Haiku 4.5" }
|
|
27195
|
+
],
|
|
27196
|
+
codex: [
|
|
27197
|
+
{ value: "gpt-5.5", label: "GPT-5.5 (default)" },
|
|
27198
|
+
{ value: "gpt-5.4", label: "GPT-5.4" },
|
|
27199
|
+
{ value: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
|
|
27200
|
+
{ value: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
|
|
27201
|
+
{ value: "gpt-5.2", label: "GPT-5.2" }
|
|
27202
|
+
],
|
|
27203
|
+
// opencode supports any provider/model string — no fixed presets.
|
|
27204
|
+
// The UI renders a free-form text input for opencode model selection.
|
|
27205
|
+
opencode: [],
|
|
27206
|
+
// cursor supports many models — no fixed presets.
|
|
27207
|
+
// The UI fetches the live list via agents.cursorModels and renders a Select.
|
|
27208
|
+
cursor: []
|
|
27209
|
+
};
|
|
27210
|
+
const agentModelChoiceSchema = object({
|
|
27211
|
+
agentId: runtimeAgentIdSchema.default("claude"),
|
|
27212
|
+
model: string$2().nullable().optional(),
|
|
27213
|
+
effort: effortLevelSchema.nullable().optional()
|
|
27176
27214
|
});
|
|
27177
|
-
|
|
27178
|
-
|
|
27179
|
-
|
|
27180
|
-
|
|
27181
|
-
|
|
27182
|
-
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27186
|
-
}
|
|
27187
|
-
|
|
27188
|
-
|
|
27189
|
-
|
|
27190
|
-
|
|
27191
|
-
|
|
27192
|
-
|
|
27193
|
-
|
|
27194
|
-
|
|
27195
|
-
|
|
27196
|
-
|
|
27197
|
-
|
|
27198
|
-
}
|
|
27199
|
-
|
|
27200
|
-
|
|
27201
|
-
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
|
|
27205
|
-
|
|
27206
|
-
|
|
27207
|
-
|
|
27208
|
-
|
|
27209
|
-
}
|
|
27210
|
-
|
|
27211
|
-
|
|
27212
|
-
|
|
27213
|
-
|
|
27214
|
-
|
|
27215
|
-
|
|
27216
|
-
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27221
|
-
if (body instanceof Blob) return false;
|
|
27222
|
-
if (body instanceof ArrayBuffer) return false;
|
|
27223
|
-
if (body instanceof URLSearchParams) return false;
|
|
27224
|
-
if (body instanceof ReadableStream) return false;
|
|
27225
|
-
if (typeof body === "string") return false;
|
|
27226
|
-
if (typeof body === "object") {
|
|
27227
|
-
return true;
|
|
27228
|
-
}
|
|
27229
|
-
return false;
|
|
27230
|
-
}
|
|
27231
|
-
async function resolveHeaders(headers) {
|
|
27232
|
-
if (!headers) return void 0;
|
|
27233
|
-
if (typeof headers === "function") {
|
|
27234
|
-
return await headers();
|
|
27235
|
-
}
|
|
27236
|
-
return headers;
|
|
27237
|
-
}
|
|
27238
|
-
function headersInitToRecord(headers) {
|
|
27239
|
-
return Object.fromEntries(new Headers(headers));
|
|
27240
|
-
}
|
|
27241
|
-
async function resolveHeadersToRecord(headers) {
|
|
27242
|
-
const resolved = await resolveHeaders(headers);
|
|
27243
|
-
if (!resolved) return {};
|
|
27244
|
-
return headersInitToRecord(resolved);
|
|
27245
|
-
}
|
|
27246
|
-
async function mergeHeaders(defaultHeaders, requestHeaders) {
|
|
27247
|
-
const resolved1 = await resolveHeaders(defaultHeaders);
|
|
27248
|
-
const resolved2 = await resolveHeaders(requestHeaders);
|
|
27249
|
-
if (!resolved1 && !resolved2) return void 0;
|
|
27250
|
-
if (!resolved1) return resolved2;
|
|
27251
|
-
if (!resolved2) return resolved1;
|
|
27252
|
-
return {
|
|
27253
|
-
...Object.fromEntries(new Headers(resolved1)),
|
|
27254
|
-
...Object.fromEntries(new Headers(resolved2))
|
|
27255
|
-
};
|
|
27256
|
-
}
|
|
27257
|
-
function removeHeaderKeys(headers, keysToRemove) {
|
|
27258
|
-
if (!headers) return void 0;
|
|
27259
|
-
const headersObj = new Headers(headers);
|
|
27260
|
-
for (const key of keysToRemove) {
|
|
27261
|
-
headersObj.delete(key);
|
|
27262
|
-
}
|
|
27263
|
-
const entries = [...headersObj.entries()];
|
|
27264
|
-
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
27265
|
-
}
|
|
27266
|
-
function objectToFormData(obj) {
|
|
27267
|
-
const formData = new FormData();
|
|
27268
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
27269
|
-
if (value === null || value === void 0) {
|
|
27270
|
-
continue;
|
|
27271
|
-
}
|
|
27272
|
-
if (value instanceof Blob || value instanceof File) {
|
|
27273
|
-
formData.append(key, value);
|
|
27274
|
-
} else if (Array.isArray(value)) {
|
|
27275
|
-
for (const entry of value) {
|
|
27276
|
-
if (entry instanceof Blob || entry instanceof File) {
|
|
27277
|
-
formData.append(key, entry);
|
|
27278
|
-
} else if (typeof entry === "object" && entry !== null) {
|
|
27279
|
-
formData.append(key, JSON.stringify(entry));
|
|
27280
|
-
} else {
|
|
27281
|
-
formData.append(key, String(entry));
|
|
27282
|
-
}
|
|
27283
|
-
}
|
|
27284
|
-
} else if (typeof value === "object") {
|
|
27285
|
-
formData.append(key, JSON.stringify(value));
|
|
27286
|
-
} else {
|
|
27287
|
-
formData.append(key, String(value));
|
|
27288
|
-
}
|
|
27289
|
-
}
|
|
27290
|
-
return formData;
|
|
27291
|
-
}
|
|
27292
|
-
function objectToUrlEncoded(obj) {
|
|
27293
|
-
const params = new URLSearchParams();
|
|
27294
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
27295
|
-
if (value === void 0 || value === null) {
|
|
27296
|
-
continue;
|
|
27297
|
-
}
|
|
27298
|
-
if (Array.isArray(value)) {
|
|
27299
|
-
for (const item of value) {
|
|
27300
|
-
if (item !== void 0 && item !== null) {
|
|
27301
|
-
params.append(key, String(item));
|
|
27302
|
-
}
|
|
27303
|
-
}
|
|
27304
|
-
} else if (typeof value === "object") {
|
|
27305
|
-
params.append(key, JSON.stringify(value));
|
|
27306
|
-
} else {
|
|
27307
|
-
params.append(key, String(value));
|
|
27308
|
-
}
|
|
27309
|
-
}
|
|
27310
|
-
return params.toString();
|
|
27311
|
-
}
|
|
27312
|
-
function sortObjectKeys(obj, seen2 = /* @__PURE__ */ new WeakSet()) {
|
|
27313
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
27314
|
-
if (seen2.has(obj)) {
|
|
27315
|
-
return "[Circular]";
|
|
27316
|
-
}
|
|
27317
|
-
seen2.add(obj);
|
|
27318
|
-
if (Array.isArray(obj)) {
|
|
27319
|
-
return obj.map((item) => sortObjectKeys(item, seen2));
|
|
27320
|
-
}
|
|
27321
|
-
return Object.keys(obj).sort().reduce(
|
|
27322
|
-
(sorted, key) => {
|
|
27323
|
-
sorted[key] = sortObjectKeys(
|
|
27324
|
-
obj[key],
|
|
27325
|
-
seen2
|
|
27326
|
-
);
|
|
27327
|
-
return sorted;
|
|
27328
|
-
},
|
|
27329
|
-
{}
|
|
27330
|
-
);
|
|
27331
|
-
}
|
|
27332
|
-
function isSpooshBody(value) {
|
|
27333
|
-
return typeof value === "object" && value !== null && "__spooshBody" in value && value.__spooshBody === true;
|
|
27334
|
-
}
|
|
27335
|
-
function resolveRequestBody(rawBody) {
|
|
27336
|
-
if (rawBody === void 0 || rawBody === null) {
|
|
27337
|
-
return void 0;
|
|
27338
|
-
}
|
|
27339
|
-
if (isSpooshBody(rawBody)) {
|
|
27340
|
-
const body = rawBody;
|
|
27341
|
-
switch (body.kind) {
|
|
27342
|
-
case "form":
|
|
27343
|
-
return {
|
|
27344
|
-
body: objectToFormData(body.value),
|
|
27345
|
-
removeHeaders: ["Content-Type"]
|
|
27346
|
-
};
|
|
27347
|
-
case "json":
|
|
27348
|
-
return {
|
|
27349
|
-
body: JSON.stringify(body.value),
|
|
27350
|
-
headers: { "Content-Type": "application/json" }
|
|
27351
|
-
};
|
|
27352
|
-
case "urlencoded":
|
|
27353
|
-
return {
|
|
27354
|
-
body: objectToUrlEncoded(body.value),
|
|
27355
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
27356
|
-
};
|
|
27357
|
-
}
|
|
27358
|
-
}
|
|
27359
|
-
if (isJsonBody(rawBody)) {
|
|
27360
|
-
if (__DEV__() && containsFile(rawBody)) {
|
|
27361
|
-
console.warn(
|
|
27362
|
-
"[spoosh] Plain object body contains File/Blob. Use form() wrapper for multipart upload."
|
|
27363
|
-
);
|
|
27364
|
-
}
|
|
27365
|
-
return {
|
|
27366
|
-
body: JSON.stringify(rawBody),
|
|
27367
|
-
headers: { "Content-Type": "application/json" }
|
|
27368
|
-
};
|
|
27369
|
-
}
|
|
27370
|
-
if (rawBody instanceof FormData) {
|
|
27371
|
-
return { body: rawBody, removeHeaders: ["Content-Type"] };
|
|
27372
|
-
}
|
|
27373
|
-
return { body: rawBody };
|
|
27374
|
-
}
|
|
27375
|
-
function normalizeTag$1(tag) {
|
|
27376
|
-
return tag.startsWith("/") ? tag.slice(1) : tag;
|
|
27377
|
-
}
|
|
27378
|
-
function matchTag(entryTag, pattern) {
|
|
27379
|
-
const normalizedTag = normalizeTag$1(entryTag);
|
|
27380
|
-
const normalizedPattern = normalizeTag$1(pattern);
|
|
27381
|
-
if (normalizedPattern.endsWith("/*")) {
|
|
27382
|
-
const prefix2 = normalizedPattern.slice(0, -2);
|
|
27383
|
-
return prefix2 === "" ? normalizedTag.length > 0 : normalizedTag.startsWith(prefix2 + "/");
|
|
27384
|
-
}
|
|
27385
|
-
return normalizedTag === normalizedPattern;
|
|
27386
|
-
}
|
|
27387
|
-
function matchTags(entryTag, patterns) {
|
|
27388
|
-
return patterns.some((pattern) => matchTag(entryTag, pattern));
|
|
27389
|
-
}
|
|
27390
|
-
function resolveTags(options, resolvedPath) {
|
|
27391
|
-
const tagsOption = options == null ? void 0 : options.tags;
|
|
27392
|
-
if (!tagsOption) {
|
|
27393
|
-
const tag2 = resolvedPath.join("/");
|
|
27394
|
-
return tag2 ? [normalizeTag$1(tag2)] : [];
|
|
27395
|
-
}
|
|
27396
|
-
if (typeof tagsOption === "string") {
|
|
27397
|
-
return [normalizeTag$1(tagsOption)];
|
|
27398
|
-
}
|
|
27399
|
-
if (Array.isArray(tagsOption)) {
|
|
27400
|
-
return [...new Set(tagsOption.map(normalizeTag$1))];
|
|
27401
|
-
}
|
|
27402
|
-
const tag = resolvedPath.join("/");
|
|
27403
|
-
return tag ? [normalizeTag$1(tag)] : [];
|
|
27404
|
-
}
|
|
27405
|
-
function resolvePath(path2, params) {
|
|
27406
|
-
if (!params) return path2;
|
|
27407
|
-
return path2.map((segment) => {
|
|
27408
|
-
if (segment.startsWith(":")) {
|
|
27409
|
-
const paramName = segment.slice(1);
|
|
27410
|
-
const value = params[paramName];
|
|
27411
|
-
if (value === void 0) {
|
|
27412
|
-
throw new Error(`Missing path parameter: ${paramName}`);
|
|
27413
|
-
}
|
|
27414
|
-
return String(value);
|
|
27415
|
-
}
|
|
27416
|
-
return segment;
|
|
27417
|
-
});
|
|
27418
|
-
}
|
|
27419
|
-
function resolvePathString(path2, params) {
|
|
27420
|
-
if (!params) return path2;
|
|
27421
|
-
return path2.split("/").map((segment) => {
|
|
27422
|
-
if (segment.startsWith(":")) {
|
|
27423
|
-
const paramName = segment.slice(1);
|
|
27424
|
-
const value = params[paramName];
|
|
27425
|
-
return value !== void 0 ? String(value) : segment;
|
|
27426
|
-
}
|
|
27427
|
-
return segment;
|
|
27428
|
-
}).join("/");
|
|
27429
|
-
}
|
|
27430
|
-
var isAbortError = (err) => err instanceof DOMException && err.name === "AbortError";
|
|
27431
|
-
var fetchTransport = async (url, init) => {
|
|
27432
|
-
const res = await fetch(url, init);
|
|
27433
|
-
const contentType = res.headers.get("content-type");
|
|
27434
|
-
const isJson = contentType == null ? void 0 : contentType.includes("application/json");
|
|
27435
|
-
const isText = (contentType == null ? void 0 : contentType.includes("text/")) || (contentType == null ? void 0 : contentType.includes("application/xml"));
|
|
27436
|
-
let data;
|
|
27437
|
-
if (isJson) {
|
|
27438
|
-
data = await res.json();
|
|
27439
|
-
} else if (isText) {
|
|
27440
|
-
data = await res.text();
|
|
27441
|
-
} else {
|
|
27442
|
-
data = void 0;
|
|
27215
|
+
const DEFAULT_AGENT_MODEL_CHOICE = { agentId: "claude", model: null, effort: null };
|
|
27216
|
+
const workflowSlotTypeSchema = _enum(["dev", "review", "plan", "orch"]);
|
|
27217
|
+
const tierLevelSchema = _enum(["minimal", "low", "medium", "high", "max"]);
|
|
27218
|
+
const LEVEL_ORDER = ["minimal", "low", "medium", "high", "max"];
|
|
27219
|
+
const TIER_LEVEL_OPTIONS = [
|
|
27220
|
+
{ value: "minimal", label: "Minimal" },
|
|
27221
|
+
{ value: "low", label: "Low" },
|
|
27222
|
+
{ value: "medium", label: "Medium" },
|
|
27223
|
+
{ value: "high", label: "High" },
|
|
27224
|
+
{ value: "max", label: "Max" }
|
|
27225
|
+
];
|
|
27226
|
+
const modelPairSchema = object({
|
|
27227
|
+
id: string$2(),
|
|
27228
|
+
level: tierLevelSchema,
|
|
27229
|
+
isFree: boolean$1().default(false),
|
|
27230
|
+
binary: runtimeAgentIdSchema,
|
|
27231
|
+
model: string$2().nullable().optional(),
|
|
27232
|
+
effort: effortLevelSchema.nullable().optional()
|
|
27233
|
+
});
|
|
27234
|
+
const pairSelectionModeSchema = _enum(["auto", "preferFree", "freeOnly", "paidOnly"]);
|
|
27235
|
+
const PAIR_SELECTION_MODE_OPTIONS = [
|
|
27236
|
+
{ value: "auto", label: "Auto (priority)" },
|
|
27237
|
+
{ value: "preferFree", label: "Prefer free" },
|
|
27238
|
+
{ value: "freeOnly", label: "Free only" },
|
|
27239
|
+
{ value: "paidOnly", label: "Paid only" }
|
|
27240
|
+
];
|
|
27241
|
+
const SLOT_TOOL_IDS = ["browser"];
|
|
27242
|
+
const slotToolSchema = _enum(SLOT_TOOL_IDS);
|
|
27243
|
+
const slotModelConfigSchema = object({
|
|
27244
|
+
pairs: array(modelPairSchema).min(1),
|
|
27245
|
+
mode: pairSelectionModeSchema.default("auto"),
|
|
27246
|
+
pinnedPairId: string$2().optional()
|
|
27247
|
+
});
|
|
27248
|
+
const cardModelConfigSchema = record(string$2(), slotModelConfigSchema);
|
|
27249
|
+
function pickByMode(candidates, mode) {
|
|
27250
|
+
switch (mode) {
|
|
27251
|
+
case "preferFree":
|
|
27252
|
+
return candidates.find((p) => p.isFree) ?? candidates[0];
|
|
27253
|
+
case "freeOnly":
|
|
27254
|
+
return candidates.find((p) => p.isFree);
|
|
27255
|
+
case "paidOnly":
|
|
27256
|
+
return candidates.find((p) => !p.isFree);
|
|
27257
|
+
default:
|
|
27258
|
+
return candidates[0];
|
|
27443
27259
|
}
|
|
27444
|
-
return { ok: res.ok, status: res.status, headers: res.headers, data };
|
|
27445
|
-
};
|
|
27446
|
-
var xhrTransport = (url, init, options) => {
|
|
27447
|
-
return new Promise((resolve, reject) => {
|
|
27448
|
-
const xhr = new XMLHttpRequest();
|
|
27449
|
-
xhr.open(init.method ?? "GET", url);
|
|
27450
|
-
if (init.headers) {
|
|
27451
|
-
const headers = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
|
|
27452
|
-
headers.forEach((value, key) => {
|
|
27453
|
-
xhr.setRequestHeader(key, value);
|
|
27454
|
-
});
|
|
27455
|
-
}
|
|
27456
|
-
if (init.credentials === "include") {
|
|
27457
|
-
xhr.withCredentials = true;
|
|
27458
|
-
}
|
|
27459
|
-
const onAbort = () => xhr.abort();
|
|
27460
|
-
if (init.signal) {
|
|
27461
|
-
if (init.signal.aborted) {
|
|
27462
|
-
xhr.abort();
|
|
27463
|
-
return;
|
|
27464
|
-
}
|
|
27465
|
-
init.signal.addEventListener("abort", onAbort);
|
|
27466
|
-
}
|
|
27467
|
-
const cleanup = () => {
|
|
27468
|
-
var _a3;
|
|
27469
|
-
(_a3 = init.signal) == null ? void 0 : _a3.removeEventListener("abort", onAbort);
|
|
27470
|
-
};
|
|
27471
|
-
if (options == null ? void 0 : options.onProgress) {
|
|
27472
|
-
xhr.upload.addEventListener("progress", (event) => {
|
|
27473
|
-
options.onProgress(event, xhr);
|
|
27474
|
-
});
|
|
27475
|
-
xhr.addEventListener("progress", (event) => {
|
|
27476
|
-
options.onProgress(event, xhr);
|
|
27477
|
-
});
|
|
27478
|
-
}
|
|
27479
|
-
xhr.addEventListener("load", () => {
|
|
27480
|
-
cleanup();
|
|
27481
|
-
const status = xhr.status;
|
|
27482
|
-
const ok2 = status >= 200 && status < 300;
|
|
27483
|
-
const responseHeaders = new Headers();
|
|
27484
|
-
const rawHeaders = xhr.getAllResponseHeaders().trim();
|
|
27485
|
-
if (rawHeaders) {
|
|
27486
|
-
rawHeaders.split("\r\n").forEach((line) => {
|
|
27487
|
-
const idx = line.indexOf(": ");
|
|
27488
|
-
if (idx > 0) {
|
|
27489
|
-
responseHeaders.append(
|
|
27490
|
-
line.substring(0, idx),
|
|
27491
|
-
line.substring(idx + 2)
|
|
27492
|
-
);
|
|
27493
|
-
}
|
|
27494
|
-
});
|
|
27495
|
-
}
|
|
27496
|
-
const contentType = responseHeaders.get("content-type");
|
|
27497
|
-
const isJson = contentType == null ? void 0 : contentType.includes("application/json");
|
|
27498
|
-
let data;
|
|
27499
|
-
try {
|
|
27500
|
-
data = isJson ? JSON.parse(xhr.responseText) : xhr.responseText;
|
|
27501
|
-
} catch {
|
|
27502
|
-
data = xhr.responseText;
|
|
27503
|
-
}
|
|
27504
|
-
resolve({ ok: ok2, status, headers: responseHeaders, data });
|
|
27505
|
-
});
|
|
27506
|
-
xhr.addEventListener("error", () => {
|
|
27507
|
-
cleanup();
|
|
27508
|
-
reject(new TypeError("Network request failed"));
|
|
27509
|
-
});
|
|
27510
|
-
xhr.addEventListener("abort", () => {
|
|
27511
|
-
cleanup();
|
|
27512
|
-
reject(new DOMException("Aborted", "AbortError"));
|
|
27513
|
-
});
|
|
27514
|
-
xhr.send(init.body);
|
|
27515
|
-
});
|
|
27516
|
-
};
|
|
27517
|
-
async function executeFetch(baseUrl, path2, method, defaultOptions2, requestOptions, nextTags) {
|
|
27518
|
-
return executeCoreFetch({
|
|
27519
|
-
baseUrl,
|
|
27520
|
-
path: path2,
|
|
27521
|
-
method,
|
|
27522
|
-
defaultOptions: defaultOptions2,
|
|
27523
|
-
requestOptions,
|
|
27524
|
-
middlewareFetchInit: void 0,
|
|
27525
|
-
nextTags
|
|
27526
|
-
});
|
|
27527
27260
|
}
|
|
27528
|
-
function
|
|
27529
|
-
|
|
27530
|
-
|
|
27531
|
-
|
|
27532
|
-
}
|
|
27533
|
-
if ((requestOptions == null ? void 0 : requestOptions.body) !== void 0) {
|
|
27534
|
-
fields.body = requestOptions.body;
|
|
27261
|
+
function resolvePair(cfg, activeLevel) {
|
|
27262
|
+
if (cfg.pinnedPairId) {
|
|
27263
|
+
const pinned = cfg.pairs.find((p) => p.id === cfg.pinnedPairId);
|
|
27264
|
+
if (pinned) return pinned;
|
|
27535
27265
|
}
|
|
27536
|
-
|
|
27537
|
-
|
|
27266
|
+
const startIdx = LEVEL_ORDER.indexOf(activeLevel);
|
|
27267
|
+
const order2 = [];
|
|
27268
|
+
for (let i2 = startIdx; i2 < LEVEL_ORDER.length; i2++) order2.push(i2);
|
|
27269
|
+
for (let i2 = startIdx - 1; i2 >= 0; i2--) order2.push(i2);
|
|
27270
|
+
for (const i2 of order2) {
|
|
27271
|
+
const candidates = cfg.pairs.filter((p) => p.level === LEVEL_ORDER[i2]);
|
|
27272
|
+
if (candidates.length === 0) continue;
|
|
27273
|
+
const pick3 = pickByMode(candidates, cfg.mode);
|
|
27274
|
+
if (pick3) return pick3;
|
|
27538
27275
|
}
|
|
27539
|
-
|
|
27540
|
-
|
|
27276
|
+
for (const i2 of order2) {
|
|
27277
|
+
const candidates = cfg.pairs.filter((p) => p.level === LEVEL_ORDER[i2]);
|
|
27278
|
+
if (candidates[0]) return candidates[0];
|
|
27541
27279
|
}
|
|
27542
|
-
|
|
27280
|
+
const fallback = cfg.pairs[0];
|
|
27281
|
+
if (!fallback) throw new Error("resolvePair: slot has no model pairs");
|
|
27282
|
+
return fallback;
|
|
27543
27283
|
}
|
|
27544
|
-
|
|
27545
|
-
|
|
27546
|
-
return
|
|
27284
|
+
const promptValueSchema = preprocess$1(
|
|
27285
|
+
(v2) => {
|
|
27286
|
+
if (typeof v2 === "string") return { source: "inline", text: v2 };
|
|
27287
|
+
return v2;
|
|
27288
|
+
},
|
|
27289
|
+
discriminatedUnion("source", [
|
|
27290
|
+
object({ source: literal("inline"), text: string$2() }),
|
|
27291
|
+
object({ source: literal("file"), path: string$2() })
|
|
27292
|
+
])
|
|
27293
|
+
);
|
|
27294
|
+
const EMPTY_INLINE_PROMPT = { source: "inline", text: "" };
|
|
27295
|
+
const workflowSlotSchema = object({
|
|
27296
|
+
id: string$2(),
|
|
27297
|
+
type: workflowSlotTypeSchema,
|
|
27298
|
+
name: string$2(),
|
|
27299
|
+
order: number$2().int().nonnegative(),
|
|
27300
|
+
enabled: boolean$1(),
|
|
27301
|
+
prompt: promptValueSchema.default(EMPTY_INLINE_PROMPT),
|
|
27302
|
+
// Model tiers for this slot, in priority order (top = highest). Copied to the
|
|
27303
|
+
// card at creation; the card's active level + mode select which pair runs.
|
|
27304
|
+
pairs: array(modelPairSchema).min(1),
|
|
27305
|
+
mode: pairSelectionModeSchema.default("auto"),
|
|
27306
|
+
// Tools this slot may use (e.g. "browser"). Workflow-only, not ticket-editable.
|
|
27307
|
+
tools: array(slotToolSchema).default([]),
|
|
27308
|
+
// review slots only: may set the card's active level on reopen.
|
|
27309
|
+
canAdjustLevel: boolean$1().default(false),
|
|
27310
|
+
// plan slots only: re-run even if a plan already exists on the card.
|
|
27311
|
+
rerun: boolean$1().default(false)
|
|
27312
|
+
});
|
|
27313
|
+
const workflowSchema = object({
|
|
27314
|
+
id: string$2(),
|
|
27315
|
+
name: string$2(),
|
|
27316
|
+
isDefault: boolean$1().default(false),
|
|
27317
|
+
forStory: boolean$1().default(false),
|
|
27318
|
+
slots: array(workflowSlotSchema)
|
|
27319
|
+
});
|
|
27320
|
+
function highestWorkflowLevel(workflow) {
|
|
27321
|
+
let bestIdx = -1;
|
|
27322
|
+
for (const slot of (workflow == null ? void 0 : workflow.slots) ?? []) {
|
|
27323
|
+
for (const p of slot.pairs) bestIdx = Math.max(bestIdx, LEVEL_ORDER.indexOf(p.level));
|
|
27547
27324
|
}
|
|
27548
|
-
return
|
|
27325
|
+
return LEVEL_ORDER[bestIdx] ?? "medium";
|
|
27549
27326
|
}
|
|
27550
|
-
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27554
|
-
|
|
27327
|
+
const DEFAULT_GIT_INSTRUCTIONS = `# Git conventions
|
|
27328
|
+
|
|
27329
|
+
These rules govern how to write commit messages, PR titles, and PR
|
|
27330
|
+
descriptions.
|
|
27331
|
+
|
|
27332
|
+
## PR title
|
|
27333
|
+
- Imperative, present tense: "Add board view", "Fix race in poller".
|
|
27334
|
+
Not past tense, not gerund.
|
|
27335
|
+
- ≤70 characters; aim for 50.
|
|
27336
|
+
- Describe what shipped, not the task. "Add board view" beats
|
|
27337
|
+
"Implement board view feature".
|
|
27338
|
+
- No prefixes like \`feat:\` / \`[FEAT]\` / \`fix:\`.
|
|
27339
|
+
- No ticket IDs in the title (put them in the description if needed).
|
|
27340
|
+
- No trailing period.
|
|
27341
|
+
|
|
27342
|
+
## PR description
|
|
27343
|
+
Keep it focused. Two sections, nothing more unless genuinely useful:
|
|
27344
|
+
|
|
27345
|
+
## Summary
|
|
27346
|
+
- What changed and why. Use as many bullets as the scope warrants —
|
|
27347
|
+
a one-line fix is one bullet; a refactor touching 20 files may
|
|
27348
|
+
need ten. Don't pad, don't truncate.
|
|
27349
|
+
|
|
27350
|
+
## Test plan
|
|
27351
|
+
- What you actually ran or clicked, and the outcome.
|
|
27352
|
+
- Type-check and lint passing are not a test plan on their own.
|
|
27353
|
+
- If something couldn't be verified, say so in one line.
|
|
27354
|
+
|
|
27355
|
+
Do NOT include:
|
|
27356
|
+
- Iteration narration ("Round N", "addressed feedback", "after review").
|
|
27357
|
+
- Commit SHAs or branch names — GitHub already shows both.
|
|
27358
|
+
- Paths to internal planning docs, scratch files, or task tracker URLs.
|
|
27359
|
+
- "Verification:" sections that only list a passing type-check or lint.
|
|
27360
|
+
- Self-congratulation ("clean", "all checks pass", "ready to merge").
|
|
27361
|
+
- Restating the task description verbatim.
|
|
27362
|
+
|
|
27363
|
+
## Commit messages
|
|
27364
|
+
- Short imperative subject line, ≤72 chars. That's usually enough.
|
|
27365
|
+
- Skip the body unless a reviewer reading the diff alone would be
|
|
27366
|
+
confused about *why* the change exists.
|
|
27367
|
+
- Reference an issue only if a concrete one exists to close
|
|
27368
|
+
(\`Closes #123\`). Never invent issue numbers.
|
|
27369
|
+
`;
|
|
27370
|
+
const runtimeBoardColumnIdSchema = _enum([
|
|
27371
|
+
"todo",
|
|
27372
|
+
"in_progress",
|
|
27373
|
+
"reopened",
|
|
27374
|
+
"ready_for_review",
|
|
27375
|
+
"blocked",
|
|
27376
|
+
"done"
|
|
27377
|
+
]);
|
|
27378
|
+
const reviewActorSchema = object({
|
|
27379
|
+
type: _enum(["ai", "human", "external"]),
|
|
27380
|
+
id: string$2(),
|
|
27381
|
+
source: string$2().optional()
|
|
27382
|
+
});
|
|
27383
|
+
const reviewIssueSchema = object({
|
|
27384
|
+
file: string$2().optional(),
|
|
27385
|
+
line: number$2().optional(),
|
|
27386
|
+
severity: _enum(["blocking", "warning", "info"]),
|
|
27387
|
+
message: string$2()
|
|
27388
|
+
});
|
|
27389
|
+
const reviewAttachmentSchema = object({
|
|
27390
|
+
type: string$2(),
|
|
27391
|
+
// "image" | "file" | any mime category
|
|
27392
|
+
name: string$2(),
|
|
27393
|
+
mimeType: string$2(),
|
|
27394
|
+
path: string$2()
|
|
27395
|
+
// absolute path in ~/.whipped/attachments/
|
|
27396
|
+
});
|
|
27397
|
+
const runtimeReviewCommentSchema = object({
|
|
27398
|
+
id: string$2(),
|
|
27399
|
+
type: string$2(),
|
|
27400
|
+
actor: reviewActorSchema,
|
|
27401
|
+
status: _enum(["pass", "fail", "warning", "skipped"]).optional(),
|
|
27402
|
+
createdAt: number$2(),
|
|
27403
|
+
streamId: string$2().optional(),
|
|
27404
|
+
summary: string$2(),
|
|
27405
|
+
issues: array(reviewIssueSchema).optional(),
|
|
27406
|
+
attachments: array(reviewAttachmentSchema).optional(),
|
|
27407
|
+
metadata: record(string$2(), unknown$1()).optional()
|
|
27408
|
+
});
|
|
27409
|
+
const runtimeActivityEntrySchema = object({
|
|
27410
|
+
timestamp: number$2(),
|
|
27411
|
+
message: string$2()
|
|
27412
|
+
});
|
|
27413
|
+
const runtimeTaskSessionStateSchema = _enum(["running", "stopped", "completed", "failed", "killed"]);
|
|
27414
|
+
const runtimeTerminalSessionEntrySchema = object({
|
|
27415
|
+
streamId: string$2(),
|
|
27416
|
+
type: string$2(),
|
|
27417
|
+
startedAt: number$2(),
|
|
27418
|
+
endedAt: number$2().optional(),
|
|
27419
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27420
|
+
state: runtimeTaskSessionStateSchema.optional()
|
|
27421
|
+
});
|
|
27422
|
+
const runtimeCardPrioritySchema = _enum(["urgent", "high", "medium", "low"]);
|
|
27423
|
+
const cardTypeSchema = _enum(["task", "story", "subtask"]);
|
|
27424
|
+
const runtimePrMetaSchema = object({
|
|
27425
|
+
url: string$2().optional(),
|
|
27426
|
+
title: string$2().optional(),
|
|
27427
|
+
description: string$2().optional(),
|
|
27428
|
+
updatedAt: number$2().optional(),
|
|
27429
|
+
updatedBy: string$2().optional()
|
|
27430
|
+
});
|
|
27431
|
+
const runtimeBoardCardSchema = object({
|
|
27432
|
+
id: string$2(),
|
|
27433
|
+
description: string$2(),
|
|
27434
|
+
descriptionAttachments: array(reviewAttachmentSchema).optional().default([]),
|
|
27435
|
+
columnId: runtimeBoardColumnIdSchema,
|
|
27436
|
+
type: cardTypeSchema.default("task"),
|
|
27437
|
+
readyForDev: boolean$1().default(false),
|
|
27438
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27439
|
+
priority: runtimeCardPrioritySchema.optional(),
|
|
27440
|
+
// Single-parent stacking: this card continues in the parent's worktree/branch
|
|
27441
|
+
// and starts once the parent reaches ready_for_review. Mutually exclusive with waitsFor.
|
|
27442
|
+
dependsOn: string$2().optional(),
|
|
27443
|
+
// Many-parent gate (tasks only): this card starts only once ALL listed cards are
|
|
27444
|
+
// done (merged), in a fresh worktree branched from baseRef. Mutually exclusive with dependsOn.
|
|
27445
|
+
waitsFor: array(string$2()).default([]),
|
|
27446
|
+
// Story-only: the IDs of this story's subtasks. The story triggers its orchestrator
|
|
27447
|
+
// workflow once every subtask reaches ready_for_review.
|
|
27448
|
+
subtaskIds: array(string$2()).default([]),
|
|
27449
|
+
autoFixAttempts: number$2().int().nonnegative().default(0),
|
|
27450
|
+
baseRef: string$2(),
|
|
27451
|
+
createdAt: number$2(),
|
|
27452
|
+
updatedAt: number$2(),
|
|
27453
|
+
githubIssueUrl: string$2().optional(),
|
|
27454
|
+
pr: runtimePrMetaSchema.optional(),
|
|
27455
|
+
workflowId: string$2().optional(),
|
|
27456
|
+
// Plan written by the one-shot plan agent; injected into the dev agent's prompt.
|
|
27457
|
+
plan: string$2().optional(),
|
|
27458
|
+
// Workflow-wide capability level; every slot resolves it to its own pair.
|
|
27459
|
+
activeLevel: tierLevelSchema.default("medium"),
|
|
27460
|
+
// Per-slot model config, snapshotted from the workflow at creation and editable
|
|
27461
|
+
// per ticket (slotId → {pairs, mode, pinnedPairId}).
|
|
27462
|
+
modelConfig: cardModelConfigSchema.optional(),
|
|
27463
|
+
reviewComments: array(runtimeReviewCommentSchema).default([]),
|
|
27464
|
+
activityLog: array(runtimeActivityEntrySchema).default([]),
|
|
27465
|
+
terminalSessions: array(runtimeTerminalSessionEntrySchema).default([]),
|
|
27466
|
+
githubCommentIds: array(string$2()).default([]),
|
|
27467
|
+
worktreePath: string$2().optional(),
|
|
27468
|
+
branchName: string$2().optional(),
|
|
27469
|
+
slackMessageTs: string$2().optional(),
|
|
27470
|
+
slackChannelId: string$2().optional()
|
|
27471
|
+
});
|
|
27472
|
+
const runtimeBoardColumnSchema = object({
|
|
27473
|
+
id: runtimeBoardColumnIdSchema,
|
|
27474
|
+
title: string$2(),
|
|
27475
|
+
taskIds: array(string$2())
|
|
27476
|
+
});
|
|
27477
|
+
const runtimeBoardDataSchema = object({
|
|
27478
|
+
columns: array(runtimeBoardColumnSchema),
|
|
27479
|
+
cards: record(string$2(), runtimeBoardCardSchema)
|
|
27480
|
+
});
|
|
27481
|
+
const runtimeGlobalConfigSchema = object({
|
|
27482
|
+
defaultAgent: runtimeAgentIdSchema.default("claude"),
|
|
27483
|
+
maxParallelTasks: number$2().int().positive().default(4),
|
|
27484
|
+
maxParallelQA: number$2().int().positive().default(1),
|
|
27485
|
+
maxAutoFixAttempts: number$2().int().nonnegative().default(3),
|
|
27486
|
+
pollingIntervalSeconds: number$2().int().positive().default(30),
|
|
27487
|
+
prPollingIntervalSeconds: number$2().int().positive().default(60),
|
|
27488
|
+
terminalApp: string$2().optional(),
|
|
27489
|
+
slackEnabled: boolean$1().default(true),
|
|
27490
|
+
slackBotToken: string$2().optional(),
|
|
27491
|
+
slackSigningSecret: string$2().optional(),
|
|
27492
|
+
slackAppConfigToken: string$2().optional(),
|
|
27493
|
+
slackClientId: string$2().optional(),
|
|
27494
|
+
slackClientSecret: string$2().optional(),
|
|
27495
|
+
slackAppId: string$2().optional(),
|
|
27496
|
+
slackOauthAuthorizeUrl: string$2().optional(),
|
|
27497
|
+
slackPublicUrl: string$2().optional(),
|
|
27498
|
+
slackBotName: string$2().default("Whipped"),
|
|
27499
|
+
slackInstallerUserId: string$2().optional(),
|
|
27500
|
+
autoStartTunnel: boolean$1().default(false),
|
|
27501
|
+
tunnelId: string$2().optional(),
|
|
27502
|
+
tunnelDomain: string$2().optional(),
|
|
27503
|
+
tunnelName: string$2().default("whipped"),
|
|
27504
|
+
// Auth: single shared password (scrypt hash) + HMAC secret for signed session
|
|
27505
|
+
// cookies + machine token for local agent machinery (MCP/hooks). Never expose
|
|
27506
|
+
// these over the API — see configController's response.
|
|
27507
|
+
authPasswordHash: string$2().optional(),
|
|
27508
|
+
authSessionSecret: string$2().optional(),
|
|
27509
|
+
authMachineToken: string$2().optional()
|
|
27510
|
+
});
|
|
27511
|
+
const runtimeGithubConfigSchema = object({
|
|
27512
|
+
token: string$2()
|
|
27513
|
+
});
|
|
27514
|
+
const runtimeWorktreeSetupSchema = object({
|
|
27515
|
+
filesToCopy: array(string$2()).default([]),
|
|
27516
|
+
installCommand: string$2().default("")
|
|
27517
|
+
});
|
|
27518
|
+
const runtimeProjectSecretSchema = object({
|
|
27519
|
+
key: string$2().min(1),
|
|
27520
|
+
value: string$2()
|
|
27521
|
+
});
|
|
27522
|
+
const BUILTIN_SECRET_KEYS = ["GITHUB_TOKEN"];
|
|
27523
|
+
const runtimeProjectConfigSchema = object({
|
|
27524
|
+
name: string$2().optional(),
|
|
27525
|
+
defaultAgent: runtimeAgentIdSchema.optional(),
|
|
27526
|
+
maxParallelTasks: number$2().int().positive().optional(),
|
|
27527
|
+
maxAutoFixAttempts: number$2().int().nonnegative().optional(),
|
|
27528
|
+
pollingIntervalSeconds: number$2().int().positive().optional(),
|
|
27529
|
+
// What happens when a card passes review (polling/dispatch is always on; per-ticket
|
|
27530
|
+
// readyForDev gates pickup). "off" parks it in ready_for_review, "pr" auto-creates a
|
|
27531
|
+
// GitHub PR, "yolo" merges the branch straight into the local baseRef and pushes.
|
|
27532
|
+
deliveryMode: _enum(["off", "pr", "yolo"]).default("off"),
|
|
27533
|
+
autoCommit: boolean$1().default(true),
|
|
27534
|
+
defaultBaseBranch: string$2().optional(),
|
|
27535
|
+
github: runtimeGithubConfigSchema.optional(),
|
|
27536
|
+
worktreeSetup: runtimeWorktreeSetupSchema.optional(),
|
|
27537
|
+
startCommand: string$2().default(""),
|
|
27538
|
+
workflows: array(workflowSchema).default([]),
|
|
27539
|
+
secrets: array(runtimeProjectSecretSchema).default([]),
|
|
27540
|
+
systemPrompt: string$2().optional(),
|
|
27541
|
+
// Freeform instructions injected into the dev agent's prompt to shape PR
|
|
27542
|
+
// titles, descriptions, and commit messages. Empty/absent → daemon falls
|
|
27543
|
+
// back to DEFAULT_GIT_INSTRUCTIONS.
|
|
27544
|
+
gitInstructions: string$2().optional(),
|
|
27545
|
+
// Which agent binary/model/effort the assistant agent runs as. Absent → claude.
|
|
27546
|
+
assistantModel: agentModelChoiceSchema.optional()
|
|
27547
|
+
});
|
|
27548
|
+
object({
|
|
27549
|
+
workspaceId: string$2(),
|
|
27550
|
+
repoPath: string$2(),
|
|
27551
|
+
board: runtimeBoardDataSchema,
|
|
27552
|
+
revision: number$2(),
|
|
27553
|
+
projectConfig: runtimeProjectConfigSchema
|
|
27554
|
+
});
|
|
27555
|
+
object({
|
|
27556
|
+
board: runtimeBoardDataSchema,
|
|
27557
|
+
revision: number$2()
|
|
27558
|
+
});
|
|
27559
|
+
const runtimeVisualElementSchema = object({
|
|
27560
|
+
elementSelector: string$2().optional(),
|
|
27561
|
+
elementText: string$2().optional(),
|
|
27562
|
+
componentName: string$2().optional(),
|
|
27563
|
+
componentChain: array(string$2()).optional(),
|
|
27564
|
+
sourceFile: string$2().optional(),
|
|
27565
|
+
sourceLine: number$2().optional(),
|
|
27566
|
+
// The page the element was captured on. Selections can span pages, so this is
|
|
27567
|
+
// per-element rather than relying on the visualComment-level pageUrl.
|
|
27568
|
+
pageUrl: string$2().optional()
|
|
27569
|
+
});
|
|
27570
|
+
const runtimeVisualCommentSchema = object({
|
|
27571
|
+
pageUrl: string$2().optional(),
|
|
27572
|
+
elements: array(runtimeVisualElementSchema).default([])
|
|
27573
|
+
});
|
|
27574
|
+
const runtimeCardCreateRequestSchema = object({
|
|
27575
|
+
description: string$2(),
|
|
27576
|
+
type: cardTypeSchema.optional(),
|
|
27577
|
+
// Browser-extension element references; folded into the description server-side.
|
|
27578
|
+
visualComment: runtimeVisualCommentSchema.optional(),
|
|
27579
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27580
|
+
priority: runtimeCardPrioritySchema.optional(),
|
|
27581
|
+
readyForDev: boolean$1().optional(),
|
|
27582
|
+
dependsOn: string$2().optional(),
|
|
27583
|
+
waitsFor: array(string$2()).optional(),
|
|
27584
|
+
subtaskIds: array(string$2()).optional(),
|
|
27585
|
+
columnId: runtimeBoardColumnIdSchema.optional(),
|
|
27586
|
+
baseRef: string$2().optional(),
|
|
27587
|
+
githubIssueUrl: string$2().optional(),
|
|
27588
|
+
workflowId: string$2().optional(),
|
|
27589
|
+
descriptionAttachments: array(reviewAttachmentSchema).optional(),
|
|
27590
|
+
branchName: string$2().optional(),
|
|
27591
|
+
// Optional per-ticket overrides edited before creation. When omitted, the card
|
|
27592
|
+
// snapshots the resolved workflow's pairs and defaults the active level to the
|
|
27593
|
+
// workflow's highest configured tier.
|
|
27594
|
+
modelConfig: cardModelConfigSchema.optional(),
|
|
27595
|
+
activeLevel: tierLevelSchema.optional()
|
|
27596
|
+
});
|
|
27597
|
+
object({
|
|
27598
|
+
cardId: string$2(),
|
|
27599
|
+
targetColumnId: runtimeBoardColumnIdSchema,
|
|
27600
|
+
targetIndex: number$2().int().nonnegative().optional(),
|
|
27601
|
+
revision: number$2()
|
|
27602
|
+
});
|
|
27603
|
+
object({
|
|
27604
|
+
cardId: string$2(),
|
|
27605
|
+
description: string$2().optional(),
|
|
27606
|
+
descriptionAttachments: array(reviewAttachmentSchema).optional(),
|
|
27607
|
+
type: cardTypeSchema.optional(),
|
|
27608
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27609
|
+
priority: runtimeCardPrioritySchema.optional(),
|
|
27610
|
+
readyForDev: boolean$1().optional(),
|
|
27611
|
+
dependsOn: string$2().optional(),
|
|
27612
|
+
waitsFor: array(string$2()).optional(),
|
|
27613
|
+
subtaskIds: array(string$2()).optional(),
|
|
27614
|
+
workflowId: string$2().optional(),
|
|
27615
|
+
branchName: string$2().optional(),
|
|
27616
|
+
plan: string$2().optional(),
|
|
27617
|
+
activeLevel: tierLevelSchema.optional(),
|
|
27618
|
+
modelConfig: cardModelConfigSchema.optional(),
|
|
27619
|
+
revision: number$2()
|
|
27620
|
+
});
|
|
27621
|
+
const memoryScopeSchema = _enum(["global", "project"]);
|
|
27622
|
+
const memoryTypeSchema = _enum([
|
|
27623
|
+
"fact",
|
|
27624
|
+
"convention",
|
|
27625
|
+
"decision",
|
|
27626
|
+
"preference",
|
|
27627
|
+
"rule",
|
|
27628
|
+
"lesson",
|
|
27629
|
+
"sharp_edge"
|
|
27630
|
+
]);
|
|
27631
|
+
const MEMORY_TYPE_OPTIONS = [
|
|
27632
|
+
{ value: "fact", label: "Fact" },
|
|
27633
|
+
{ value: "convention", label: "Convention" },
|
|
27634
|
+
{ value: "decision", label: "Decision" },
|
|
27635
|
+
{ value: "preference", label: "Preference" },
|
|
27636
|
+
{ value: "rule", label: "Rule" },
|
|
27637
|
+
{ value: "lesson", label: "Lesson" },
|
|
27638
|
+
{ value: "sharp_edge", label: "Sharp edge" }
|
|
27639
|
+
];
|
|
27640
|
+
const memorySourceTypeSchema = _enum(["user_correction", "explicit_save", "task_lesson", "manual_human"]);
|
|
27641
|
+
const memoryStatusSchema = _enum(["pending", "approved"]);
|
|
27642
|
+
const runtimeMemoryOriginAgentSchema = object({
|
|
27643
|
+
agent: string$2(),
|
|
27644
|
+
model: string$2().optional()
|
|
27645
|
+
});
|
|
27646
|
+
object({
|
|
27647
|
+
id: string$2(),
|
|
27648
|
+
scope: memoryScopeSchema,
|
|
27649
|
+
workspaceId: string$2().nullable(),
|
|
27650
|
+
originWorkspaceId: string$2().nullable().optional(),
|
|
27651
|
+
type: memoryTypeSchema,
|
|
27652
|
+
title: string$2(),
|
|
27653
|
+
content: string$2(),
|
|
27654
|
+
sourceType: memorySourceTypeSchema,
|
|
27655
|
+
importance: number$2().int().min(1).max(3).default(1),
|
|
27656
|
+
tags: array(string$2()).default([]),
|
|
27657
|
+
boundWorkspaceIds: array(string$2()).default([]),
|
|
27658
|
+
originCardId: string$2().nullable().optional(),
|
|
27659
|
+
originAgent: runtimeMemoryOriginAgentSchema.nullable().optional(),
|
|
27660
|
+
status: memoryStatusSchema.default("approved"),
|
|
27661
|
+
createdAt: number$2(),
|
|
27662
|
+
updatedAt: number$2()
|
|
27663
|
+
});
|
|
27664
|
+
function normalizeTag$1(raw2) {
|
|
27665
|
+
return raw2.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
27666
|
+
}
|
|
27667
|
+
_enum(["interval", "calendar"]);
|
|
27668
|
+
const recurringScheduleSchema = discriminatedUnion("kind", [
|
|
27669
|
+
object({ kind: literal("interval"), intervalSeconds: number$2().int().positive() }),
|
|
27670
|
+
object({ kind: literal("calendar"), cronExpr: string$2().min(1), timezone: string$2().min(1) })
|
|
27671
|
+
]);
|
|
27672
|
+
const recurringRunStatusSchema = _enum(["running", "ok", "error", "killed"]);
|
|
27673
|
+
const recurringRunTriggerSchema = _enum(["schedule", "manual"]);
|
|
27674
|
+
const recurringAgentRunSchema = object({
|
|
27675
|
+
id: string$2(),
|
|
27676
|
+
startedAt: number$2(),
|
|
27677
|
+
endedAt: number$2().optional(),
|
|
27678
|
+
status: recurringRunStatusSchema,
|
|
27679
|
+
summary: string$2().optional(),
|
|
27680
|
+
tokens: number$2().optional(),
|
|
27681
|
+
trigger: recurringRunTriggerSchema.default("schedule"),
|
|
27682
|
+
streamId: string$2().optional()
|
|
27683
|
+
});
|
|
27684
|
+
object({
|
|
27685
|
+
id: string$2(),
|
|
27686
|
+
name: string$2(),
|
|
27687
|
+
instructions: string$2().default(""),
|
|
27688
|
+
schedule: recurringScheduleSchema,
|
|
27689
|
+
model: agentModelChoiceSchema,
|
|
27690
|
+
enabled: boolean$1().default(true),
|
|
27691
|
+
lastRunAt: number$2().optional(),
|
|
27692
|
+
nextRunAt: number$2().optional(),
|
|
27693
|
+
journal: string$2().default(""),
|
|
27694
|
+
createdAt: number$2(),
|
|
27695
|
+
updatedAt: number$2(),
|
|
27696
|
+
recentRuns: array(recurringAgentRunSchema).default([])
|
|
27697
|
+
});
|
|
27698
|
+
object({
|
|
27699
|
+
name: string$2().min(1),
|
|
27700
|
+
instructions: string$2().optional(),
|
|
27701
|
+
schedule: recurringScheduleSchema,
|
|
27702
|
+
model: agentModelChoiceSchema.optional(),
|
|
27703
|
+
enabled: boolean$1().optional()
|
|
27704
|
+
});
|
|
27705
|
+
object({
|
|
27706
|
+
id: string$2(),
|
|
27707
|
+
name: string$2().min(1).optional(),
|
|
27708
|
+
instructions: string$2().optional(),
|
|
27709
|
+
schedule: recurringScheduleSchema.optional(),
|
|
27710
|
+
model: agentModelChoiceSchema.optional(),
|
|
27711
|
+
enabled: boolean$1().optional(),
|
|
27712
|
+
journal: string$2().optional()
|
|
27713
|
+
});
|
|
27714
|
+
const projectFolderSchema = object({
|
|
27715
|
+
id: string$2(),
|
|
27716
|
+
name: string$2(),
|
|
27717
|
+
collapsed: boolean$1().default(false),
|
|
27718
|
+
projectIds: array(string$2())
|
|
27719
|
+
});
|
|
27720
|
+
const topLevelItemSchema = discriminatedUnion("type", [
|
|
27721
|
+
object({ type: literal("folder"), id: string$2() }),
|
|
27722
|
+
object({ type: literal("project"), workspaceId: string$2() })
|
|
27723
|
+
]);
|
|
27724
|
+
object({
|
|
27725
|
+
version: literal(1),
|
|
27726
|
+
topLevel: array(topLevelItemSchema),
|
|
27727
|
+
folders: record(string$2(), projectFolderSchema)
|
|
27728
|
+
});
|
|
27729
|
+
object({
|
|
27730
|
+
workspaceId: string$2(),
|
|
27731
|
+
repoPath: string$2(),
|
|
27732
|
+
name: string$2(),
|
|
27733
|
+
lastUpdated: number$2()
|
|
27734
|
+
});
|
|
27735
|
+
const addProjectSchema = object({
|
|
27736
|
+
repoPath: string$2().min(1, "Repository path is required"),
|
|
27737
|
+
deliveryMode: _enum(["off", "pr", "yolo"]),
|
|
27738
|
+
defaultBaseBranch: string$2().optional(),
|
|
27739
|
+
assistantModel: agentModelChoiceSchema
|
|
27740
|
+
});
|
|
27741
|
+
function stringifyQuery(query) {
|
|
27742
|
+
const parts = [];
|
|
27743
|
+
for (const [key, value] of Object.entries(query)) {
|
|
27744
|
+
if (value === void 0 || value === null || value === "") {
|
|
27745
|
+
continue;
|
|
27746
|
+
}
|
|
27747
|
+
parts.push(
|
|
27748
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`
|
|
27749
|
+
);
|
|
27750
|
+
}
|
|
27751
|
+
return parts.join("&");
|
|
27752
|
+
}
|
|
27753
|
+
function buildUrl(baseUrl, path2, query) {
|
|
27754
|
+
const isAbsolute = /^https?:\/\//.test(baseUrl);
|
|
27755
|
+
if (isAbsolute) {
|
|
27756
|
+
const normalizedBase = baseUrl.replace(/\/?$/, "/");
|
|
27757
|
+
const url = new URL(path2.join("/"), normalizedBase);
|
|
27758
|
+
if (query) {
|
|
27759
|
+
url.search = stringifyQuery(query);
|
|
27760
|
+
}
|
|
27761
|
+
return url.toString();
|
|
27762
|
+
}
|
|
27763
|
+
const cleanBase = `/${baseUrl.replace(/^\/|\/$/g, "")}`;
|
|
27764
|
+
const pathStr = path2.length > 0 ? `/${path2.join("/")}` : "";
|
|
27765
|
+
const queryStr = query ? stringifyQuery(query) : "";
|
|
27766
|
+
return `${cleanBase}${pathStr}${queryStr ? `?${queryStr}` : ""}`;
|
|
27767
|
+
}
|
|
27768
|
+
function __DEV__() {
|
|
27769
|
+
return typeof process !== "undefined" && true;
|
|
27770
|
+
}
|
|
27771
|
+
function generateTags(path2) {
|
|
27772
|
+
return path2.map((_2, i2) => path2.slice(0, i2 + 1).join("/"));
|
|
27773
|
+
}
|
|
27774
|
+
function containsFile(value) {
|
|
27775
|
+
if (value instanceof File || value instanceof Blob) return true;
|
|
27776
|
+
if (Array.isArray(value)) return value.some(containsFile);
|
|
27777
|
+
if (value && typeof value === "object") {
|
|
27778
|
+
return Object.values(value).some(containsFile);
|
|
27779
|
+
}
|
|
27780
|
+
return false;
|
|
27781
|
+
}
|
|
27782
|
+
function isJsonBody(body) {
|
|
27783
|
+
if (body === null || body === void 0) return false;
|
|
27784
|
+
if (body instanceof FormData) return false;
|
|
27785
|
+
if (body instanceof Blob) return false;
|
|
27786
|
+
if (body instanceof ArrayBuffer) return false;
|
|
27787
|
+
if (body instanceof URLSearchParams) return false;
|
|
27788
|
+
if (body instanceof ReadableStream) return false;
|
|
27789
|
+
if (typeof body === "string") return false;
|
|
27790
|
+
if (typeof body === "object") {
|
|
27791
|
+
return true;
|
|
27792
|
+
}
|
|
27793
|
+
return false;
|
|
27794
|
+
}
|
|
27795
|
+
async function resolveHeaders(headers) {
|
|
27796
|
+
if (!headers) return void 0;
|
|
27797
|
+
if (typeof headers === "function") {
|
|
27798
|
+
return await headers();
|
|
27799
|
+
}
|
|
27800
|
+
return headers;
|
|
27801
|
+
}
|
|
27802
|
+
function headersInitToRecord(headers) {
|
|
27803
|
+
return Object.fromEntries(new Headers(headers));
|
|
27804
|
+
}
|
|
27805
|
+
async function resolveHeadersToRecord(headers) {
|
|
27806
|
+
const resolved = await resolveHeaders(headers);
|
|
27807
|
+
if (!resolved) return {};
|
|
27808
|
+
return headersInitToRecord(resolved);
|
|
27809
|
+
}
|
|
27810
|
+
async function mergeHeaders(defaultHeaders, requestHeaders) {
|
|
27811
|
+
const resolved1 = await resolveHeaders(defaultHeaders);
|
|
27812
|
+
const resolved2 = await resolveHeaders(requestHeaders);
|
|
27813
|
+
if (!resolved1 && !resolved2) return void 0;
|
|
27814
|
+
if (!resolved1) return resolved2;
|
|
27815
|
+
if (!resolved2) return resolved1;
|
|
27816
|
+
return {
|
|
27817
|
+
...Object.fromEntries(new Headers(resolved1)),
|
|
27818
|
+
...Object.fromEntries(new Headers(resolved2))
|
|
27819
|
+
};
|
|
27820
|
+
}
|
|
27821
|
+
function removeHeaderKeys(headers, keysToRemove) {
|
|
27822
|
+
if (!headers) return void 0;
|
|
27823
|
+
const headersObj = new Headers(headers);
|
|
27824
|
+
for (const key of keysToRemove) {
|
|
27825
|
+
headersObj.delete(key);
|
|
27826
|
+
}
|
|
27827
|
+
const entries = [...headersObj.entries()];
|
|
27828
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
27829
|
+
}
|
|
27830
|
+
function objectToFormData(obj) {
|
|
27831
|
+
const formData = new FormData();
|
|
27832
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
27833
|
+
if (value === null || value === void 0) {
|
|
27834
|
+
continue;
|
|
27835
|
+
}
|
|
27836
|
+
if (value instanceof Blob || value instanceof File) {
|
|
27837
|
+
formData.append(key, value);
|
|
27838
|
+
} else if (Array.isArray(value)) {
|
|
27839
|
+
for (const entry of value) {
|
|
27840
|
+
if (entry instanceof Blob || entry instanceof File) {
|
|
27841
|
+
formData.append(key, entry);
|
|
27842
|
+
} else if (typeof entry === "object" && entry !== null) {
|
|
27843
|
+
formData.append(key, JSON.stringify(entry));
|
|
27844
|
+
} else {
|
|
27845
|
+
formData.append(key, String(entry));
|
|
27846
|
+
}
|
|
27847
|
+
}
|
|
27848
|
+
} else if (typeof value === "object") {
|
|
27849
|
+
formData.append(key, JSON.stringify(value));
|
|
27850
|
+
} else {
|
|
27851
|
+
formData.append(key, String(value));
|
|
27852
|
+
}
|
|
27853
|
+
}
|
|
27854
|
+
return formData;
|
|
27855
|
+
}
|
|
27856
|
+
function objectToUrlEncoded(obj) {
|
|
27857
|
+
const params = new URLSearchParams();
|
|
27858
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
27859
|
+
if (value === void 0 || value === null) {
|
|
27860
|
+
continue;
|
|
27861
|
+
}
|
|
27862
|
+
if (Array.isArray(value)) {
|
|
27863
|
+
for (const item of value) {
|
|
27864
|
+
if (item !== void 0 && item !== null) {
|
|
27865
|
+
params.append(key, String(item));
|
|
27866
|
+
}
|
|
27867
|
+
}
|
|
27868
|
+
} else if (typeof value === "object") {
|
|
27869
|
+
params.append(key, JSON.stringify(value));
|
|
27870
|
+
} else {
|
|
27871
|
+
params.append(key, String(value));
|
|
27872
|
+
}
|
|
27873
|
+
}
|
|
27874
|
+
return params.toString();
|
|
27875
|
+
}
|
|
27876
|
+
function sortObjectKeys(obj, seen2 = /* @__PURE__ */ new WeakSet()) {
|
|
27877
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
27878
|
+
if (seen2.has(obj)) {
|
|
27879
|
+
return "[Circular]";
|
|
27880
|
+
}
|
|
27881
|
+
seen2.add(obj);
|
|
27882
|
+
if (Array.isArray(obj)) {
|
|
27883
|
+
return obj.map((item) => sortObjectKeys(item, seen2));
|
|
27884
|
+
}
|
|
27885
|
+
return Object.keys(obj).sort().reduce(
|
|
27886
|
+
(sorted, key) => {
|
|
27887
|
+
sorted[key] = sortObjectKeys(
|
|
27888
|
+
obj[key],
|
|
27889
|
+
seen2
|
|
27890
|
+
);
|
|
27891
|
+
return sorted;
|
|
27892
|
+
},
|
|
27893
|
+
{}
|
|
27894
|
+
);
|
|
27895
|
+
}
|
|
27896
|
+
function isSpooshBody(value) {
|
|
27897
|
+
return typeof value === "object" && value !== null && "__spooshBody" in value && value.__spooshBody === true;
|
|
27898
|
+
}
|
|
27899
|
+
function resolveRequestBody(rawBody) {
|
|
27900
|
+
if (rawBody === void 0 || rawBody === null) {
|
|
27901
|
+
return void 0;
|
|
27902
|
+
}
|
|
27903
|
+
if (isSpooshBody(rawBody)) {
|
|
27904
|
+
const body = rawBody;
|
|
27905
|
+
switch (body.kind) {
|
|
27906
|
+
case "form":
|
|
27907
|
+
return {
|
|
27908
|
+
body: objectToFormData(body.value),
|
|
27909
|
+
removeHeaders: ["Content-Type"]
|
|
27910
|
+
};
|
|
27911
|
+
case "json":
|
|
27912
|
+
return {
|
|
27913
|
+
body: JSON.stringify(body.value),
|
|
27914
|
+
headers: { "Content-Type": "application/json" }
|
|
27915
|
+
};
|
|
27916
|
+
case "urlencoded":
|
|
27917
|
+
return {
|
|
27918
|
+
body: objectToUrlEncoded(body.value),
|
|
27919
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
27920
|
+
};
|
|
27921
|
+
}
|
|
27922
|
+
}
|
|
27923
|
+
if (isJsonBody(rawBody)) {
|
|
27924
|
+
if (__DEV__() && containsFile(rawBody)) {
|
|
27925
|
+
console.warn(
|
|
27926
|
+
"[spoosh] Plain object body contains File/Blob. Use form() wrapper for multipart upload."
|
|
27927
|
+
);
|
|
27928
|
+
}
|
|
27929
|
+
return {
|
|
27930
|
+
body: JSON.stringify(rawBody),
|
|
27931
|
+
headers: { "Content-Type": "application/json" }
|
|
27932
|
+
};
|
|
27933
|
+
}
|
|
27934
|
+
if (rawBody instanceof FormData) {
|
|
27935
|
+
return { body: rawBody, removeHeaders: ["Content-Type"] };
|
|
27936
|
+
}
|
|
27937
|
+
return { body: rawBody };
|
|
27938
|
+
}
|
|
27939
|
+
function normalizeTag(tag) {
|
|
27940
|
+
return tag.startsWith("/") ? tag.slice(1) : tag;
|
|
27941
|
+
}
|
|
27942
|
+
function matchTag(entryTag, pattern) {
|
|
27943
|
+
const normalizedTag = normalizeTag(entryTag);
|
|
27944
|
+
const normalizedPattern = normalizeTag(pattern);
|
|
27945
|
+
if (normalizedPattern.endsWith("/*")) {
|
|
27946
|
+
const prefix2 = normalizedPattern.slice(0, -2);
|
|
27947
|
+
return prefix2 === "" ? normalizedTag.length > 0 : normalizedTag.startsWith(prefix2 + "/");
|
|
27948
|
+
}
|
|
27949
|
+
return normalizedTag === normalizedPattern;
|
|
27950
|
+
}
|
|
27951
|
+
function matchTags(entryTag, patterns) {
|
|
27952
|
+
return patterns.some((pattern) => matchTag(entryTag, pattern));
|
|
27953
|
+
}
|
|
27954
|
+
function resolveTags(options, resolvedPath) {
|
|
27955
|
+
const tagsOption = options == null ? void 0 : options.tags;
|
|
27956
|
+
if (!tagsOption) {
|
|
27957
|
+
const tag2 = resolvedPath.join("/");
|
|
27958
|
+
return tag2 ? [normalizeTag(tag2)] : [];
|
|
27959
|
+
}
|
|
27960
|
+
if (typeof tagsOption === "string") {
|
|
27961
|
+
return [normalizeTag(tagsOption)];
|
|
27962
|
+
}
|
|
27963
|
+
if (Array.isArray(tagsOption)) {
|
|
27964
|
+
return [...new Set(tagsOption.map(normalizeTag))];
|
|
27965
|
+
}
|
|
27966
|
+
const tag = resolvedPath.join("/");
|
|
27967
|
+
return tag ? [normalizeTag(tag)] : [];
|
|
27968
|
+
}
|
|
27969
|
+
function resolvePath(path2, params) {
|
|
27970
|
+
if (!params) return path2;
|
|
27971
|
+
return path2.map((segment) => {
|
|
27972
|
+
if (segment.startsWith(":")) {
|
|
27973
|
+
const paramName = segment.slice(1);
|
|
27974
|
+
const value = params[paramName];
|
|
27975
|
+
if (value === void 0) {
|
|
27976
|
+
throw new Error(`Missing path parameter: ${paramName}`);
|
|
27977
|
+
}
|
|
27978
|
+
return String(value);
|
|
27979
|
+
}
|
|
27980
|
+
return segment;
|
|
27981
|
+
});
|
|
27982
|
+
}
|
|
27983
|
+
function resolvePathString(path2, params) {
|
|
27984
|
+
if (!params) return path2;
|
|
27985
|
+
return path2.split("/").map((segment) => {
|
|
27986
|
+
if (segment.startsWith(":")) {
|
|
27987
|
+
const paramName = segment.slice(1);
|
|
27988
|
+
const value = params[paramName];
|
|
27989
|
+
return value !== void 0 ? String(value) : segment;
|
|
27990
|
+
}
|
|
27991
|
+
return segment;
|
|
27992
|
+
}).join("/");
|
|
27993
|
+
}
|
|
27994
|
+
var isAbortError = (err) => err instanceof DOMException && err.name === "AbortError";
|
|
27995
|
+
var fetchTransport = async (url, init) => {
|
|
27996
|
+
const res = await fetch(url, init);
|
|
27997
|
+
const contentType = res.headers.get("content-type");
|
|
27998
|
+
const isJson = contentType == null ? void 0 : contentType.includes("application/json");
|
|
27999
|
+
const isText = (contentType == null ? void 0 : contentType.includes("text/")) || (contentType == null ? void 0 : contentType.includes("application/xml"));
|
|
28000
|
+
let data;
|
|
28001
|
+
if (isJson) {
|
|
28002
|
+
data = await res.json();
|
|
28003
|
+
} else if (isText) {
|
|
28004
|
+
data = await res.text();
|
|
28005
|
+
} else {
|
|
28006
|
+
data = void 0;
|
|
28007
|
+
}
|
|
28008
|
+
return { ok: res.ok, status: res.status, headers: res.headers, data };
|
|
28009
|
+
};
|
|
28010
|
+
var xhrTransport = (url, init, options) => {
|
|
28011
|
+
return new Promise((resolve, reject) => {
|
|
28012
|
+
const xhr = new XMLHttpRequest();
|
|
28013
|
+
xhr.open(init.method ?? "GET", url);
|
|
28014
|
+
if (init.headers) {
|
|
28015
|
+
const headers = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
|
|
28016
|
+
headers.forEach((value, key) => {
|
|
28017
|
+
xhr.setRequestHeader(key, value);
|
|
28018
|
+
});
|
|
28019
|
+
}
|
|
28020
|
+
if (init.credentials === "include") {
|
|
28021
|
+
xhr.withCredentials = true;
|
|
28022
|
+
}
|
|
28023
|
+
const onAbort = () => xhr.abort();
|
|
28024
|
+
if (init.signal) {
|
|
28025
|
+
if (init.signal.aborted) {
|
|
28026
|
+
xhr.abort();
|
|
28027
|
+
return;
|
|
28028
|
+
}
|
|
28029
|
+
init.signal.addEventListener("abort", onAbort);
|
|
28030
|
+
}
|
|
28031
|
+
const cleanup = () => {
|
|
28032
|
+
var _a3;
|
|
28033
|
+
(_a3 = init.signal) == null ? void 0 : _a3.removeEventListener("abort", onAbort);
|
|
28034
|
+
};
|
|
28035
|
+
if (options == null ? void 0 : options.onProgress) {
|
|
28036
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
28037
|
+
options.onProgress(event, xhr);
|
|
28038
|
+
});
|
|
28039
|
+
xhr.addEventListener("progress", (event) => {
|
|
28040
|
+
options.onProgress(event, xhr);
|
|
28041
|
+
});
|
|
28042
|
+
}
|
|
28043
|
+
xhr.addEventListener("load", () => {
|
|
28044
|
+
cleanup();
|
|
28045
|
+
const status = xhr.status;
|
|
28046
|
+
const ok2 = status >= 200 && status < 300;
|
|
28047
|
+
const responseHeaders = new Headers();
|
|
28048
|
+
const rawHeaders = xhr.getAllResponseHeaders().trim();
|
|
28049
|
+
if (rawHeaders) {
|
|
28050
|
+
rawHeaders.split("\r\n").forEach((line) => {
|
|
28051
|
+
const idx = line.indexOf(": ");
|
|
28052
|
+
if (idx > 0) {
|
|
28053
|
+
responseHeaders.append(
|
|
28054
|
+
line.substring(0, idx),
|
|
28055
|
+
line.substring(idx + 2)
|
|
28056
|
+
);
|
|
28057
|
+
}
|
|
28058
|
+
});
|
|
28059
|
+
}
|
|
28060
|
+
const contentType = responseHeaders.get("content-type");
|
|
28061
|
+
const isJson = contentType == null ? void 0 : contentType.includes("application/json");
|
|
28062
|
+
let data;
|
|
28063
|
+
try {
|
|
28064
|
+
data = isJson ? JSON.parse(xhr.responseText) : xhr.responseText;
|
|
28065
|
+
} catch {
|
|
28066
|
+
data = xhr.responseText;
|
|
28067
|
+
}
|
|
28068
|
+
resolve({ ok: ok2, status, headers: responseHeaders, data });
|
|
28069
|
+
});
|
|
28070
|
+
xhr.addEventListener("error", () => {
|
|
28071
|
+
cleanup();
|
|
28072
|
+
reject(new TypeError("Network request failed"));
|
|
28073
|
+
});
|
|
28074
|
+
xhr.addEventListener("abort", () => {
|
|
28075
|
+
cleanup();
|
|
28076
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
28077
|
+
});
|
|
28078
|
+
xhr.send(init.body);
|
|
28079
|
+
});
|
|
28080
|
+
};
|
|
28081
|
+
async function executeFetch(baseUrl, path2, method, defaultOptions2, requestOptions, nextTags) {
|
|
28082
|
+
return executeCoreFetch({
|
|
28083
|
+
baseUrl,
|
|
28084
|
+
path: path2,
|
|
28085
|
+
method,
|
|
28086
|
+
defaultOptions: defaultOptions2,
|
|
28087
|
+
requestOptions,
|
|
28088
|
+
middlewareFetchInit: void 0,
|
|
28089
|
+
nextTags
|
|
28090
|
+
});
|
|
28091
|
+
}
|
|
28092
|
+
function buildInputFields(requestOptions) {
|
|
28093
|
+
const fields = {};
|
|
28094
|
+
if ((requestOptions == null ? void 0 : requestOptions.query) !== void 0) {
|
|
28095
|
+
fields.query = requestOptions.query;
|
|
28096
|
+
}
|
|
28097
|
+
if ((requestOptions == null ? void 0 : requestOptions.body) !== void 0) {
|
|
28098
|
+
fields.body = requestOptions.body;
|
|
28099
|
+
}
|
|
28100
|
+
if ((requestOptions == null ? void 0 : requestOptions.params) !== void 0) {
|
|
28101
|
+
fields.params = requestOptions.params;
|
|
28102
|
+
}
|
|
28103
|
+
if (Object.keys(fields).length === 0) {
|
|
28104
|
+
return {};
|
|
28105
|
+
}
|
|
28106
|
+
return { input: fields };
|
|
28107
|
+
}
|
|
28108
|
+
function resolveTransport(option) {
|
|
28109
|
+
if (option === "xhr" && typeof XMLHttpRequest !== "undefined") {
|
|
28110
|
+
return xhrTransport;
|
|
28111
|
+
}
|
|
28112
|
+
return fetchTransport;
|
|
28113
|
+
}
|
|
28114
|
+
async function executeCoreFetch(config2) {
|
|
28115
|
+
const {
|
|
28116
|
+
baseUrl,
|
|
28117
|
+
path: path2,
|
|
28118
|
+
method,
|
|
27555
28119
|
defaultOptions: defaultOptions2,
|
|
27556
28120
|
requestOptions,
|
|
27557
28121
|
middlewareFetchInit,
|
|
@@ -29595,19 +30159,19 @@ function resolveInvalidateTags(path2, params, invalidateOption, autoInvalidate,
|
|
|
29595
30159
|
return ["*"];
|
|
29596
30160
|
}
|
|
29597
30161
|
if (typeof invalidateOption === "string") {
|
|
29598
|
-
const normalized = normalizeTag
|
|
30162
|
+
const normalized = normalizeTag(invalidateOption);
|
|
29599
30163
|
if (normalized === "*") {
|
|
29600
30164
|
return ["*"];
|
|
29601
30165
|
}
|
|
29602
30166
|
return [normalized];
|
|
29603
30167
|
}
|
|
29604
30168
|
if (Array.isArray(invalidateOption)) {
|
|
29605
|
-
return [...new Set(invalidateOption.map(normalizeTag
|
|
30169
|
+
return [...new Set(invalidateOption.map(normalizeTag))];
|
|
29606
30170
|
}
|
|
29607
30171
|
if (!autoInvalidate) {
|
|
29608
30172
|
return false;
|
|
29609
30173
|
}
|
|
29610
|
-
const resolvedPath = normalizeTag
|
|
30174
|
+
const resolvedPath = normalizeTag(resolvePathString(path2, params));
|
|
29611
30175
|
const segments = resolvedPath.split("/");
|
|
29612
30176
|
const depth = calculateSegmentDepth(resolvedPath, groups);
|
|
29613
30177
|
const baseSegments = segments.slice(0, depth);
|
|
@@ -29669,7 +30233,7 @@ function invalidationPlugin(config2 = {}) {
|
|
|
29669
30233
|
eventEmitter.emit("refetchAll", void 0);
|
|
29670
30234
|
return;
|
|
29671
30235
|
}
|
|
29672
|
-
const patterns = rawPatterns.map(normalizeTag
|
|
30236
|
+
const patterns = rawPatterns.map(normalizeTag);
|
|
29673
30237
|
if (patterns.includes("*")) {
|
|
29674
30238
|
et == null ? void 0 : et.emit("Refetch all (manual)", { color: "warning" });
|
|
29675
30239
|
eventEmitter.emit("refetchAll", void 0);
|
|
@@ -31156,14 +31720,186 @@ function FolderPickerDialog({ initialPath, onSelect, onClose }) {
|
|
|
31156
31720
|
}
|
|
31157
31721
|
) });
|
|
31158
31722
|
}
|
|
31723
|
+
function AgentBinarySelect({
|
|
31724
|
+
value,
|
|
31725
|
+
onChange,
|
|
31726
|
+
floatingStrategy,
|
|
31727
|
+
menuClassName
|
|
31728
|
+
}) {
|
|
31729
|
+
const available = useRead((api) => api("agents/available").GET());
|
|
31730
|
+
const availableIds = new Set((available.data ?? []).map((a2) => a2.id));
|
|
31731
|
+
const isMissing = (id) => available.data != null && !availableIds.has(id);
|
|
31732
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
31733
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31734
|
+
Select_default,
|
|
31735
|
+
{
|
|
31736
|
+
value,
|
|
31737
|
+
floatingStrategy,
|
|
31738
|
+
menuClassName,
|
|
31739
|
+
onChange: (v2) => onChange(v2),
|
|
31740
|
+
children: AGENT_BINARY_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 w-full", children: [
|
|
31741
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: isMissing(o2.value) ? "text-[#8888a0]" : "", children: o2.label }),
|
|
31742
|
+
isMissing(o2.value) && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { size: 11, className: "text-amber-500 ml-auto shrink-0" })
|
|
31743
|
+
] }) }, o2.value))
|
|
31744
|
+
}
|
|
31745
|
+
),
|
|
31746
|
+
isMissing(value) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-[10px] text-amber-400", children: [
|
|
31747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { size: 11, className: "shrink-0" }),
|
|
31748
|
+
"Not installed — this agent won't run."
|
|
31749
|
+
] })
|
|
31750
|
+
] });
|
|
31751
|
+
}
|
|
31752
|
+
function ModelSelect({
|
|
31753
|
+
agentId,
|
|
31754
|
+
value,
|
|
31755
|
+
onChange,
|
|
31756
|
+
floatingStrategy,
|
|
31757
|
+
menuClassName
|
|
31758
|
+
}) {
|
|
31759
|
+
const staticOptions = MODEL_OPTIONS[agentId];
|
|
31760
|
+
const isDynamic = agentId === "opencode" || agentId === "cursor";
|
|
31761
|
+
const modelsRead = useRead(
|
|
31762
|
+
(api) => api("agents/models").GET({
|
|
31763
|
+
query: { agent: agentId === "cursor" ? "cursor" : "opencode" }
|
|
31764
|
+
}),
|
|
31765
|
+
{ enabled: isDynamic }
|
|
31766
|
+
);
|
|
31767
|
+
const dynamicModels = modelsRead.data ?? [];
|
|
31768
|
+
const isFetching = modelsRead.fetching;
|
|
31769
|
+
const options = isDynamic ? dynamicModels : staticOptions;
|
|
31770
|
+
const [customChosen, setCustomChosen] = reactExports.useState(false);
|
|
31771
|
+
const isPresetValue = value === "" || options.some((o2) => o2.value === value);
|
|
31772
|
+
const customMode = customChosen || !isPresetValue;
|
|
31773
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
31774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
31775
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31776
|
+
Select_default,
|
|
31777
|
+
{
|
|
31778
|
+
floatingStrategy,
|
|
31779
|
+
menuClassName,
|
|
31780
|
+
value: customMode ? "__custom__" : value,
|
|
31781
|
+
onChange: (v2) => {
|
|
31782
|
+
if (v2 === "__custom__") {
|
|
31783
|
+
setCustomChosen(true);
|
|
31784
|
+
} else {
|
|
31785
|
+
setCustomChosen(false);
|
|
31786
|
+
onChange(v2);
|
|
31787
|
+
}
|
|
31788
|
+
},
|
|
31789
|
+
filterable: true,
|
|
31790
|
+
children: [
|
|
31791
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "", label: "Default" }),
|
|
31792
|
+
options.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value)),
|
|
31793
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "__custom__", label: "Custom..." })
|
|
31794
|
+
]
|
|
31795
|
+
}
|
|
31796
|
+
) }),
|
|
31797
|
+
isDynamic && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31798
|
+
"button",
|
|
31799
|
+
{
|
|
31800
|
+
type: "button",
|
|
31801
|
+
onClick: () => void modelsRead.trigger(),
|
|
31802
|
+
disabled: isFetching,
|
|
31803
|
+
title: "Refresh model list",
|
|
31804
|
+
className: "flex items-center justify-center px-2 rounded border border-[var(--color-border-secondary)] bg-[#1a1a1f] hover:bg-[var(--color-surface-hover)] disabled:opacity-50 transition-colors",
|
|
31805
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31806
|
+
"svg",
|
|
31807
|
+
{
|
|
31808
|
+
className: classNames("w-4 h-4", isFetching ? "animate-spin" : ""),
|
|
31809
|
+
fill: "none",
|
|
31810
|
+
viewBox: "0 0 24 24",
|
|
31811
|
+
stroke: "currentColor",
|
|
31812
|
+
strokeWidth: 2,
|
|
31813
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31814
|
+
"path",
|
|
31815
|
+
{
|
|
31816
|
+
strokeLinecap: "round",
|
|
31817
|
+
strokeLinejoin: "round",
|
|
31818
|
+
d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
|
31819
|
+
}
|
|
31820
|
+
)
|
|
31821
|
+
}
|
|
31822
|
+
)
|
|
31823
|
+
}
|
|
31824
|
+
)
|
|
31825
|
+
] }),
|
|
31826
|
+
customMode && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31827
|
+
Input_default,
|
|
31828
|
+
{
|
|
31829
|
+
value,
|
|
31830
|
+
onChange: (e) => onChange(e.target.value),
|
|
31831
|
+
placeholder: agentId === "opencode" ? "e.g. anthropic/claude-opus-4-7" : agentId === "cursor" ? "e.g. claude-opus-4-7-thinking-max" : agentId === "claude" ? "e.g. claude-opus-4-7" : "e.g. gpt-5-codex"
|
|
31832
|
+
}
|
|
31833
|
+
)
|
|
31834
|
+
] });
|
|
31835
|
+
}
|
|
31836
|
+
function AgentModelPicker({
|
|
31837
|
+
value,
|
|
31838
|
+
onChange,
|
|
31839
|
+
floatingStrategy,
|
|
31840
|
+
menuClassName
|
|
31841
|
+
}) {
|
|
31842
|
+
const agentId = value.agentId ?? "claude";
|
|
31843
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start", children: [
|
|
31844
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full sm:w-32 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31845
|
+
AgentBinarySelect,
|
|
31846
|
+
{
|
|
31847
|
+
value: agentId,
|
|
31848
|
+
floatingStrategy,
|
|
31849
|
+
menuClassName,
|
|
31850
|
+
onChange: (v2) => onChange({ ...value, agentId: v2, model: null })
|
|
31851
|
+
}
|
|
31852
|
+
) }),
|
|
31853
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31854
|
+
ModelSelect,
|
|
31855
|
+
{
|
|
31856
|
+
agentId,
|
|
31857
|
+
value: value.model ?? "",
|
|
31858
|
+
onChange: (v2) => onChange({ ...value, model: v2 || null }),
|
|
31859
|
+
floatingStrategy,
|
|
31860
|
+
menuClassName
|
|
31861
|
+
}
|
|
31862
|
+
) }),
|
|
31863
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full sm:w-36 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31864
|
+
Select_default,
|
|
31865
|
+
{
|
|
31866
|
+
value: value.effort ?? "",
|
|
31867
|
+
floatingStrategy,
|
|
31868
|
+
menuClassName,
|
|
31869
|
+
onChange: (v2) => onChange({ ...value, effort: v2 || null }),
|
|
31870
|
+
children: [
|
|
31871
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "", label: "Default effort" }),
|
|
31872
|
+
EFFORT_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value))
|
|
31873
|
+
]
|
|
31874
|
+
}
|
|
31875
|
+
) })
|
|
31876
|
+
] });
|
|
31877
|
+
}
|
|
31878
|
+
function BranchSelect({ branches, value, onChange, placeholder = "Select branch" }) {
|
|
31879
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31880
|
+
Select_default,
|
|
31881
|
+
{
|
|
31882
|
+
value,
|
|
31883
|
+
onChange: (v2) => onChange(v2),
|
|
31884
|
+
placeholder,
|
|
31885
|
+
filterable: true,
|
|
31886
|
+
prefix: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { size: 13, className: "text-[#8888a0]" }),
|
|
31887
|
+
children: branches.map((b2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: b2, label: b2 }, b2))
|
|
31888
|
+
}
|
|
31889
|
+
);
|
|
31890
|
+
}
|
|
31159
31891
|
function ConfigureStep({
|
|
31160
31892
|
repoPath,
|
|
31893
|
+
branches,
|
|
31161
31894
|
adding,
|
|
31162
31895
|
onBack,
|
|
31163
31896
|
onAdd
|
|
31164
31897
|
}) {
|
|
31898
|
+
const { setValue } = useFormContext();
|
|
31165
31899
|
const folderName = repoPath.split("/").filter(Boolean).at(-1) ?? repoPath;
|
|
31166
31900
|
const deliveryMode = useWatch({ name: "deliveryMode" });
|
|
31901
|
+
const defaultBaseBranch = useWatch({ name: "defaultBaseBranch" }) ?? "";
|
|
31902
|
+
const assistantModel = useWatch({ name: "assistantModel" }) ?? DEFAULT_AGENT_MODEL_CHOICE;
|
|
31167
31903
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
|
|
31168
31904
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-6 flex flex-col gap-5", children: [
|
|
31169
31905
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
@@ -31194,12 +31930,36 @@ function ConfigureStep({
|
|
|
31194
31930
|
] })
|
|
31195
31931
|
] })
|
|
31196
31932
|
] }),
|
|
31933
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3.5", children: [
|
|
31934
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-medium uppercase text-[#4a4a5a] tracking-[1px]", children: "Git defaults" }),
|
|
31935
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
31936
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31937
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#c0c0d0]", children: "Default base branch" }),
|
|
31938
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-0.5 text-[#4a4a5a]", children: "Used when creating new tasks and stories." })
|
|
31939
|
+
] }),
|
|
31940
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-40", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31941
|
+
BranchSelect,
|
|
31942
|
+
{
|
|
31943
|
+
branches,
|
|
31944
|
+
value: defaultBaseBranch,
|
|
31945
|
+
onChange: (v2) => setValue("defaultBaseBranch", v2 || void 0, { shouldDirty: true }),
|
|
31946
|
+
placeholder: "main"
|
|
31947
|
+
}
|
|
31948
|
+
) })
|
|
31949
|
+
] })
|
|
31950
|
+
] }),
|
|
31197
31951
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2.5", children: [
|
|
31198
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-medium uppercase text-[#4a4a5a] tracking-[1px]", children: "
|
|
31199
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31200
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31201
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31202
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("
|
|
31952
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-medium uppercase text-[#4a4a5a] tracking-[1px]", children: "Assistant" }),
|
|
31953
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
31954
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#c0c0d0]", children: "Agent & model" }),
|
|
31955
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-[#4a4a5a]", children: "Which agent runs the in-app assistant." }),
|
|
31956
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31957
|
+
AgentModelPicker,
|
|
31958
|
+
{
|
|
31959
|
+
value: assistantModel,
|
|
31960
|
+
onChange: (next2) => setValue("assistantModel", next2, { shouldDirty: true })
|
|
31961
|
+
}
|
|
31962
|
+
) })
|
|
31203
31963
|
] })
|
|
31204
31964
|
] })
|
|
31205
31965
|
] }),
|
|
@@ -31341,7 +32101,8 @@ function AddProjectDialog({ onClose, onAdded }) {
|
|
|
31341
32101
|
values: {
|
|
31342
32102
|
repoPath: "",
|
|
31343
32103
|
deliveryMode: "off",
|
|
31344
|
-
|
|
32104
|
+
defaultBaseBranch: void 0,
|
|
32105
|
+
assistantModel: DEFAULT_AGENT_MODEL_CHOICE
|
|
31345
32106
|
}
|
|
31346
32107
|
});
|
|
31347
32108
|
const { control, getValues, setValue } = methods;
|
|
@@ -31364,12 +32125,19 @@ function AddProjectDialog({ onClose, onAdded }) {
|
|
|
31364
32125
|
const pathStatus = !trimmed ? "idle" : trimmed !== debouncedPath || checking ? "checking" : checkError ? "invalid" : pathData ? pathData.valid ? "valid" : "invalid" : "checking";
|
|
31365
32126
|
const pathError = checkError ? "Failed to check path" : pathStatus === "invalid" ? (pathData == null ? void 0 : pathData.error) ?? null : null;
|
|
31366
32127
|
const repoInfo = pathStatus === "valid" && pathData ? { name: pathData.name, branch: pathData.branch, remote: pathData.remote } : { name: null, branch: null, remote: null };
|
|
32128
|
+
const currentBranch = repoInfo.branch;
|
|
32129
|
+
reactExports.useEffect(() => {
|
|
32130
|
+
if (currentBranch && !getValues("defaultBaseBranch")) {
|
|
32131
|
+
setValue("defaultBaseBranch", currentBranch);
|
|
32132
|
+
}
|
|
32133
|
+
}, [currentBranch, getValues, setValue]);
|
|
31367
32134
|
const addProjectWrite = useWrite((api) => api("projects").POST());
|
|
31368
32135
|
const handleAdd = methods.handleSubmit(async (values) => {
|
|
31369
32136
|
var _a3, _b2;
|
|
31370
32137
|
const initialConfig = {
|
|
31371
32138
|
deliveryMode: values.deliveryMode,
|
|
31372
|
-
|
|
32139
|
+
defaultBaseBranch: ((_a3 = values.defaultBaseBranch) == null ? void 0 : _a3.trim()) || void 0,
|
|
32140
|
+
assistantModel: values.assistantModel
|
|
31373
32141
|
};
|
|
31374
32142
|
const res = await addProjectWrite.trigger({
|
|
31375
32143
|
body: { repoPath: values.repoPath.trim(), initialConfig }
|
|
@@ -31471,6 +32239,7 @@ function AddProjectDialog({ onClose, onAdded }) {
|
|
|
31471
32239
|
ConfigureStep,
|
|
31472
32240
|
{
|
|
31473
32241
|
repoPath: getValues("repoPath"),
|
|
32242
|
+
branches: (pathData == null ? void 0 : pathData.branches) ?? [],
|
|
31474
32243
|
adding: addProjectWrite.loading,
|
|
31475
32244
|
onBack: () => setStep("select"),
|
|
31476
32245
|
onAdd: () => void handleAdd()
|
|
@@ -48654,195 +49423,34 @@ const ConnectedDroppable = connect_default(makeMapStateToProps, mapDispatchToPro
|
|
|
48654
49423
|
return {
|
|
48655
49424
|
...attachDefaultPropsToOwnProps(ownProps),
|
|
48656
49425
|
...stateProps,
|
|
48657
|
-
...dispatchProps
|
|
48658
|
-
};
|
|
48659
|
-
}, {
|
|
48660
|
-
context: StoreContext,
|
|
48661
|
-
areStatePropsEqual: isStrictEqual
|
|
48662
|
-
})(Droppable);
|
|
48663
|
-
function EmptyFolderSlot({ dp }) {
|
|
48664
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: dp.innerRef, ...dp.draggableProps, ...dp.dragHandleProps, className: "pl-10 pr-2.5 py-[3px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-7 border border-dashed border-[#2a2a35] rounded-md flex items-center pl-2.5 gap-1.5", children: [
|
|
48665
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-1 h-1 rounded-full bg-[#2a2a35]" }),
|
|
48666
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-[#3a3a45]", children: "Drop project here" })
|
|
48667
|
-
] }) });
|
|
48668
|
-
}
|
|
48669
|
-
function FolderHeader({
|
|
48670
|
-
folderId,
|
|
48671
|
-
folder,
|
|
48672
|
-
dp,
|
|
48673
|
-
snap,
|
|
48674
|
-
expanded,
|
|
48675
|
-
hovered,
|
|
48676
|
-
editing,
|
|
48677
|
-
editName,
|
|
48678
|
-
editRef,
|
|
48679
|
-
onToggleCollapse,
|
|
48680
|
-
onStartRename,
|
|
48681
|
-
onDeleteFolder,
|
|
48682
|
-
onEditNameChange,
|
|
48683
|
-
onCommitRename,
|
|
48684
|
-
onCancelRename
|
|
48685
|
-
}) {
|
|
48686
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
48687
|
-
"div",
|
|
48688
|
-
{
|
|
48689
|
-
ref: dp.innerRef,
|
|
48690
|
-
...dp.draggableProps,
|
|
48691
|
-
...dp.dragHandleProps,
|
|
48692
|
-
onClick: () => onToggleCollapse(folderId),
|
|
48693
|
-
className: "group flex items-center gap-1.5 h-8 pl-2.5 pr-2 rounded-md my-px mx-1 cursor-pointer select-none transition-colors",
|
|
48694
|
-
style: {
|
|
48695
|
-
...dp.draggableProps.style,
|
|
48696
|
-
background: snap.isDragging ? "#1f1f28" : hovered ? "#7c6aff15" : "transparent"
|
|
48697
|
-
},
|
|
48698
|
-
children: [
|
|
48699
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 flex items-center justify-center w-3.5 text-[#4a4a5a]", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 11 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 11 }) }),
|
|
48700
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Folder, { size: 13, className: classNames("shrink-0", hovered ? "text-[#7c6aff]" : "text-[#60607a]") }),
|
|
48701
|
-
editing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48702
|
-
"input",
|
|
48703
|
-
{
|
|
48704
|
-
ref: editRef,
|
|
48705
|
-
value: editName,
|
|
48706
|
-
onChange: (e) => onEditNameChange(e.target.value),
|
|
48707
|
-
onBlur: onCommitRename,
|
|
48708
|
-
onClick: (e) => e.stopPropagation(),
|
|
48709
|
-
onKeyDown: (e) => {
|
|
48710
|
-
if (e.key === "Enter") onCommitRename();
|
|
48711
|
-
if (e.key === "Escape") onCancelRename();
|
|
48712
|
-
},
|
|
48713
|
-
className: "flex-1 min-w-0 outline-none text-[11px] rounded px-1 bg-[#0c0c0f] border border-[#3a3a55] text-[#f0f0f5]"
|
|
48714
|
-
}
|
|
48715
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48716
|
-
"span",
|
|
48717
|
-
{
|
|
48718
|
-
className: classNames(
|
|
48719
|
-
"flex-1 min-w-0 truncate text-[11px] font-medium tracking-[0.2px]",
|
|
48720
|
-
hovered ? "text-[#c0c0d0]" : "text-[#8888a0]"
|
|
48721
|
-
),
|
|
48722
|
-
onDoubleClick: (e) => {
|
|
48723
|
-
e.stopPropagation();
|
|
48724
|
-
onStartRename(folderId);
|
|
48725
|
-
},
|
|
48726
|
-
children: folder.name
|
|
48727
|
-
}
|
|
48728
|
-
),
|
|
48729
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity", children: [
|
|
48730
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48731
|
-
"button",
|
|
48732
|
-
{
|
|
48733
|
-
onClick: (e) => {
|
|
48734
|
-
e.stopPropagation();
|
|
48735
|
-
onStartRename(folderId);
|
|
48736
|
-
},
|
|
48737
|
-
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#2a2a35] transition-colors text-[#60607a]",
|
|
48738
|
-
title: "Rename",
|
|
48739
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Pencil, { size: 10 })
|
|
48740
|
-
}
|
|
48741
|
-
),
|
|
48742
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48743
|
-
"button",
|
|
48744
|
-
{
|
|
48745
|
-
onClick: (e) => {
|
|
48746
|
-
e.stopPropagation();
|
|
48747
|
-
onDeleteFolder(folderId);
|
|
48748
|
-
},
|
|
48749
|
-
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#ef444420] transition-colors text-[#60607a]",
|
|
48750
|
-
title: "Delete",
|
|
48751
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
|
|
48752
|
-
}
|
|
48753
|
-
)
|
|
48754
|
-
] })
|
|
48755
|
-
]
|
|
48756
|
-
}
|
|
48757
|
-
);
|
|
48758
|
-
}
|
|
48759
|
-
function genId() {
|
|
48760
|
-
return Math.random().toString(36).slice(2, 10);
|
|
48761
|
-
}
|
|
48762
|
-
function buildFlat(layout, expandAll, isDragging2 = false) {
|
|
48763
|
-
var _a3, _b2;
|
|
48764
|
-
const flat = [];
|
|
48765
|
-
for (const item of layout.topLevel) {
|
|
48766
|
-
if (item.type === "folder") {
|
|
48767
|
-
flat.push({ kind: "folder-header", folderId: item.id });
|
|
48768
|
-
const expanded = expandAll || !((_a3 = layout.folders[item.id]) == null ? void 0 : _a3.collapsed);
|
|
48769
|
-
if (expanded) {
|
|
48770
|
-
const projectIds = ((_b2 = layout.folders[item.id]) == null ? void 0 : _b2.projectIds) ?? [];
|
|
48771
|
-
for (const wsId of projectIds) {
|
|
48772
|
-
flat.push({ kind: "project", workspaceId: wsId, folderId: item.id });
|
|
48773
|
-
}
|
|
48774
|
-
if (isDragging2 && projectIds.length === 0) {
|
|
48775
|
-
flat.push({ kind: "empty-folder-slot", folderId: item.id });
|
|
48776
|
-
}
|
|
48777
|
-
}
|
|
48778
|
-
} else {
|
|
48779
|
-
flat.push({ kind: "project", workspaceId: item.workspaceId, folderId: null });
|
|
48780
|
-
}
|
|
48781
|
-
}
|
|
48782
|
-
return flat;
|
|
48783
|
-
}
|
|
48784
|
-
function flatToLayout(flat, existing) {
|
|
48785
|
-
var _a3;
|
|
48786
|
-
const topLevel = [];
|
|
48787
|
-
const folders = Object.fromEntries(
|
|
48788
|
-
Object.entries(existing.folders).map(([k, v2]) => [k, { ...v2, projectIds: [] }])
|
|
48789
|
-
);
|
|
48790
|
-
const seen2 = /* @__PURE__ */ new Set();
|
|
48791
|
-
for (const item of flat) {
|
|
48792
|
-
if (item.kind === "empty-folder-slot") continue;
|
|
48793
|
-
if (item.kind === "folder-header") {
|
|
48794
|
-
if (!seen2.has(item.folderId)) {
|
|
48795
|
-
seen2.add(item.folderId);
|
|
48796
|
-
topLevel.push({ type: "folder", id: item.folderId });
|
|
48797
|
-
}
|
|
48798
|
-
} else if (item.folderId !== null) {
|
|
48799
|
-
(_a3 = folders[item.folderId]) == null ? void 0 : _a3.projectIds.push(item.workspaceId);
|
|
48800
|
-
} else {
|
|
48801
|
-
topLevel.push({ type: "project", workspaceId: item.workspaceId });
|
|
48802
|
-
}
|
|
48803
|
-
}
|
|
48804
|
-
return { ...existing, topLevel, folders };
|
|
48805
|
-
}
|
|
48806
|
-
function folderAtDest(flat, destIndex) {
|
|
48807
|
-
const after = flat[destIndex];
|
|
48808
|
-
if (!after) {
|
|
48809
|
-
const prev = flat[destIndex - 1];
|
|
48810
|
-
if (!prev || prev.kind === "folder-header") return null;
|
|
48811
|
-
if (prev.kind === "empty-folder-slot") return prev.folderId;
|
|
48812
|
-
return prev.folderId;
|
|
48813
|
-
}
|
|
48814
|
-
if (after.kind === "folder-header") return after.folderId;
|
|
48815
|
-
if (after.kind === "empty-folder-slot") return after.folderId;
|
|
48816
|
-
return after.folderId;
|
|
48817
|
-
}
|
|
48818
|
-
function syncLayout(layout, projects) {
|
|
48819
|
-
const known = new Set(projects.map((p) => p.workspaceId));
|
|
48820
|
-
const topLevel = layout.topLevel.filter((i2) => i2.type === "folder" || known.has(i2.workspaceId));
|
|
48821
|
-
const folders = Object.fromEntries(
|
|
48822
|
-
Object.entries(layout.folders).map(([id, f]) => [
|
|
48823
|
-
id,
|
|
48824
|
-
{ ...f, projectIds: f.projectIds.filter((id2) => known.has(id2)) }
|
|
48825
|
-
])
|
|
48826
|
-
);
|
|
48827
|
-
const inLayout = /* @__PURE__ */ new Set();
|
|
48828
|
-
for (const i2 of topLevel) {
|
|
48829
|
-
if (i2.type === "project") inLayout.add(i2.workspaceId);
|
|
48830
|
-
}
|
|
48831
|
-
for (const f of Object.values(folders)) {
|
|
48832
|
-
for (const id of f.projectIds) inLayout.add(id);
|
|
48833
|
-
}
|
|
48834
|
-
const newItems = projects.filter((p) => !inLayout.has(p.workspaceId)).map((p) => ({ type: "project", workspaceId: p.workspaceId }));
|
|
48835
|
-
return { ...layout, topLevel: [...topLevel, ...newItems], folders };
|
|
49426
|
+
...dispatchProps
|
|
49427
|
+
};
|
|
49428
|
+
}, {
|
|
49429
|
+
context: StoreContext,
|
|
49430
|
+
areStatePropsEqual: isStrictEqual
|
|
49431
|
+
})(Droppable);
|
|
49432
|
+
function EmptyFolderSlot({ dp }) {
|
|
49433
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: dp.innerRef, ...dp.draggableProps, ...dp.dragHandleProps, className: "pl-10 pr-2.5 py-[3px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-7 border border-dashed border-[#2a2a35] rounded-md flex items-center pl-2.5 gap-1.5", children: [
|
|
49434
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-1 h-1 rounded-full bg-[#2a2a35]" }),
|
|
49435
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-[#3a3a45]", children: "Drop project here" })
|
|
49436
|
+
] }) });
|
|
48836
49437
|
}
|
|
48837
|
-
function
|
|
48838
|
-
|
|
48839
|
-
|
|
49438
|
+
function FolderHeader({
|
|
49439
|
+
folderId,
|
|
49440
|
+
folder,
|
|
48840
49441
|
dp,
|
|
48841
49442
|
snap,
|
|
48842
|
-
|
|
48843
|
-
|
|
48844
|
-
|
|
48845
|
-
|
|
49443
|
+
expanded,
|
|
49444
|
+
hovered,
|
|
49445
|
+
editing,
|
|
49446
|
+
editName,
|
|
49447
|
+
editRef,
|
|
49448
|
+
onToggleCollapse,
|
|
49449
|
+
onStartRename,
|
|
49450
|
+
onDeleteFolder,
|
|
49451
|
+
onEditNameChange,
|
|
49452
|
+
onCommitRename,
|
|
49453
|
+
onCancelRename
|
|
48846
49454
|
}) {
|
|
48847
49455
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
48848
49456
|
"div",
|
|
@@ -48850,916 +49458,514 @@ function ProjectItem({
|
|
|
48850
49458
|
ref: dp.innerRef,
|
|
48851
49459
|
...dp.draggableProps,
|
|
48852
49460
|
...dp.dragHandleProps,
|
|
48853
|
-
onClick: () =>
|
|
48854
|
-
className:
|
|
48855
|
-
"group flex items-center gap-2 h-8 pr-2 my-px mx-1 rounded-md cursor-pointer select-none transition-colors",
|
|
48856
|
-
indent2 ? "pl-10" : "pl-3",
|
|
48857
|
-
snap.isDragging ? "opacity-70" : isActive2 ? "" : "hover:bg-[#1a1a1f]"
|
|
48858
|
-
),
|
|
49461
|
+
onClick: () => onToggleCollapse(folderId),
|
|
49462
|
+
className: "group flex items-center gap-1.5 h-8 pl-2.5 pr-2 rounded-md my-px mx-1 cursor-pointer select-none transition-colors",
|
|
48859
49463
|
style: {
|
|
48860
49464
|
...dp.draggableProps.style,
|
|
48861
|
-
background:
|
|
48862
|
-
borderLeft: isActive2 && !snap.isDragging ? "2px solid #7c6aff" : "2px solid transparent"
|
|
49465
|
+
background: snap.isDragging ? "#1f1f28" : hovered ? "#7c6aff15" : "transparent"
|
|
48863
49466
|
},
|
|
48864
49467
|
children: [
|
|
48865
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48866
|
-
|
|
49468
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 flex items-center justify-center w-3.5 text-[#4a4a5a]", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 11 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 11 }) }),
|
|
49469
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Folder, { size: 13, className: classNames("shrink-0", hovered ? "text-[#7c6aff]" : "text-[#60607a]") }),
|
|
49470
|
+
editing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49471
|
+
"input",
|
|
48867
49472
|
{
|
|
48868
|
-
|
|
48869
|
-
|
|
49473
|
+
ref: editRef,
|
|
49474
|
+
value: editName,
|
|
49475
|
+
onChange: (e) => onEditNameChange(e.target.value),
|
|
49476
|
+
onBlur: onCommitRename,
|
|
49477
|
+
onClick: (e) => e.stopPropagation(),
|
|
49478
|
+
onKeyDown: (e) => {
|
|
49479
|
+
if (e.key === "Enter") onCommitRename();
|
|
49480
|
+
if (e.key === "Escape") onCancelRename();
|
|
49481
|
+
},
|
|
49482
|
+
className: "flex-1 min-w-0 outline-none text-[11px] rounded px-1 bg-[#0c0c0f] border border-[#3a3a55] text-[#f0f0f5]"
|
|
48870
49483
|
}
|
|
48871
|
-
)
|
|
48872
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49484
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48873
49485
|
"span",
|
|
48874
49486
|
{
|
|
48875
49487
|
className: classNames(
|
|
48876
|
-
"flex-1 min-w-0 truncate text-[
|
|
48877
|
-
|
|
49488
|
+
"flex-1 min-w-0 truncate text-[11px] font-medium tracking-[0.2px]",
|
|
49489
|
+
hovered ? "text-[#c0c0d0]" : "text-[#8888a0]"
|
|
48878
49490
|
),
|
|
48879
|
-
|
|
48880
|
-
}
|
|
48881
|
-
),
|
|
48882
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48883
|
-
"button",
|
|
48884
|
-
{
|
|
48885
|
-
onClick: (e) => {
|
|
49491
|
+
onDoubleClick: (e) => {
|
|
48886
49492
|
e.stopPropagation();
|
|
48887
|
-
|
|
48888
|
-
title: "Remove project",
|
|
48889
|
-
content: `Remove "${project.name}" from Whipped? This will stop all running agents and delete all associated worktrees and data.`,
|
|
48890
|
-
confirmButtonLabel: "Remove",
|
|
48891
|
-
cancelButtonLabel: "Cancel",
|
|
48892
|
-
onConfirm: async ({ dismiss: dismiss2 }) => {
|
|
48893
|
-
await onRemove(workspaceId);
|
|
48894
|
-
dismiss2();
|
|
48895
|
-
}
|
|
48896
|
-
});
|
|
49493
|
+
onStartRename(folderId);
|
|
48897
49494
|
},
|
|
48898
|
-
|
|
48899
|
-
title: "Remove project",
|
|
48900
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
|
|
48901
|
-
}
|
|
48902
|
-
) })
|
|
48903
|
-
]
|
|
48904
|
-
}
|
|
48905
|
-
);
|
|
48906
|
-
}
|
|
48907
|
-
const ProjectsSidebar = React.forwardRef(function ProjectsSidebar2({ projects, activeWorkspaceId, onSwitch, onRemove }, ref) {
|
|
48908
|
-
const [layout, setLayout] = reactExports.useState({ version: 1, topLevel: [], folders: {} });
|
|
48909
|
-
const [isDragging2, setIsDragging] = reactExports.useState(false);
|
|
48910
|
-
const [hoveredFolderId, setHoveredFolderId] = reactExports.useState(null);
|
|
48911
|
-
const [editingId, setEditingId] = reactExports.useState(null);
|
|
48912
|
-
const [editName, setEditName] = reactExports.useState("");
|
|
48913
|
-
const editRef = reactExports.useRef(null);
|
|
48914
|
-
const saveTimer = reactExports.useRef(null);
|
|
48915
|
-
const { trigger: fetchLayout } = useRead((api) => api("projects/layout").GET(), { enabled: false });
|
|
48916
|
-
const { trigger: saveLayout } = useWrite((api) => api("projects/layout").PUT());
|
|
48917
|
-
reactExports.useEffect(() => {
|
|
48918
|
-
fetchLayout().then((res) => setLayout((prev) => syncLayout(res.data ?? prev, projects))).catch(() => {
|
|
48919
|
-
});
|
|
48920
|
-
}, []);
|
|
48921
|
-
reactExports.useEffect(() => {
|
|
48922
|
-
setLayout((prev) => syncLayout(prev, projects));
|
|
48923
|
-
}, [projects]);
|
|
48924
|
-
const persist = (next2) => {
|
|
48925
|
-
if (saveTimer.current) clearTimeout(saveTimer.current);
|
|
48926
|
-
saveTimer.current = setTimeout(() => {
|
|
48927
|
-
saveLayout({ body: next2 }).catch(() => {
|
|
48928
|
-
});
|
|
48929
|
-
}, 300);
|
|
48930
|
-
};
|
|
48931
|
-
const update2 = (next2) => {
|
|
48932
|
-
setLayout(next2);
|
|
48933
|
-
persist(next2);
|
|
48934
|
-
};
|
|
48935
|
-
const addFolder = () => {
|
|
48936
|
-
const id = genId();
|
|
48937
|
-
const next2 = {
|
|
48938
|
-
...layout,
|
|
48939
|
-
topLevel: [...layout.topLevel, { type: "folder", id }],
|
|
48940
|
-
folders: { ...layout.folders, [id]: { id, name: "New Folder", collapsed: false, projectIds: [] } }
|
|
48941
|
-
};
|
|
48942
|
-
update2(next2);
|
|
48943
|
-
setEditingId(id);
|
|
48944
|
-
setEditName("New Folder");
|
|
48945
|
-
setTimeout(() => {
|
|
48946
|
-
var _a3, _b2;
|
|
48947
|
-
(_a3 = editRef.current) == null ? void 0 : _a3.focus();
|
|
48948
|
-
(_b2 = editRef.current) == null ? void 0 : _b2.select();
|
|
48949
|
-
}, 50);
|
|
48950
|
-
};
|
|
48951
|
-
reactExports.useImperativeHandle(ref, () => ({ addFolder }));
|
|
48952
|
-
const startRename = (id) => {
|
|
48953
|
-
var _a3;
|
|
48954
|
-
setEditingId(id);
|
|
48955
|
-
setEditName(((_a3 = layout.folders[id]) == null ? void 0 : _a3.name) ?? "");
|
|
48956
|
-
setTimeout(() => {
|
|
48957
|
-
var _a4, _b2;
|
|
48958
|
-
(_a4 = editRef.current) == null ? void 0 : _a4.focus();
|
|
48959
|
-
(_b2 = editRef.current) == null ? void 0 : _b2.select();
|
|
48960
|
-
}, 50);
|
|
48961
|
-
};
|
|
48962
|
-
const commitRename = () => {
|
|
48963
|
-
if (!editingId) return;
|
|
48964
|
-
update2({
|
|
48965
|
-
...layout,
|
|
48966
|
-
folders: {
|
|
48967
|
-
...layout.folders,
|
|
48968
|
-
[editingId]: { ...layout.folders[editingId], name: editName.trim() || "Untitled" }
|
|
48969
|
-
}
|
|
48970
|
-
});
|
|
48971
|
-
setEditingId(null);
|
|
48972
|
-
};
|
|
48973
|
-
const deleteFolder = (id) => {
|
|
48974
|
-
const folder = layout.folders[id];
|
|
48975
|
-
if (!folder) return;
|
|
48976
|
-
const idx = layout.topLevel.findIndex((i2) => i2.type === "folder" && i2.id === id);
|
|
48977
|
-
const returned = folder.projectIds.map((ws2) => ({ type: "project", workspaceId: ws2 }));
|
|
48978
|
-
const topLevel = [...layout.topLevel];
|
|
48979
|
-
topLevel.splice(idx, 1, ...returned);
|
|
48980
|
-
const folders = { ...layout.folders };
|
|
48981
|
-
delete folders[id];
|
|
48982
|
-
update2({ ...layout, topLevel, folders });
|
|
48983
|
-
};
|
|
48984
|
-
const toggleCollapse = (id) => {
|
|
48985
|
-
const f = layout.folders[id];
|
|
48986
|
-
if (!f) return;
|
|
48987
|
-
update2({ ...layout, folders: { ...layout.folders, [id]: { ...f, collapsed: !f.collapsed } } });
|
|
48988
|
-
};
|
|
48989
|
-
const onDragUpdate2 = reactExports.useCallback(
|
|
48990
|
-
(update22) => {
|
|
48991
|
-
if (!update22.destination) {
|
|
48992
|
-
setHoveredFolderId(null);
|
|
48993
|
-
return;
|
|
48994
|
-
}
|
|
48995
|
-
const flat2 = buildFlat(layout, true, true);
|
|
48996
|
-
flat2.splice(update22.source.index, 1);
|
|
48997
|
-
const folderId = folderAtDest(flat2, update22.destination.index);
|
|
48998
|
-
setHoveredFolderId(folderId);
|
|
48999
|
-
},
|
|
49000
|
-
[layout]
|
|
49001
|
-
);
|
|
49002
|
-
const onDragEnd2 = (result) => {
|
|
49003
|
-
setIsDragging(false);
|
|
49004
|
-
setHoveredFolderId(null);
|
|
49005
|
-
if (!result.destination) return;
|
|
49006
|
-
const { draggableId, source, destination } = result;
|
|
49007
|
-
if (source.index === destination.index) return;
|
|
49008
|
-
const flat2 = buildFlat(layout, true, true);
|
|
49009
|
-
if (draggableId.startsWith("fh:")) {
|
|
49010
|
-
const folderId = draggableId.slice(3);
|
|
49011
|
-
flat2.splice(source.index, 1);
|
|
49012
|
-
const group = [];
|
|
49013
|
-
while (flat2[source.index] && (flat2[source.index].kind === "project" && flat2[source.index].folderId === folderId || flat2[source.index].kind === "empty-folder-slot" && flat2[source.index].folderId === folderId)) {
|
|
49014
|
-
group.push(flat2.splice(source.index, 1)[0]);
|
|
49015
|
-
}
|
|
49016
|
-
const at2 = Math.min(destination.index, flat2.length);
|
|
49017
|
-
flat2.splice(at2, 0, { kind: "folder-header", folderId }, ...group);
|
|
49018
|
-
} else {
|
|
49019
|
-
const [moved] = flat2.splice(source.index, 1);
|
|
49020
|
-
const newFolderId = folderAtDest(flat2, destination.index);
|
|
49021
|
-
flat2.splice(destination.index, 0, { ...moved, folderId: newFolderId });
|
|
49022
|
-
}
|
|
49023
|
-
update2(flatToLayout(flat2, layout));
|
|
49024
|
-
};
|
|
49025
|
-
const projectMap = Object.fromEntries(projects.map((p) => [p.workspaceId, p]));
|
|
49026
|
-
const flat = buildFlat(layout, isDragging2, isDragging2);
|
|
49027
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(DragDropContext, { onDragStart: () => setIsDragging(true), onDragUpdate: onDragUpdate2, onDragEnd: onDragEnd2, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectedDroppable, { droppableId: "sidebar", children: (provided) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: provided.innerRef, ...provided.droppableProps, className: "flex flex-col", children: [
|
|
49028
|
-
flat.map((item, index2) => {
|
|
49029
|
-
if (item.kind === "folder-header") {
|
|
49030
|
-
const folder = layout.folders[item.folderId];
|
|
49031
|
-
if (!folder) return null;
|
|
49032
|
-
const expanded = !folder.collapsed || isDragging2;
|
|
49033
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(PublicDraggable, { draggableId: `fh:${item.folderId}`, index: index2, children: (dp, snap) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49034
|
-
FolderHeader,
|
|
49035
|
-
{
|
|
49036
|
-
folderId: item.folderId,
|
|
49037
|
-
folder,
|
|
49038
|
-
dp,
|
|
49039
|
-
snap,
|
|
49040
|
-
expanded,
|
|
49041
|
-
hovered: hoveredFolderId === item.folderId,
|
|
49042
|
-
editing: editingId === item.folderId,
|
|
49043
|
-
editName,
|
|
49044
|
-
editRef,
|
|
49045
|
-
onToggleCollapse: toggleCollapse,
|
|
49046
|
-
onStartRename: startRename,
|
|
49047
|
-
onDeleteFolder: deleteFolder,
|
|
49048
|
-
onEditNameChange: setEditName,
|
|
49049
|
-
onCommitRename: commitRename,
|
|
49050
|
-
onCancelRename: () => setEditingId(null)
|
|
49051
|
-
}
|
|
49052
|
-
) }, `fh:${item.folderId}`);
|
|
49053
|
-
}
|
|
49054
|
-
if (item.kind === "empty-folder-slot") {
|
|
49055
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49056
|
-
PublicDraggable,
|
|
49057
|
-
{
|
|
49058
|
-
draggableId: `slot:${item.folderId}`,
|
|
49059
|
-
index: index2,
|
|
49060
|
-
isDragDisabled: true,
|
|
49061
|
-
children: (dp) => /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyFolderSlot, { dp })
|
|
49062
|
-
},
|
|
49063
|
-
`slot:${item.folderId}`
|
|
49064
|
-
);
|
|
49065
|
-
}
|
|
49066
|
-
const project = projectMap[item.workspaceId];
|
|
49067
|
-
if (!project) return null;
|
|
49068
|
-
const isActive2 = item.workspaceId === activeWorkspaceId;
|
|
49069
|
-
const indent2 = item.folderId !== null;
|
|
49070
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(PublicDraggable, { draggableId: `p:${item.workspaceId}`, index: index2, children: (dp, snap) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49071
|
-
ProjectItem,
|
|
49072
|
-
{
|
|
49073
|
-
project,
|
|
49074
|
-
workspaceId: item.workspaceId,
|
|
49075
|
-
dp,
|
|
49076
|
-
snap,
|
|
49077
|
-
isActive: isActive2,
|
|
49078
|
-
indent: indent2,
|
|
49079
|
-
onSwitch,
|
|
49080
|
-
onRemove
|
|
49081
|
-
}
|
|
49082
|
-
) }, `p:${item.workspaceId}`);
|
|
49083
|
-
}),
|
|
49084
|
-
provided.placeholder
|
|
49085
|
-
] }) }) });
|
|
49086
|
-
});
|
|
49087
|
-
function CardDetailHeader({
|
|
49088
|
-
card,
|
|
49089
|
-
workspaceId,
|
|
49090
|
-
projectName,
|
|
49091
|
-
externalUrl,
|
|
49092
|
-
isStory,
|
|
49093
|
-
isReadyForReview,
|
|
49094
|
-
hasStartCommand = false,
|
|
49095
|
-
merging,
|
|
49096
|
-
onMerge,
|
|
49097
|
-
onPR,
|
|
49098
|
-
onDelete,
|
|
49099
|
-
onClose
|
|
49100
|
-
}) {
|
|
49101
|
-
var _a3, _b2, _c3;
|
|
49102
|
-
const { session: runSession, start: startRun, stop: stopRun } = useRunSession(workspaceId);
|
|
49103
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-6 py-2.5 border-b border-[#2a2a35] bg-[#141418] shrink-0", children: [
|
|
49104
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-[#60607a] hover:text-gray-300 transition-colors", title: "Back to board", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 18 }) }),
|
|
49105
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49106
|
-
projectName && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
49107
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-[#60607a]", children: projectName }),
|
|
49108
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-[#2a2a35]", children: "/" })
|
|
49109
|
-
] }),
|
|
49110
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] font-semibold text-[#f0f0f5] truncate", children: ((_a3 = card.description) == null ? void 0 : _a3.split("\n")[0]) ?? card.id }),
|
|
49111
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
49112
|
-
externalUrl && !((_b2 = card.pr) == null ? void 0 : _b2.url) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49113
|
-
"a",
|
|
49114
|
-
{
|
|
49115
|
-
href: externalUrl,
|
|
49116
|
-
target: "_blank",
|
|
49117
|
-
rel: "noreferrer",
|
|
49118
|
-
className: "text-[#60607a] hover:text-gray-300 transition-colors",
|
|
49119
|
-
title: "Open external link",
|
|
49120
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 15 })
|
|
49121
|
-
}
|
|
49122
|
-
),
|
|
49123
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49124
|
-
hasStartCommand && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: runSession.status === "running" && runSession.cardId === card.id ? /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: "Stop", side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49125
|
-
"button",
|
|
49126
|
-
{
|
|
49127
|
-
onClick: () => void stopRun(),
|
|
49128
|
-
className: "cursor-pointer text-[#60607a] hover:text-red-400 transition-colors",
|
|
49129
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Square, { size: 15, className: "fill-current" })
|
|
49130
|
-
}
|
|
49131
|
-
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49132
|
-
Tooltip_default,
|
|
49133
|
-
{
|
|
49134
|
-
delayDuration: 0,
|
|
49135
|
-
content: runSession.status === "running" ? "Another task is running" : "Run",
|
|
49136
|
-
side: "bottom",
|
|
49137
|
-
triggerAsChild: true,
|
|
49138
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49139
|
-
"button",
|
|
49140
|
-
{
|
|
49141
|
-
onClick: () => void startRun(card.id),
|
|
49142
|
-
disabled: runSession.status === "running",
|
|
49143
|
-
className: "cursor-pointer text-[#60607a] hover:text-emerald-400 transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
49144
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 15 })
|
|
49495
|
+
children: folder.name
|
|
49145
49496
|
}
|
|
49146
|
-
)
|
|
49147
|
-
|
|
49148
|
-
|
|
49149
|
-
!isStory && isReadyForReview && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
49150
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49151
|
-
Tooltip_default,
|
|
49152
|
-
{
|
|
49153
|
-
delayDuration: 0,
|
|
49154
|
-
content: merging ? "Merging..." : `Merge into ${card.baseRef}`,
|
|
49155
|
-
side: "bottom",
|
|
49156
|
-
triggerAsChild: true,
|
|
49157
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49497
|
+
),
|
|
49498
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity", children: [
|
|
49499
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49158
49500
|
"button",
|
|
49159
49501
|
{
|
|
49160
|
-
onClick:
|
|
49161
|
-
|
|
49162
|
-
|
|
49163
|
-
|
|
49502
|
+
onClick: (e) => {
|
|
49503
|
+
e.stopPropagation();
|
|
49504
|
+
onStartRename(folderId);
|
|
49505
|
+
},
|
|
49506
|
+
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#2a2a35] transition-colors text-[#60607a]",
|
|
49507
|
+
title: "Rename",
|
|
49508
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Pencil, { size: 10 })
|
|
49509
|
+
}
|
|
49510
|
+
),
|
|
49511
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49512
|
+
"button",
|
|
49513
|
+
{
|
|
49514
|
+
onClick: (e) => {
|
|
49515
|
+
e.stopPropagation();
|
|
49516
|
+
onDeleteFolder(folderId);
|
|
49517
|
+
},
|
|
49518
|
+
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#ef444420] transition-colors text-[#60607a]",
|
|
49519
|
+
title: "Delete",
|
|
49520
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
|
|
49164
49521
|
}
|
|
49165
49522
|
)
|
|
49166
|
-
}
|
|
49167
|
-
|
|
49168
|
-
|
|
49169
|
-
|
|
49170
|
-
{
|
|
49171
|
-
href: card.pr.url,
|
|
49172
|
-
target: "_blank",
|
|
49173
|
-
rel: "noreferrer",
|
|
49174
|
-
title: "Open Pull Request",
|
|
49175
|
-
className: "cursor-pointer text-green-400 hover:text-green-300 transition-colors",
|
|
49176
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitPullRequest, { size: 15 })
|
|
49177
|
-
}
|
|
49178
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: `Create PR against ${card.baseRef}`, side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49179
|
-
"button",
|
|
49180
|
-
{
|
|
49181
|
-
onClick: onPR,
|
|
49182
|
-
disabled: merging,
|
|
49183
|
-
className: "cursor-pointer text-[#60607a] hover:text-green-400 transition-colors disabled:opacity-40",
|
|
49184
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitPullRequest, { size: 15 })
|
|
49185
|
-
}
|
|
49186
|
-
) })
|
|
49187
|
-
] }),
|
|
49188
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49189
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: "Delete task", side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49190
|
-
"button",
|
|
49191
|
-
{
|
|
49192
|
-
onClick: onDelete,
|
|
49193
|
-
className: "cursor-pointer text-[#60607a] hover:text-red-400 transition-colors",
|
|
49194
|
-
title: "Delete task",
|
|
49195
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 15 })
|
|
49196
|
-
}
|
|
49197
|
-
) })
|
|
49198
|
-
] });
|
|
49523
|
+
] })
|
|
49524
|
+
]
|
|
49525
|
+
}
|
|
49526
|
+
);
|
|
49199
49527
|
}
|
|
49200
|
-
|
|
49201
|
-
|
|
49202
|
-
|
|
49203
|
-
|
|
49204
|
-
|
|
49205
|
-
|
|
49206
|
-
|
|
49207
|
-
|
|
49208
|
-
|
|
49209
|
-
|
|
49210
|
-
|
|
49211
|
-
|
|
49212
|
-
|
|
49213
|
-
|
|
49214
|
-
|
|
49215
|
-
|
|
49216
|
-
|
|
49217
|
-
|
|
49218
|
-
|
|
49219
|
-
|
|
49220
|
-
|
|
49221
|
-
|
|
49222
|
-
{ value: "claude-haiku-4-5", label: "Haiku 4.5" }
|
|
49223
|
-
],
|
|
49224
|
-
codex: [
|
|
49225
|
-
{ value: "gpt-5.5", label: "GPT-5.5 (default)" },
|
|
49226
|
-
{ value: "gpt-5.4", label: "GPT-5.4" },
|
|
49227
|
-
{ value: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
|
|
49228
|
-
{ value: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
|
|
49229
|
-
{ value: "gpt-5.2", label: "GPT-5.2" }
|
|
49230
|
-
],
|
|
49231
|
-
// opencode supports any provider/model string — no fixed presets.
|
|
49232
|
-
// The UI renders a free-form text input for opencode model selection.
|
|
49233
|
-
opencode: [],
|
|
49234
|
-
// cursor supports many models — no fixed presets.
|
|
49235
|
-
// The UI fetches the live list via agents.cursorModels and renders a Select.
|
|
49236
|
-
cursor: []
|
|
49237
|
-
};
|
|
49238
|
-
const agentModelChoiceSchema = object({
|
|
49239
|
-
agentId: runtimeAgentIdSchema.default("claude"),
|
|
49240
|
-
model: string$2().nullable().optional(),
|
|
49241
|
-
effort: effortLevelSchema.nullable().optional()
|
|
49242
|
-
});
|
|
49243
|
-
const DEFAULT_AGENT_MODEL_CHOICE = { agentId: "claude", model: null, effort: null };
|
|
49244
|
-
const workflowSlotTypeSchema = _enum(["dev", "review", "plan", "orch"]);
|
|
49245
|
-
const tierLevelSchema = _enum(["minimal", "low", "medium", "high", "max"]);
|
|
49246
|
-
const LEVEL_ORDER = ["minimal", "low", "medium", "high", "max"];
|
|
49247
|
-
const TIER_LEVEL_OPTIONS = [
|
|
49248
|
-
{ value: "minimal", label: "Minimal" },
|
|
49249
|
-
{ value: "low", label: "Low" },
|
|
49250
|
-
{ value: "medium", label: "Medium" },
|
|
49251
|
-
{ value: "high", label: "High" },
|
|
49252
|
-
{ value: "max", label: "Max" }
|
|
49253
|
-
];
|
|
49254
|
-
const modelPairSchema = object({
|
|
49255
|
-
id: string$2(),
|
|
49256
|
-
level: tierLevelSchema,
|
|
49257
|
-
isFree: boolean$1().default(false),
|
|
49258
|
-
binary: runtimeAgentIdSchema,
|
|
49259
|
-
model: string$2().nullable().optional(),
|
|
49260
|
-
effort: effortLevelSchema.nullable().optional()
|
|
49261
|
-
});
|
|
49262
|
-
const pairSelectionModeSchema = _enum(["auto", "preferFree", "freeOnly", "paidOnly"]);
|
|
49263
|
-
const PAIR_SELECTION_MODE_OPTIONS = [
|
|
49264
|
-
{ value: "auto", label: "Auto (priority)" },
|
|
49265
|
-
{ value: "preferFree", label: "Prefer free" },
|
|
49266
|
-
{ value: "freeOnly", label: "Free only" },
|
|
49267
|
-
{ value: "paidOnly", label: "Paid only" }
|
|
49268
|
-
];
|
|
49269
|
-
const SLOT_TOOL_IDS = ["browser"];
|
|
49270
|
-
const slotToolSchema = _enum(SLOT_TOOL_IDS);
|
|
49271
|
-
const slotModelConfigSchema = object({
|
|
49272
|
-
pairs: array(modelPairSchema).min(1),
|
|
49273
|
-
mode: pairSelectionModeSchema.default("auto"),
|
|
49274
|
-
pinnedPairId: string$2().optional()
|
|
49275
|
-
});
|
|
49276
|
-
const cardModelConfigSchema = record(string$2(), slotModelConfigSchema);
|
|
49277
|
-
function pickByMode(candidates, mode) {
|
|
49278
|
-
switch (mode) {
|
|
49279
|
-
case "preferFree":
|
|
49280
|
-
return candidates.find((p) => p.isFree) ?? candidates[0];
|
|
49281
|
-
case "freeOnly":
|
|
49282
|
-
return candidates.find((p) => p.isFree);
|
|
49283
|
-
case "paidOnly":
|
|
49284
|
-
return candidates.find((p) => !p.isFree);
|
|
49285
|
-
default:
|
|
49286
|
-
return candidates[0];
|
|
49528
|
+
function genId() {
|
|
49529
|
+
return Math.random().toString(36).slice(2, 10);
|
|
49530
|
+
}
|
|
49531
|
+
function buildFlat(layout, expandAll, isDragging2 = false) {
|
|
49532
|
+
var _a3, _b2;
|
|
49533
|
+
const flat = [];
|
|
49534
|
+
for (const item of layout.topLevel) {
|
|
49535
|
+
if (item.type === "folder") {
|
|
49536
|
+
flat.push({ kind: "folder-header", folderId: item.id });
|
|
49537
|
+
const expanded = expandAll || !((_a3 = layout.folders[item.id]) == null ? void 0 : _a3.collapsed);
|
|
49538
|
+
if (expanded) {
|
|
49539
|
+
const projectIds = ((_b2 = layout.folders[item.id]) == null ? void 0 : _b2.projectIds) ?? [];
|
|
49540
|
+
for (const wsId of projectIds) {
|
|
49541
|
+
flat.push({ kind: "project", workspaceId: wsId, folderId: item.id });
|
|
49542
|
+
}
|
|
49543
|
+
if (isDragging2 && projectIds.length === 0) {
|
|
49544
|
+
flat.push({ kind: "empty-folder-slot", folderId: item.id });
|
|
49545
|
+
}
|
|
49546
|
+
}
|
|
49547
|
+
} else {
|
|
49548
|
+
flat.push({ kind: "project", workspaceId: item.workspaceId, folderId: null });
|
|
49549
|
+
}
|
|
49287
49550
|
}
|
|
49551
|
+
return flat;
|
|
49288
49552
|
}
|
|
49289
|
-
function
|
|
49290
|
-
|
|
49291
|
-
|
|
49292
|
-
|
|
49293
|
-
|
|
49294
|
-
|
|
49295
|
-
const
|
|
49296
|
-
for (
|
|
49297
|
-
|
|
49298
|
-
|
|
49299
|
-
|
|
49300
|
-
|
|
49301
|
-
|
|
49302
|
-
|
|
49553
|
+
function flatToLayout(flat, existing) {
|
|
49554
|
+
var _a3;
|
|
49555
|
+
const topLevel = [];
|
|
49556
|
+
const folders = Object.fromEntries(
|
|
49557
|
+
Object.entries(existing.folders).map(([k, v2]) => [k, { ...v2, projectIds: [] }])
|
|
49558
|
+
);
|
|
49559
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
49560
|
+
for (const item of flat) {
|
|
49561
|
+
if (item.kind === "empty-folder-slot") continue;
|
|
49562
|
+
if (item.kind === "folder-header") {
|
|
49563
|
+
if (!seen2.has(item.folderId)) {
|
|
49564
|
+
seen2.add(item.folderId);
|
|
49565
|
+
topLevel.push({ type: "folder", id: item.folderId });
|
|
49566
|
+
}
|
|
49567
|
+
} else if (item.folderId !== null) {
|
|
49568
|
+
(_a3 = folders[item.folderId]) == null ? void 0 : _a3.projectIds.push(item.workspaceId);
|
|
49569
|
+
} else {
|
|
49570
|
+
topLevel.push({ type: "project", workspaceId: item.workspaceId });
|
|
49571
|
+
}
|
|
49303
49572
|
}
|
|
49304
|
-
|
|
49305
|
-
|
|
49306
|
-
|
|
49573
|
+
return { ...existing, topLevel, folders };
|
|
49574
|
+
}
|
|
49575
|
+
function folderAtDest(flat, destIndex) {
|
|
49576
|
+
const after = flat[destIndex];
|
|
49577
|
+
if (!after) {
|
|
49578
|
+
const prev = flat[destIndex - 1];
|
|
49579
|
+
if (!prev || prev.kind === "folder-header") return null;
|
|
49580
|
+
if (prev.kind === "empty-folder-slot") return prev.folderId;
|
|
49581
|
+
return prev.folderId;
|
|
49307
49582
|
}
|
|
49308
|
-
|
|
49309
|
-
if (
|
|
49310
|
-
return
|
|
49583
|
+
if (after.kind === "folder-header") return after.folderId;
|
|
49584
|
+
if (after.kind === "empty-folder-slot") return after.folderId;
|
|
49585
|
+
return after.folderId;
|
|
49311
49586
|
}
|
|
49312
|
-
|
|
49313
|
-
(
|
|
49314
|
-
|
|
49315
|
-
|
|
49316
|
-
|
|
49317
|
-
|
|
49318
|
-
|
|
49319
|
-
|
|
49320
|
-
|
|
49321
|
-
);
|
|
49322
|
-
const
|
|
49323
|
-
|
|
49324
|
-
id: string$2(),
|
|
49325
|
-
type: workflowSlotTypeSchema,
|
|
49326
|
-
name: string$2(),
|
|
49327
|
-
order: number$2().int().nonnegative(),
|
|
49328
|
-
enabled: boolean$1(),
|
|
49329
|
-
prompt: promptValueSchema.default(EMPTY_INLINE_PROMPT),
|
|
49330
|
-
// Model tiers for this slot, in priority order (top = highest). Copied to the
|
|
49331
|
-
// card at creation; the card's active level + mode select which pair runs.
|
|
49332
|
-
pairs: array(modelPairSchema).min(1),
|
|
49333
|
-
mode: pairSelectionModeSchema.default("auto"),
|
|
49334
|
-
// Tools this slot may use (e.g. "browser"). Workflow-only, not ticket-editable.
|
|
49335
|
-
tools: array(slotToolSchema).default([]),
|
|
49336
|
-
// review slots only: may set the card's active level on reopen.
|
|
49337
|
-
canAdjustLevel: boolean$1().default(false),
|
|
49338
|
-
// plan slots only: re-run even if a plan already exists on the card.
|
|
49339
|
-
rerun: boolean$1().default(false)
|
|
49340
|
-
});
|
|
49341
|
-
const workflowSchema = object({
|
|
49342
|
-
id: string$2(),
|
|
49343
|
-
name: string$2(),
|
|
49344
|
-
isDefault: boolean$1().default(false),
|
|
49345
|
-
forStory: boolean$1().default(false),
|
|
49346
|
-
slots: array(workflowSlotSchema)
|
|
49347
|
-
});
|
|
49348
|
-
function highestWorkflowLevel(workflow) {
|
|
49349
|
-
let bestIdx = -1;
|
|
49350
|
-
for (const slot of (workflow == null ? void 0 : workflow.slots) ?? []) {
|
|
49351
|
-
for (const p of slot.pairs) bestIdx = Math.max(bestIdx, LEVEL_ORDER.indexOf(p.level));
|
|
49587
|
+
function syncLayout(layout, projects) {
|
|
49588
|
+
const known = new Set(projects.map((p) => p.workspaceId));
|
|
49589
|
+
const topLevel = layout.topLevel.filter((i2) => i2.type === "folder" || known.has(i2.workspaceId));
|
|
49590
|
+
const folders = Object.fromEntries(
|
|
49591
|
+
Object.entries(layout.folders).map(([id, f]) => [
|
|
49592
|
+
id,
|
|
49593
|
+
{ ...f, projectIds: f.projectIds.filter((id2) => known.has(id2)) }
|
|
49594
|
+
])
|
|
49595
|
+
);
|
|
49596
|
+
const inLayout = /* @__PURE__ */ new Set();
|
|
49597
|
+
for (const i2 of topLevel) {
|
|
49598
|
+
if (i2.type === "project") inLayout.add(i2.workspaceId);
|
|
49352
49599
|
}
|
|
49353
|
-
|
|
49600
|
+
for (const f of Object.values(folders)) {
|
|
49601
|
+
for (const id of f.projectIds) inLayout.add(id);
|
|
49602
|
+
}
|
|
49603
|
+
const newItems = projects.filter((p) => !inLayout.has(p.workspaceId)).map((p) => ({ type: "project", workspaceId: p.workspaceId }));
|
|
49604
|
+
return { ...layout, topLevel: [...topLevel, ...newItems], folders };
|
|
49354
49605
|
}
|
|
49355
|
-
|
|
49356
|
-
|
|
49357
|
-
|
|
49358
|
-
|
|
49359
|
-
|
|
49360
|
-
|
|
49361
|
-
|
|
49362
|
-
|
|
49363
|
-
|
|
49364
|
-
|
|
49365
|
-
|
|
49366
|
-
|
|
49367
|
-
|
|
49368
|
-
|
|
49369
|
-
|
|
49370
|
-
|
|
49371
|
-
|
|
49372
|
-
|
|
49373
|
-
|
|
49374
|
-
|
|
49375
|
-
|
|
49376
|
-
|
|
49377
|
-
|
|
49378
|
-
|
|
49379
|
-
|
|
49380
|
-
|
|
49381
|
-
|
|
49382
|
-
|
|
49383
|
-
|
|
49384
|
-
|
|
49385
|
-
|
|
49386
|
-
-
|
|
49387
|
-
|
|
49388
|
-
|
|
49389
|
-
|
|
49390
|
-
|
|
49391
|
-
|
|
49392
|
-
|
|
49393
|
-
|
|
49394
|
-
|
|
49395
|
-
|
|
49396
|
-
|
|
49397
|
-
|
|
49398
|
-
|
|
49399
|
-
|
|
49400
|
-
|
|
49401
|
-
|
|
49402
|
-
|
|
49403
|
-
|
|
49404
|
-
|
|
49405
|
-
|
|
49406
|
-
|
|
49407
|
-
|
|
49408
|
-
|
|
49409
|
-
|
|
49410
|
-
})
|
|
49411
|
-
|
|
49412
|
-
|
|
49413
|
-
|
|
49414
|
-
|
|
49415
|
-
|
|
49416
|
-
|
|
49417
|
-
|
|
49418
|
-
|
|
49419
|
-
|
|
49420
|
-
|
|
49421
|
-
|
|
49422
|
-
|
|
49423
|
-
|
|
49424
|
-
});
|
|
49425
|
-
const runtimeReviewCommentSchema = object({
|
|
49426
|
-
id: string$2(),
|
|
49427
|
-
type: string$2(),
|
|
49428
|
-
actor: reviewActorSchema,
|
|
49429
|
-
status: _enum(["pass", "fail", "warning", "skipped"]).optional(),
|
|
49430
|
-
createdAt: number$2(),
|
|
49431
|
-
streamId: string$2().optional(),
|
|
49432
|
-
summary: string$2(),
|
|
49433
|
-
issues: array(reviewIssueSchema).optional(),
|
|
49434
|
-
attachments: array(reviewAttachmentSchema).optional(),
|
|
49435
|
-
metadata: record(string$2(), unknown$1()).optional()
|
|
49436
|
-
});
|
|
49437
|
-
const runtimeActivityEntrySchema = object({
|
|
49438
|
-
timestamp: number$2(),
|
|
49439
|
-
message: string$2()
|
|
49440
|
-
});
|
|
49441
|
-
const runtimeTaskSessionStateSchema = _enum(["running", "stopped", "completed", "failed", "killed"]);
|
|
49442
|
-
const runtimeTerminalSessionEntrySchema = object({
|
|
49443
|
-
streamId: string$2(),
|
|
49444
|
-
type: string$2(),
|
|
49445
|
-
startedAt: number$2(),
|
|
49446
|
-
endedAt: number$2().optional(),
|
|
49447
|
-
agentId: runtimeAgentIdSchema.optional(),
|
|
49448
|
-
state: runtimeTaskSessionStateSchema.optional()
|
|
49449
|
-
});
|
|
49450
|
-
const runtimeCardPrioritySchema = _enum(["urgent", "high", "medium", "low"]);
|
|
49451
|
-
const cardTypeSchema = _enum(["task", "story", "subtask"]);
|
|
49452
|
-
const runtimePrMetaSchema = object({
|
|
49453
|
-
url: string$2().optional(),
|
|
49454
|
-
title: string$2().optional(),
|
|
49455
|
-
description: string$2().optional(),
|
|
49456
|
-
updatedAt: number$2().optional(),
|
|
49457
|
-
updatedBy: string$2().optional()
|
|
49458
|
-
});
|
|
49459
|
-
const runtimeBoardCardSchema = object({
|
|
49460
|
-
id: string$2(),
|
|
49461
|
-
description: string$2(),
|
|
49462
|
-
descriptionAttachments: array(reviewAttachmentSchema).optional().default([]),
|
|
49463
|
-
columnId: runtimeBoardColumnIdSchema,
|
|
49464
|
-
type: cardTypeSchema.default("task"),
|
|
49465
|
-
readyForDev: boolean$1().default(false),
|
|
49466
|
-
agentId: runtimeAgentIdSchema.optional(),
|
|
49467
|
-
priority: runtimeCardPrioritySchema.optional(),
|
|
49468
|
-
// Single-parent stacking: this card continues in the parent's worktree/branch
|
|
49469
|
-
// and starts once the parent reaches ready_for_review. Mutually exclusive with waitsFor.
|
|
49470
|
-
dependsOn: string$2().optional(),
|
|
49471
|
-
// Many-parent gate (tasks only): this card starts only once ALL listed cards are
|
|
49472
|
-
// done (merged), in a fresh worktree branched from baseRef. Mutually exclusive with dependsOn.
|
|
49473
|
-
waitsFor: array(string$2()).default([]),
|
|
49474
|
-
// Story-only: the IDs of this story's subtasks. The story triggers its orchestrator
|
|
49475
|
-
// workflow once every subtask reaches ready_for_review.
|
|
49476
|
-
subtaskIds: array(string$2()).default([]),
|
|
49477
|
-
autoFixAttempts: number$2().int().nonnegative().default(0),
|
|
49478
|
-
baseRef: string$2(),
|
|
49479
|
-
createdAt: number$2(),
|
|
49480
|
-
updatedAt: number$2(),
|
|
49481
|
-
githubIssueUrl: string$2().optional(),
|
|
49482
|
-
pr: runtimePrMetaSchema.optional(),
|
|
49483
|
-
workflowId: string$2().optional(),
|
|
49484
|
-
// Plan written by the one-shot plan agent; injected into the dev agent's prompt.
|
|
49485
|
-
plan: string$2().optional(),
|
|
49486
|
-
// Workflow-wide capability level; every slot resolves it to its own pair.
|
|
49487
|
-
activeLevel: tierLevelSchema.default("medium"),
|
|
49488
|
-
// Per-slot model config, snapshotted from the workflow at creation and editable
|
|
49489
|
-
// per ticket (slotId → {pairs, mode, pinnedPairId}).
|
|
49490
|
-
modelConfig: cardModelConfigSchema.optional(),
|
|
49491
|
-
reviewComments: array(runtimeReviewCommentSchema).default([]),
|
|
49492
|
-
activityLog: array(runtimeActivityEntrySchema).default([]),
|
|
49493
|
-
terminalSessions: array(runtimeTerminalSessionEntrySchema).default([]),
|
|
49494
|
-
githubCommentIds: array(string$2()).default([]),
|
|
49495
|
-
worktreePath: string$2().optional(),
|
|
49496
|
-
branchName: string$2().optional(),
|
|
49497
|
-
slackMessageTs: string$2().optional(),
|
|
49498
|
-
slackChannelId: string$2().optional()
|
|
49499
|
-
});
|
|
49500
|
-
const runtimeBoardColumnSchema = object({
|
|
49501
|
-
id: runtimeBoardColumnIdSchema,
|
|
49502
|
-
title: string$2(),
|
|
49503
|
-
taskIds: array(string$2())
|
|
49504
|
-
});
|
|
49505
|
-
const runtimeBoardDataSchema = object({
|
|
49506
|
-
columns: array(runtimeBoardColumnSchema),
|
|
49507
|
-
cards: record(string$2(), runtimeBoardCardSchema)
|
|
49508
|
-
});
|
|
49509
|
-
const runtimeGlobalConfigSchema = object({
|
|
49510
|
-
defaultAgent: runtimeAgentIdSchema.default("claude"),
|
|
49511
|
-
maxParallelTasks: number$2().int().positive().default(4),
|
|
49512
|
-
maxParallelQA: number$2().int().positive().default(1),
|
|
49513
|
-
maxAutoFixAttempts: number$2().int().nonnegative().default(3),
|
|
49514
|
-
pollingIntervalSeconds: number$2().int().positive().default(30),
|
|
49515
|
-
prPollingIntervalSeconds: number$2().int().positive().default(60),
|
|
49516
|
-
terminalApp: string$2().optional(),
|
|
49517
|
-
slackEnabled: boolean$1().default(true),
|
|
49518
|
-
slackBotToken: string$2().optional(),
|
|
49519
|
-
slackSigningSecret: string$2().optional(),
|
|
49520
|
-
slackAppConfigToken: string$2().optional(),
|
|
49521
|
-
slackClientId: string$2().optional(),
|
|
49522
|
-
slackClientSecret: string$2().optional(),
|
|
49523
|
-
slackAppId: string$2().optional(),
|
|
49524
|
-
slackOauthAuthorizeUrl: string$2().optional(),
|
|
49525
|
-
slackPublicUrl: string$2().optional(),
|
|
49526
|
-
slackBotName: string$2().default("Whipped"),
|
|
49527
|
-
slackInstallerUserId: string$2().optional(),
|
|
49528
|
-
autoStartTunnel: boolean$1().default(false),
|
|
49529
|
-
tunnelId: string$2().optional(),
|
|
49530
|
-
tunnelDomain: string$2().optional(),
|
|
49531
|
-
tunnelName: string$2().default("whipped"),
|
|
49532
|
-
// Auth: single shared password (scrypt hash) + HMAC secret for signed session
|
|
49533
|
-
// cookies + machine token for local agent machinery (MCP/hooks). Never expose
|
|
49534
|
-
// these over the API — see configController's response.
|
|
49535
|
-
authPasswordHash: string$2().optional(),
|
|
49536
|
-
authSessionSecret: string$2().optional(),
|
|
49537
|
-
authMachineToken: string$2().optional()
|
|
49538
|
-
});
|
|
49539
|
-
const runtimeGithubConfigSchema = object({
|
|
49540
|
-
token: string$2()
|
|
49541
|
-
});
|
|
49542
|
-
const runtimeWorktreeSetupSchema = object({
|
|
49543
|
-
filesToCopy: array(string$2()).default([]),
|
|
49544
|
-
installCommand: string$2().default("")
|
|
49545
|
-
});
|
|
49546
|
-
const runtimeProjectSecretSchema = object({
|
|
49547
|
-
key: string$2().min(1),
|
|
49548
|
-
value: string$2()
|
|
49549
|
-
});
|
|
49550
|
-
const BUILTIN_SECRET_KEYS = ["GITHUB_TOKEN"];
|
|
49551
|
-
const runtimeProjectConfigSchema = object({
|
|
49552
|
-
name: string$2().optional(),
|
|
49553
|
-
defaultAgent: runtimeAgentIdSchema.optional(),
|
|
49554
|
-
maxParallelTasks: number$2().int().positive().optional(),
|
|
49555
|
-
maxAutoFixAttempts: number$2().int().nonnegative().optional(),
|
|
49556
|
-
pollingIntervalSeconds: number$2().int().positive().optional(),
|
|
49557
|
-
// What happens when a card passes review (polling/dispatch is always on; per-ticket
|
|
49558
|
-
// readyForDev gates pickup). "off" parks it in ready_for_review, "pr" auto-creates a
|
|
49559
|
-
// GitHub PR, "yolo" merges the branch straight into the local baseRef and pushes.
|
|
49560
|
-
deliveryMode: _enum(["off", "pr", "yolo"]).default("off"),
|
|
49561
|
-
autoCommit: boolean$1().default(true),
|
|
49562
|
-
defaultBaseBranch: string$2().optional(),
|
|
49563
|
-
github: runtimeGithubConfigSchema.optional(),
|
|
49564
|
-
worktreeSetup: runtimeWorktreeSetupSchema.optional(),
|
|
49565
|
-
startCommand: string$2().default(""),
|
|
49566
|
-
workflows: array(workflowSchema).default([]),
|
|
49567
|
-
secrets: array(runtimeProjectSecretSchema).default([]),
|
|
49568
|
-
systemPrompt: string$2().optional(),
|
|
49569
|
-
// Freeform instructions injected into the dev agent's prompt to shape PR
|
|
49570
|
-
// titles, descriptions, and commit messages. Empty/absent → daemon falls
|
|
49571
|
-
// back to DEFAULT_GIT_INSTRUCTIONS.
|
|
49572
|
-
gitInstructions: string$2().optional(),
|
|
49573
|
-
// Which agent binary/model/effort the assistant agent runs as. Absent → claude.
|
|
49574
|
-
assistantModel: agentModelChoiceSchema.optional()
|
|
49575
|
-
});
|
|
49576
|
-
object({
|
|
49577
|
-
workspaceId: string$2(),
|
|
49578
|
-
repoPath: string$2(),
|
|
49579
|
-
board: runtimeBoardDataSchema,
|
|
49580
|
-
revision: number$2(),
|
|
49581
|
-
projectConfig: runtimeProjectConfigSchema
|
|
49582
|
-
});
|
|
49583
|
-
object({
|
|
49584
|
-
board: runtimeBoardDataSchema,
|
|
49585
|
-
revision: number$2()
|
|
49586
|
-
});
|
|
49587
|
-
const runtimeVisualElementSchema = object({
|
|
49588
|
-
elementSelector: string$2().optional(),
|
|
49589
|
-
elementText: string$2().optional(),
|
|
49590
|
-
componentName: string$2().optional(),
|
|
49591
|
-
componentChain: array(string$2()).optional(),
|
|
49592
|
-
sourceFile: string$2().optional(),
|
|
49593
|
-
sourceLine: number$2().optional(),
|
|
49594
|
-
// The page the element was captured on. Selections can span pages, so this is
|
|
49595
|
-
// per-element rather than relying on the visualComment-level pageUrl.
|
|
49596
|
-
pageUrl: string$2().optional()
|
|
49597
|
-
});
|
|
49598
|
-
const runtimeVisualCommentSchema = object({
|
|
49599
|
-
pageUrl: string$2().optional(),
|
|
49600
|
-
elements: array(runtimeVisualElementSchema).default([])
|
|
49601
|
-
});
|
|
49602
|
-
const runtimeCardCreateRequestSchema = object({
|
|
49603
|
-
description: string$2(),
|
|
49604
|
-
type: cardTypeSchema.optional(),
|
|
49605
|
-
// Browser-extension element references; folded into the description server-side.
|
|
49606
|
-
visualComment: runtimeVisualCommentSchema.optional(),
|
|
49607
|
-
agentId: runtimeAgentIdSchema.optional(),
|
|
49608
|
-
priority: runtimeCardPrioritySchema.optional(),
|
|
49609
|
-
readyForDev: boolean$1().optional(),
|
|
49610
|
-
dependsOn: string$2().optional(),
|
|
49611
|
-
waitsFor: array(string$2()).optional(),
|
|
49612
|
-
subtaskIds: array(string$2()).optional(),
|
|
49613
|
-
columnId: runtimeBoardColumnIdSchema.optional(),
|
|
49614
|
-
baseRef: string$2().optional(),
|
|
49615
|
-
githubIssueUrl: string$2().optional(),
|
|
49616
|
-
workflowId: string$2().optional(),
|
|
49617
|
-
descriptionAttachments: array(reviewAttachmentSchema).optional(),
|
|
49618
|
-
branchName: string$2().optional(),
|
|
49619
|
-
// Optional per-ticket overrides edited before creation. When omitted, the card
|
|
49620
|
-
// snapshots the resolved workflow's pairs and defaults the active level to the
|
|
49621
|
-
// workflow's highest configured tier.
|
|
49622
|
-
modelConfig: cardModelConfigSchema.optional(),
|
|
49623
|
-
activeLevel: tierLevelSchema.optional()
|
|
49624
|
-
});
|
|
49625
|
-
object({
|
|
49626
|
-
cardId: string$2(),
|
|
49627
|
-
targetColumnId: runtimeBoardColumnIdSchema,
|
|
49628
|
-
targetIndex: number$2().int().nonnegative().optional(),
|
|
49629
|
-
revision: number$2()
|
|
49630
|
-
});
|
|
49631
|
-
object({
|
|
49632
|
-
cardId: string$2(),
|
|
49633
|
-
description: string$2().optional(),
|
|
49634
|
-
descriptionAttachments: array(reviewAttachmentSchema).optional(),
|
|
49635
|
-
type: cardTypeSchema.optional(),
|
|
49636
|
-
agentId: runtimeAgentIdSchema.optional(),
|
|
49637
|
-
priority: runtimeCardPrioritySchema.optional(),
|
|
49638
|
-
readyForDev: boolean$1().optional(),
|
|
49639
|
-
dependsOn: string$2().optional(),
|
|
49640
|
-
waitsFor: array(string$2()).optional(),
|
|
49641
|
-
subtaskIds: array(string$2()).optional(),
|
|
49642
|
-
workflowId: string$2().optional(),
|
|
49643
|
-
branchName: string$2().optional(),
|
|
49644
|
-
plan: string$2().optional(),
|
|
49645
|
-
activeLevel: tierLevelSchema.optional(),
|
|
49646
|
-
modelConfig: cardModelConfigSchema.optional(),
|
|
49647
|
-
revision: number$2()
|
|
49648
|
-
});
|
|
49649
|
-
const memoryScopeSchema = _enum(["global", "project"]);
|
|
49650
|
-
const memoryTypeSchema = _enum([
|
|
49651
|
-
"fact",
|
|
49652
|
-
"convention",
|
|
49653
|
-
"decision",
|
|
49654
|
-
"preference",
|
|
49655
|
-
"rule",
|
|
49656
|
-
"lesson",
|
|
49657
|
-
"sharp_edge"
|
|
49658
|
-
]);
|
|
49659
|
-
const MEMORY_TYPE_OPTIONS = [
|
|
49660
|
-
{ value: "fact", label: "Fact" },
|
|
49661
|
-
{ value: "convention", label: "Convention" },
|
|
49662
|
-
{ value: "decision", label: "Decision" },
|
|
49663
|
-
{ value: "preference", label: "Preference" },
|
|
49664
|
-
{ value: "rule", label: "Rule" },
|
|
49665
|
-
{ value: "lesson", label: "Lesson" },
|
|
49666
|
-
{ value: "sharp_edge", label: "Sharp edge" }
|
|
49667
|
-
];
|
|
49668
|
-
const memorySourceTypeSchema = _enum(["user_correction", "explicit_save", "task_lesson", "manual_human"]);
|
|
49669
|
-
const memoryStatusSchema = _enum(["pending", "approved"]);
|
|
49670
|
-
const runtimeMemoryOriginAgentSchema = object({
|
|
49671
|
-
agent: string$2(),
|
|
49672
|
-
model: string$2().optional()
|
|
49673
|
-
});
|
|
49674
|
-
object({
|
|
49675
|
-
id: string$2(),
|
|
49676
|
-
scope: memoryScopeSchema,
|
|
49677
|
-
workspaceId: string$2().nullable(),
|
|
49678
|
-
originWorkspaceId: string$2().nullable().optional(),
|
|
49679
|
-
type: memoryTypeSchema,
|
|
49680
|
-
title: string$2(),
|
|
49681
|
-
content: string$2(),
|
|
49682
|
-
sourceType: memorySourceTypeSchema,
|
|
49683
|
-
importance: number$2().int().min(1).max(3).default(1),
|
|
49684
|
-
tags: array(string$2()).default([]),
|
|
49685
|
-
boundWorkspaceIds: array(string$2()).default([]),
|
|
49686
|
-
originCardId: string$2().nullable().optional(),
|
|
49687
|
-
originAgent: runtimeMemoryOriginAgentSchema.nullable().optional(),
|
|
49688
|
-
status: memoryStatusSchema.default("approved"),
|
|
49689
|
-
createdAt: number$2(),
|
|
49690
|
-
updatedAt: number$2()
|
|
49691
|
-
});
|
|
49692
|
-
function normalizeTag(raw2) {
|
|
49693
|
-
return raw2.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
49606
|
+
function ProjectItem({
|
|
49607
|
+
project,
|
|
49608
|
+
workspaceId,
|
|
49609
|
+
dp,
|
|
49610
|
+
snap,
|
|
49611
|
+
isActive: isActive2,
|
|
49612
|
+
indent: indent2,
|
|
49613
|
+
onSwitch,
|
|
49614
|
+
onRemove
|
|
49615
|
+
}) {
|
|
49616
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
49617
|
+
"div",
|
|
49618
|
+
{
|
|
49619
|
+
ref: dp.innerRef,
|
|
49620
|
+
...dp.draggableProps,
|
|
49621
|
+
...dp.dragHandleProps,
|
|
49622
|
+
onClick: () => onSwitch(workspaceId),
|
|
49623
|
+
className: classNames(
|
|
49624
|
+
"group flex items-center gap-2 h-8 pr-2 my-px mx-1 rounded-md cursor-pointer select-none transition-colors",
|
|
49625
|
+
indent2 ? "pl-10" : "pl-3",
|
|
49626
|
+
snap.isDragging ? "opacity-70" : isActive2 ? "" : "hover:bg-[#1a1a1f]"
|
|
49627
|
+
),
|
|
49628
|
+
style: {
|
|
49629
|
+
...dp.draggableProps.style,
|
|
49630
|
+
background: isActive2 && !snap.isDragging ? "#7c6aff18" : "transparent",
|
|
49631
|
+
borderLeft: isActive2 && !snap.isDragging ? "2px solid #7c6aff" : "2px solid transparent"
|
|
49632
|
+
},
|
|
49633
|
+
children: [
|
|
49634
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49635
|
+
"div",
|
|
49636
|
+
{
|
|
49637
|
+
className: classNames("w-1.5 h-1.5 rounded-full shrink-0", isActive2 ? "bg-[#7c6aff]" : "bg-[#2a2a35]"),
|
|
49638
|
+
style: isActive2 ? { boxShadow: "0 0 6px #7c6aff80" } : void 0
|
|
49639
|
+
}
|
|
49640
|
+
),
|
|
49641
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49642
|
+
"span",
|
|
49643
|
+
{
|
|
49644
|
+
className: classNames(
|
|
49645
|
+
"flex-1 min-w-0 truncate text-[12px]",
|
|
49646
|
+
isActive2 ? "text-[#f0f0f5] font-medium" : "text-[#8888a0] font-normal"
|
|
49647
|
+
),
|
|
49648
|
+
children: project.name
|
|
49649
|
+
}
|
|
49650
|
+
),
|
|
49651
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49652
|
+
"button",
|
|
49653
|
+
{
|
|
49654
|
+
onClick: (e) => {
|
|
49655
|
+
e.stopPropagation();
|
|
49656
|
+
ConfirmDialog_default.show({
|
|
49657
|
+
title: "Remove project",
|
|
49658
|
+
content: `Remove "${project.name}" from Whipped? This will stop all running agents and delete all associated worktrees and data.`,
|
|
49659
|
+
confirmButtonLabel: "Remove",
|
|
49660
|
+
cancelButtonLabel: "Cancel",
|
|
49661
|
+
onConfirm: async ({ dismiss: dismiss2 }) => {
|
|
49662
|
+
await onRemove(workspaceId);
|
|
49663
|
+
dismiss2();
|
|
49664
|
+
}
|
|
49665
|
+
});
|
|
49666
|
+
},
|
|
49667
|
+
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#ef444420] transition-colors text-[#60607a] hover:text-[#ef4444]",
|
|
49668
|
+
title: "Remove project",
|
|
49669
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
|
|
49670
|
+
}
|
|
49671
|
+
) })
|
|
49672
|
+
]
|
|
49673
|
+
}
|
|
49674
|
+
);
|
|
49694
49675
|
}
|
|
49695
|
-
|
|
49696
|
-
const
|
|
49697
|
-
|
|
49698
|
-
|
|
49699
|
-
]);
|
|
49700
|
-
const
|
|
49701
|
-
const
|
|
49702
|
-
const
|
|
49703
|
-
|
|
49704
|
-
|
|
49705
|
-
|
|
49706
|
-
|
|
49707
|
-
|
|
49708
|
-
|
|
49709
|
-
|
|
49710
|
-
|
|
49711
|
-
});
|
|
49712
|
-
|
|
49713
|
-
|
|
49714
|
-
|
|
49715
|
-
|
|
49716
|
-
|
|
49717
|
-
|
|
49718
|
-
|
|
49719
|
-
|
|
49720
|
-
|
|
49721
|
-
|
|
49722
|
-
|
|
49723
|
-
|
|
49724
|
-
|
|
49725
|
-
|
|
49726
|
-
|
|
49727
|
-
|
|
49728
|
-
|
|
49729
|
-
|
|
49730
|
-
|
|
49731
|
-
|
|
49732
|
-
|
|
49733
|
-
|
|
49734
|
-
|
|
49735
|
-
|
|
49736
|
-
|
|
49737
|
-
|
|
49738
|
-
|
|
49739
|
-
|
|
49740
|
-
|
|
49741
|
-
|
|
49742
|
-
|
|
49743
|
-
|
|
49744
|
-
|
|
49745
|
-
|
|
49746
|
-
|
|
49747
|
-
|
|
49748
|
-
|
|
49749
|
-
|
|
49750
|
-
|
|
49751
|
-
|
|
49752
|
-
|
|
49753
|
-
|
|
49754
|
-
|
|
49755
|
-
|
|
49756
|
-
}
|
|
49757
|
-
|
|
49758
|
-
|
|
49759
|
-
|
|
49760
|
-
|
|
49761
|
-
|
|
49676
|
+
const ProjectsSidebar = React.forwardRef(function ProjectsSidebar2({ projects, activeWorkspaceId, onSwitch, onRemove }, ref) {
|
|
49677
|
+
const [layout, setLayout] = reactExports.useState({ version: 1, topLevel: [], folders: {} });
|
|
49678
|
+
const [isDragging2, setIsDragging] = reactExports.useState(false);
|
|
49679
|
+
const [hoveredFolderId, setHoveredFolderId] = reactExports.useState(null);
|
|
49680
|
+
const [editingId, setEditingId] = reactExports.useState(null);
|
|
49681
|
+
const [editName, setEditName] = reactExports.useState("");
|
|
49682
|
+
const editRef = reactExports.useRef(null);
|
|
49683
|
+
const saveTimer = reactExports.useRef(null);
|
|
49684
|
+
const { trigger: fetchLayout } = useRead((api) => api("projects/layout").GET(), { enabled: false });
|
|
49685
|
+
const { trigger: saveLayout } = useWrite((api) => api("projects/layout").PUT());
|
|
49686
|
+
reactExports.useEffect(() => {
|
|
49687
|
+
fetchLayout().then((res) => setLayout((prev) => syncLayout(res.data ?? prev, projects))).catch(() => {
|
|
49688
|
+
});
|
|
49689
|
+
}, []);
|
|
49690
|
+
reactExports.useEffect(() => {
|
|
49691
|
+
setLayout((prev) => syncLayout(prev, projects));
|
|
49692
|
+
}, [projects]);
|
|
49693
|
+
const persist = (next2) => {
|
|
49694
|
+
if (saveTimer.current) clearTimeout(saveTimer.current);
|
|
49695
|
+
saveTimer.current = setTimeout(() => {
|
|
49696
|
+
saveLayout({ body: next2 }).catch(() => {
|
|
49697
|
+
});
|
|
49698
|
+
}, 300);
|
|
49699
|
+
};
|
|
49700
|
+
const update2 = (next2) => {
|
|
49701
|
+
setLayout(next2);
|
|
49702
|
+
persist(next2);
|
|
49703
|
+
};
|
|
49704
|
+
const addFolder = () => {
|
|
49705
|
+
const id = genId();
|
|
49706
|
+
const next2 = {
|
|
49707
|
+
...layout,
|
|
49708
|
+
topLevel: [...layout.topLevel, { type: "folder", id }],
|
|
49709
|
+
folders: { ...layout.folders, [id]: { id, name: "New Folder", collapsed: false, projectIds: [] } }
|
|
49710
|
+
};
|
|
49711
|
+
update2(next2);
|
|
49712
|
+
setEditingId(id);
|
|
49713
|
+
setEditName("New Folder");
|
|
49714
|
+
setTimeout(() => {
|
|
49715
|
+
var _a3, _b2;
|
|
49716
|
+
(_a3 = editRef.current) == null ? void 0 : _a3.focus();
|
|
49717
|
+
(_b2 = editRef.current) == null ? void 0 : _b2.select();
|
|
49718
|
+
}, 50);
|
|
49719
|
+
};
|
|
49720
|
+
reactExports.useImperativeHandle(ref, () => ({ addFolder }));
|
|
49721
|
+
const startRename = (id) => {
|
|
49722
|
+
var _a3;
|
|
49723
|
+
setEditingId(id);
|
|
49724
|
+
setEditName(((_a3 = layout.folders[id]) == null ? void 0 : _a3.name) ?? "");
|
|
49725
|
+
setTimeout(() => {
|
|
49726
|
+
var _a4, _b2;
|
|
49727
|
+
(_a4 = editRef.current) == null ? void 0 : _a4.focus();
|
|
49728
|
+
(_b2 = editRef.current) == null ? void 0 : _b2.select();
|
|
49729
|
+
}, 50);
|
|
49730
|
+
};
|
|
49731
|
+
const commitRename = () => {
|
|
49732
|
+
if (!editingId) return;
|
|
49733
|
+
update2({
|
|
49734
|
+
...layout,
|
|
49735
|
+
folders: {
|
|
49736
|
+
...layout.folders,
|
|
49737
|
+
[editingId]: { ...layout.folders[editingId], name: editName.trim() || "Untitled" }
|
|
49738
|
+
}
|
|
49739
|
+
});
|
|
49740
|
+
setEditingId(null);
|
|
49741
|
+
};
|
|
49742
|
+
const deleteFolder = (id) => {
|
|
49743
|
+
const folder = layout.folders[id];
|
|
49744
|
+
if (!folder) return;
|
|
49745
|
+
const idx = layout.topLevel.findIndex((i2) => i2.type === "folder" && i2.id === id);
|
|
49746
|
+
const returned = folder.projectIds.map((ws2) => ({ type: "project", workspaceId: ws2 }));
|
|
49747
|
+
const topLevel = [...layout.topLevel];
|
|
49748
|
+
topLevel.splice(idx, 1, ...returned);
|
|
49749
|
+
const folders = { ...layout.folders };
|
|
49750
|
+
delete folders[id];
|
|
49751
|
+
update2({ ...layout, topLevel, folders });
|
|
49752
|
+
};
|
|
49753
|
+
const toggleCollapse = (id) => {
|
|
49754
|
+
const f = layout.folders[id];
|
|
49755
|
+
if (!f) return;
|
|
49756
|
+
update2({ ...layout, folders: { ...layout.folders, [id]: { ...f, collapsed: !f.collapsed } } });
|
|
49757
|
+
};
|
|
49758
|
+
const onDragUpdate2 = reactExports.useCallback(
|
|
49759
|
+
(update22) => {
|
|
49760
|
+
if (!update22.destination) {
|
|
49761
|
+
setHoveredFolderId(null);
|
|
49762
|
+
return;
|
|
49763
|
+
}
|
|
49764
|
+
const flat2 = buildFlat(layout, true, true);
|
|
49765
|
+
flat2.splice(update22.source.index, 1);
|
|
49766
|
+
const folderId = folderAtDest(flat2, update22.destination.index);
|
|
49767
|
+
setHoveredFolderId(folderId);
|
|
49768
|
+
},
|
|
49769
|
+
[layout]
|
|
49770
|
+
);
|
|
49771
|
+
const onDragEnd2 = (result) => {
|
|
49772
|
+
setIsDragging(false);
|
|
49773
|
+
setHoveredFolderId(null);
|
|
49774
|
+
if (!result.destination) return;
|
|
49775
|
+
const { draggableId, source, destination } = result;
|
|
49776
|
+
if (source.index === destination.index) return;
|
|
49777
|
+
const flat2 = buildFlat(layout, true, true);
|
|
49778
|
+
if (draggableId.startsWith("fh:")) {
|
|
49779
|
+
const folderId = draggableId.slice(3);
|
|
49780
|
+
flat2.splice(source.index, 1);
|
|
49781
|
+
const group = [];
|
|
49782
|
+
while (flat2[source.index] && (flat2[source.index].kind === "project" && flat2[source.index].folderId === folderId || flat2[source.index].kind === "empty-folder-slot" && flat2[source.index].folderId === folderId)) {
|
|
49783
|
+
group.push(flat2.splice(source.index, 1)[0]);
|
|
49784
|
+
}
|
|
49785
|
+
const at2 = Math.min(destination.index, flat2.length);
|
|
49786
|
+
flat2.splice(at2, 0, { kind: "folder-header", folderId }, ...group);
|
|
49787
|
+
} else {
|
|
49788
|
+
const [moved] = flat2.splice(source.index, 1);
|
|
49789
|
+
const newFolderId = folderAtDest(flat2, destination.index);
|
|
49790
|
+
flat2.splice(destination.index, 0, { ...moved, folderId: newFolderId });
|
|
49791
|
+
}
|
|
49792
|
+
update2(flatToLayout(flat2, layout));
|
|
49793
|
+
};
|
|
49794
|
+
const projectMap = Object.fromEntries(projects.map((p) => [p.workspaceId, p]));
|
|
49795
|
+
const flat = buildFlat(layout, isDragging2, isDragging2);
|
|
49796
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(DragDropContext, { onDragStart: () => setIsDragging(true), onDragUpdate: onDragUpdate2, onDragEnd: onDragEnd2, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectedDroppable, { droppableId: "sidebar", children: (provided) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: provided.innerRef, ...provided.droppableProps, className: "flex flex-col", children: [
|
|
49797
|
+
flat.map((item, index2) => {
|
|
49798
|
+
if (item.kind === "folder-header") {
|
|
49799
|
+
const folder = layout.folders[item.folderId];
|
|
49800
|
+
if (!folder) return null;
|
|
49801
|
+
const expanded = !folder.collapsed || isDragging2;
|
|
49802
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(PublicDraggable, { draggableId: `fh:${item.folderId}`, index: index2, children: (dp, snap) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49803
|
+
FolderHeader,
|
|
49804
|
+
{
|
|
49805
|
+
folderId: item.folderId,
|
|
49806
|
+
folder,
|
|
49807
|
+
dp,
|
|
49808
|
+
snap,
|
|
49809
|
+
expanded,
|
|
49810
|
+
hovered: hoveredFolderId === item.folderId,
|
|
49811
|
+
editing: editingId === item.folderId,
|
|
49812
|
+
editName,
|
|
49813
|
+
editRef,
|
|
49814
|
+
onToggleCollapse: toggleCollapse,
|
|
49815
|
+
onStartRename: startRename,
|
|
49816
|
+
onDeleteFolder: deleteFolder,
|
|
49817
|
+
onEditNameChange: setEditName,
|
|
49818
|
+
onCommitRename: commitRename,
|
|
49819
|
+
onCancelRename: () => setEditingId(null)
|
|
49820
|
+
}
|
|
49821
|
+
) }, `fh:${item.folderId}`);
|
|
49822
|
+
}
|
|
49823
|
+
if (item.kind === "empty-folder-slot") {
|
|
49824
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49825
|
+
PublicDraggable,
|
|
49826
|
+
{
|
|
49827
|
+
draggableId: `slot:${item.folderId}`,
|
|
49828
|
+
index: index2,
|
|
49829
|
+
isDragDisabled: true,
|
|
49830
|
+
children: (dp) => /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyFolderSlot, { dp })
|
|
49831
|
+
},
|
|
49832
|
+
`slot:${item.folderId}`
|
|
49833
|
+
);
|
|
49834
|
+
}
|
|
49835
|
+
const project = projectMap[item.workspaceId];
|
|
49836
|
+
if (!project) return null;
|
|
49837
|
+
const isActive2 = item.workspaceId === activeWorkspaceId;
|
|
49838
|
+
const indent2 = item.folderId !== null;
|
|
49839
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(PublicDraggable, { draggableId: `p:${item.workspaceId}`, index: index2, children: (dp, snap) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49840
|
+
ProjectItem,
|
|
49841
|
+
{
|
|
49842
|
+
project,
|
|
49843
|
+
workspaceId: item.workspaceId,
|
|
49844
|
+
dp,
|
|
49845
|
+
snap,
|
|
49846
|
+
isActive: isActive2,
|
|
49847
|
+
indent: indent2,
|
|
49848
|
+
onSwitch,
|
|
49849
|
+
onRemove
|
|
49850
|
+
}
|
|
49851
|
+
) }, `p:${item.workspaceId}`);
|
|
49852
|
+
}),
|
|
49853
|
+
provided.placeholder
|
|
49854
|
+
] }) }) });
|
|
49762
49855
|
});
|
|
49856
|
+
function CardDetailHeader({
|
|
49857
|
+
card,
|
|
49858
|
+
workspaceId,
|
|
49859
|
+
projectName,
|
|
49860
|
+
externalUrl,
|
|
49861
|
+
isStory,
|
|
49862
|
+
isReadyForReview,
|
|
49863
|
+
hasStartCommand = false,
|
|
49864
|
+
merging,
|
|
49865
|
+
onMerge,
|
|
49866
|
+
onPR,
|
|
49867
|
+
onDelete,
|
|
49868
|
+
onClose
|
|
49869
|
+
}) {
|
|
49870
|
+
var _a3, _b2, _c3;
|
|
49871
|
+
const { session: runSession, start: startRun, stop: stopRun } = useRunSession(workspaceId);
|
|
49872
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-6 py-2.5 border-b border-[#2a2a35] bg-[#141418] shrink-0", children: [
|
|
49873
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-[#60607a] hover:text-gray-300 transition-colors", title: "Back to board", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 18 }) }),
|
|
49874
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49875
|
+
projectName && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
49876
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-[#60607a]", children: projectName }),
|
|
49877
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-[#2a2a35]", children: "/" })
|
|
49878
|
+
] }),
|
|
49879
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] font-semibold text-[#f0f0f5] truncate", children: ((_a3 = card.description) == null ? void 0 : _a3.split("\n")[0]) ?? card.id }),
|
|
49880
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
49881
|
+
externalUrl && !((_b2 = card.pr) == null ? void 0 : _b2.url) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49882
|
+
"a",
|
|
49883
|
+
{
|
|
49884
|
+
href: externalUrl,
|
|
49885
|
+
target: "_blank",
|
|
49886
|
+
rel: "noreferrer",
|
|
49887
|
+
className: "text-[#60607a] hover:text-gray-300 transition-colors",
|
|
49888
|
+
title: "Open external link",
|
|
49889
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 15 })
|
|
49890
|
+
}
|
|
49891
|
+
),
|
|
49892
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49893
|
+
hasStartCommand && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: runSession.status === "running" && runSession.cardId === card.id ? /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: "Stop", side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49894
|
+
"button",
|
|
49895
|
+
{
|
|
49896
|
+
onClick: () => void stopRun(),
|
|
49897
|
+
className: "cursor-pointer text-[#60607a] hover:text-red-400 transition-colors",
|
|
49898
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Square, { size: 15, className: "fill-current" })
|
|
49899
|
+
}
|
|
49900
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49901
|
+
Tooltip_default,
|
|
49902
|
+
{
|
|
49903
|
+
delayDuration: 0,
|
|
49904
|
+
content: runSession.status === "running" ? "Another task is running" : "Run",
|
|
49905
|
+
side: "bottom",
|
|
49906
|
+
triggerAsChild: true,
|
|
49907
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49908
|
+
"button",
|
|
49909
|
+
{
|
|
49910
|
+
onClick: () => void startRun(card.id),
|
|
49911
|
+
disabled: runSession.status === "running",
|
|
49912
|
+
className: "cursor-pointer text-[#60607a] hover:text-emerald-400 transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
49913
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 15 })
|
|
49914
|
+
}
|
|
49915
|
+
)
|
|
49916
|
+
}
|
|
49917
|
+
) }),
|
|
49918
|
+
!isStory && isReadyForReview && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
49919
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49920
|
+
Tooltip_default,
|
|
49921
|
+
{
|
|
49922
|
+
delayDuration: 0,
|
|
49923
|
+
content: merging ? "Merging..." : `Merge into ${card.baseRef}`,
|
|
49924
|
+
side: "bottom",
|
|
49925
|
+
triggerAsChild: true,
|
|
49926
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49927
|
+
"button",
|
|
49928
|
+
{
|
|
49929
|
+
onClick: onMerge,
|
|
49930
|
+
disabled: merging,
|
|
49931
|
+
className: "cursor-pointer text-[#60607a] hover:text-emerald-400 transition-colors disabled:opacity-40",
|
|
49932
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitMerge, { size: 15 })
|
|
49933
|
+
}
|
|
49934
|
+
)
|
|
49935
|
+
}
|
|
49936
|
+
),
|
|
49937
|
+
((_c3 = card.pr) == null ? void 0 : _c3.url) ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49938
|
+
"a",
|
|
49939
|
+
{
|
|
49940
|
+
href: card.pr.url,
|
|
49941
|
+
target: "_blank",
|
|
49942
|
+
rel: "noreferrer",
|
|
49943
|
+
title: "Open Pull Request",
|
|
49944
|
+
className: "cursor-pointer text-green-400 hover:text-green-300 transition-colors",
|
|
49945
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitPullRequest, { size: 15 })
|
|
49946
|
+
}
|
|
49947
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: `Create PR against ${card.baseRef}`, side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49948
|
+
"button",
|
|
49949
|
+
{
|
|
49950
|
+
onClick: onPR,
|
|
49951
|
+
disabled: merging,
|
|
49952
|
+
className: "cursor-pointer text-[#60607a] hover:text-green-400 transition-colors disabled:opacity-40",
|
|
49953
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitPullRequest, { size: 15 })
|
|
49954
|
+
}
|
|
49955
|
+
) })
|
|
49956
|
+
] }),
|
|
49957
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49958
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: "Delete task", side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49959
|
+
"button",
|
|
49960
|
+
{
|
|
49961
|
+
onClick: onDelete,
|
|
49962
|
+
className: "cursor-pointer text-[#60607a] hover:text-red-400 transition-colors",
|
|
49963
|
+
title: "Delete task",
|
|
49964
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 15 })
|
|
49965
|
+
}
|
|
49966
|
+
) })
|
|
49967
|
+
] });
|
|
49968
|
+
}
|
|
49763
49969
|
const COLUMN_LABELS = {
|
|
49764
49970
|
todo: "Todo",
|
|
49765
49971
|
in_progress: "In Progress",
|
|
@@ -73705,19 +73911,6 @@ function CommitMsgDialog({
|
|
|
73705
73911
|
] })
|
|
73706
73912
|
] });
|
|
73707
73913
|
}
|
|
73708
|
-
function BranchSelect({ branches, value, onChange, placeholder = "Select branch" }) {
|
|
73709
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
73710
|
-
Select_default,
|
|
73711
|
-
{
|
|
73712
|
-
value,
|
|
73713
|
-
onChange: (v2) => onChange(v2),
|
|
73714
|
-
placeholder,
|
|
73715
|
-
filterable: true,
|
|
73716
|
-
prefix: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { size: 13, className: "text-[#8888a0]" }),
|
|
73717
|
-
children: branches.map((b2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: b2, label: b2 }, b2))
|
|
73718
|
-
}
|
|
73719
|
-
);
|
|
73720
|
-
}
|
|
73721
73914
|
function CreatePRDialog({
|
|
73722
73915
|
dismiss: dismiss2,
|
|
73723
73916
|
workspaceId,
|
|
@@ -74358,90 +74551,6 @@ function cardToFormModelConfig(cfg) {
|
|
|
74358
74551
|
}
|
|
74359
74552
|
return out;
|
|
74360
74553
|
}
|
|
74361
|
-
function ModelSelect({
|
|
74362
|
-
agentId,
|
|
74363
|
-
value,
|
|
74364
|
-
onChange,
|
|
74365
|
-
floatingStrategy,
|
|
74366
|
-
menuClassName
|
|
74367
|
-
}) {
|
|
74368
|
-
const staticOptions = MODEL_OPTIONS[agentId];
|
|
74369
|
-
const isDynamic = agentId === "opencode" || agentId === "cursor";
|
|
74370
|
-
const modelsRead = useRead(
|
|
74371
|
-
(api) => api("agents/models").GET({
|
|
74372
|
-
query: { agent: agentId === "cursor" ? "cursor" : "opencode" }
|
|
74373
|
-
}),
|
|
74374
|
-
{ enabled: isDynamic }
|
|
74375
|
-
);
|
|
74376
|
-
const dynamicModels = modelsRead.data ?? [];
|
|
74377
|
-
const isFetching = modelsRead.fetching;
|
|
74378
|
-
const options = isDynamic ? dynamicModels : staticOptions;
|
|
74379
|
-
const [customChosen, setCustomChosen] = reactExports.useState(false);
|
|
74380
|
-
const isPresetValue = value === "" || options.some((o2) => o2.value === value);
|
|
74381
|
-
const customMode = customChosen || !isPresetValue;
|
|
74382
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
74383
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
74384
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
74385
|
-
Select_default,
|
|
74386
|
-
{
|
|
74387
|
-
floatingStrategy,
|
|
74388
|
-
menuClassName,
|
|
74389
|
-
value: customMode ? "__custom__" : value,
|
|
74390
|
-
onChange: (v2) => {
|
|
74391
|
-
if (v2 === "__custom__") {
|
|
74392
|
-
setCustomChosen(true);
|
|
74393
|
-
} else {
|
|
74394
|
-
setCustomChosen(false);
|
|
74395
|
-
onChange(v2);
|
|
74396
|
-
}
|
|
74397
|
-
},
|
|
74398
|
-
filterable: true,
|
|
74399
|
-
children: [
|
|
74400
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "", label: "Default" }),
|
|
74401
|
-
options.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value)),
|
|
74402
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "__custom__", label: "Custom..." })
|
|
74403
|
-
]
|
|
74404
|
-
}
|
|
74405
|
-
) }),
|
|
74406
|
-
isDynamic && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
74407
|
-
"button",
|
|
74408
|
-
{
|
|
74409
|
-
type: "button",
|
|
74410
|
-
onClick: () => void modelsRead.trigger(),
|
|
74411
|
-
disabled: isFetching,
|
|
74412
|
-
title: "Refresh model list",
|
|
74413
|
-
className: "flex items-center justify-center px-2 rounded border border-[var(--color-border-secondary)] bg-[#1a1a1f] hover:bg-[var(--color-surface-hover)] disabled:opacity-50 transition-colors",
|
|
74414
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
74415
|
-
"svg",
|
|
74416
|
-
{
|
|
74417
|
-
className: classNames("w-4 h-4", isFetching ? "animate-spin" : ""),
|
|
74418
|
-
fill: "none",
|
|
74419
|
-
viewBox: "0 0 24 24",
|
|
74420
|
-
stroke: "currentColor",
|
|
74421
|
-
strokeWidth: 2,
|
|
74422
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
74423
|
-
"path",
|
|
74424
|
-
{
|
|
74425
|
-
strokeLinecap: "round",
|
|
74426
|
-
strokeLinejoin: "round",
|
|
74427
|
-
d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
|
74428
|
-
}
|
|
74429
|
-
)
|
|
74430
|
-
}
|
|
74431
|
-
)
|
|
74432
|
-
}
|
|
74433
|
-
)
|
|
74434
|
-
] }),
|
|
74435
|
-
customMode && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
74436
|
-
Input_default,
|
|
74437
|
-
{
|
|
74438
|
-
value,
|
|
74439
|
-
onChange: (e) => onChange(e.target.value),
|
|
74440
|
-
placeholder: agentId === "opencode" ? "e.g. anthropic/claude-opus-4-7" : agentId === "cursor" ? "e.g. claude-opus-4-7-thinking-max" : agentId === "claude" ? "e.g. claude-opus-4-7" : "e.g. gpt-5-codex"
|
|
74441
|
-
}
|
|
74442
|
-
)
|
|
74443
|
-
] });
|
|
74444
|
-
}
|
|
74445
74554
|
function ModelTiersDialog({
|
|
74446
74555
|
pairs,
|
|
74447
74556
|
defaultBinary,
|
|
@@ -74564,13 +74673,12 @@ function TierRow({
|
|
|
74564
74673
|
}
|
|
74565
74674
|
),
|
|
74566
74675
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
74567
|
-
|
|
74676
|
+
AgentBinarySelect,
|
|
74568
74677
|
{
|
|
74569
74678
|
floatingStrategy: "fixed",
|
|
74570
74679
|
value: pair.binary,
|
|
74571
74680
|
onChange: (v2) => onPatch({ binary: v2, model: null }),
|
|
74572
|
-
menuClassName: "w-fit"
|
|
74573
|
-
children: AGENT_BINARY_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value))
|
|
74681
|
+
menuClassName: "w-fit"
|
|
74574
74682
|
}
|
|
74575
74683
|
),
|
|
74576
74684
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -79344,7 +79452,7 @@ function TagInput({
|
|
|
79344
79452
|
}) {
|
|
79345
79453
|
const [draft, setDraft] = reactExports.useState("");
|
|
79346
79454
|
const add2 = (raw2) => {
|
|
79347
|
-
const tag = normalizeTag(raw2);
|
|
79455
|
+
const tag = normalizeTag$1(raw2);
|
|
79348
79456
|
if (!tag || value.includes(tag)) return;
|
|
79349
79457
|
onChange([...value, tag]);
|
|
79350
79458
|
setDraft("");
|
|
@@ -79764,49 +79872,6 @@ function MemorySection({ workspaceId }) {
|
|
|
79764
79872
|
] })
|
|
79765
79873
|
] });
|
|
79766
79874
|
}
|
|
79767
|
-
function AgentModelPicker({
|
|
79768
|
-
value,
|
|
79769
|
-
onChange,
|
|
79770
|
-
floatingStrategy,
|
|
79771
|
-
menuClassName
|
|
79772
|
-
}) {
|
|
79773
|
-
const agentId = value.agentId ?? "claude";
|
|
79774
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start", children: [
|
|
79775
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full sm:w-32 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
79776
|
-
Select_default,
|
|
79777
|
-
{
|
|
79778
|
-
value: agentId,
|
|
79779
|
-
floatingStrategy,
|
|
79780
|
-
menuClassName,
|
|
79781
|
-
onChange: (v2) => onChange({ ...value, agentId: v2, model: null }),
|
|
79782
|
-
children: AGENT_BINARY_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value))
|
|
79783
|
-
}
|
|
79784
|
-
) }),
|
|
79785
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
79786
|
-
ModelSelect,
|
|
79787
|
-
{
|
|
79788
|
-
agentId,
|
|
79789
|
-
value: value.model ?? "",
|
|
79790
|
-
onChange: (v2) => onChange({ ...value, model: v2 || null }),
|
|
79791
|
-
floatingStrategy,
|
|
79792
|
-
menuClassName
|
|
79793
|
-
}
|
|
79794
|
-
) }),
|
|
79795
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full sm:w-36 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
79796
|
-
Select_default,
|
|
79797
|
-
{
|
|
79798
|
-
value: value.effort ?? "",
|
|
79799
|
-
floatingStrategy,
|
|
79800
|
-
menuClassName,
|
|
79801
|
-
onChange: (v2) => onChange({ ...value, effort: v2 || null }),
|
|
79802
|
-
children: [
|
|
79803
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "", label: "Default effort" }),
|
|
79804
|
-
EFFORT_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value))
|
|
79805
|
-
]
|
|
79806
|
-
}
|
|
79807
|
-
) })
|
|
79808
|
-
] });
|
|
79809
|
-
}
|
|
79810
79875
|
function SaveRow({ saving, onSave }) {
|
|
79811
79876
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end pt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button_default, { onClick: onSave, disabled: saving, children: saving ? "Saving..." : "Save" }) });
|
|
79812
79877
|
}
|