whipped 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +39 -19
- package/dist/web-ui/assets/{index-rpsRpaUU.js → index-Ce4HDOh7.js} +1664 -1598
- package/dist/web-ui/index.html +1 -1
- package/package.json +1 -1
|
@@ -27169,389 +27169,954 @@ 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-fable-5", label: "Fable 5" },
|
|
27190
|
+
{ value: "claude-opus-4-8", label: "Opus 4.8" },
|
|
27191
|
+
{ value: "claude-opus-4-7", label: "Opus 4.7" },
|
|
27192
|
+
{ value: "claude-opus-4-6", label: "Opus 4.6" },
|
|
27193
|
+
{ value: "claude-sonnet-4-6", label: "Sonnet 4.6" },
|
|
27194
|
+
{ value: "claude-sonnet-4-5", label: "Sonnet 4.5" },
|
|
27195
|
+
{ value: "claude-haiku-4-5", label: "Haiku 4.5" }
|
|
27196
|
+
],
|
|
27197
|
+
codex: [
|
|
27198
|
+
{ value: "gpt-5.5", label: "GPT-5.5 (default)" },
|
|
27199
|
+
{ value: "gpt-5.4", label: "GPT-5.4" },
|
|
27200
|
+
{ value: "gpt-5.4-mini", label: "GPT-5.4 Mini" },
|
|
27201
|
+
{ value: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
|
|
27202
|
+
{ value: "gpt-5.2", label: "GPT-5.2" }
|
|
27203
|
+
],
|
|
27204
|
+
// opencode supports any provider/model string — no fixed presets.
|
|
27205
|
+
// The UI renders a free-form text input for opencode model selection.
|
|
27206
|
+
opencode: [],
|
|
27207
|
+
// cursor supports many models — no fixed presets.
|
|
27208
|
+
// The UI fetches the live list via agents.cursorModels and renders a Select.
|
|
27209
|
+
cursor: []
|
|
27210
|
+
};
|
|
27211
|
+
const agentModelChoiceSchema = object({
|
|
27212
|
+
agentId: runtimeAgentIdSchema.default("claude"),
|
|
27213
|
+
model: string$2().nullable().optional(),
|
|
27214
|
+
effort: effortLevelSchema.nullable().optional()
|
|
27176
27215
|
});
|
|
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;
|
|
27216
|
+
const DEFAULT_AGENT_MODEL_CHOICE = { agentId: "claude", model: null, effort: null };
|
|
27217
|
+
const workflowSlotTypeSchema = _enum(["dev", "review", "plan", "orch"]);
|
|
27218
|
+
const tierLevelSchema = _enum(["minimal", "low", "medium", "high", "max"]);
|
|
27219
|
+
const LEVEL_ORDER = ["minimal", "low", "medium", "high", "max"];
|
|
27220
|
+
const TIER_LEVEL_OPTIONS = [
|
|
27221
|
+
{ value: "minimal", label: "Minimal" },
|
|
27222
|
+
{ value: "low", label: "Low" },
|
|
27223
|
+
{ value: "medium", label: "Medium" },
|
|
27224
|
+
{ value: "high", label: "High" },
|
|
27225
|
+
{ value: "max", label: "Max" }
|
|
27226
|
+
];
|
|
27227
|
+
const modelPairSchema = object({
|
|
27228
|
+
id: string$2(),
|
|
27229
|
+
level: tierLevelSchema,
|
|
27230
|
+
isFree: boolean$1().default(false),
|
|
27231
|
+
binary: runtimeAgentIdSchema,
|
|
27232
|
+
model: string$2().nullable().optional(),
|
|
27233
|
+
effort: effortLevelSchema.nullable().optional()
|
|
27234
|
+
});
|
|
27235
|
+
const pairSelectionModeSchema = _enum(["auto", "preferFree", "freeOnly", "paidOnly"]);
|
|
27236
|
+
const PAIR_SELECTION_MODE_OPTIONS = [
|
|
27237
|
+
{ value: "auto", label: "Auto (priority)" },
|
|
27238
|
+
{ value: "preferFree", label: "Prefer free" },
|
|
27239
|
+
{ value: "freeOnly", label: "Free only" },
|
|
27240
|
+
{ value: "paidOnly", label: "Paid only" }
|
|
27241
|
+
];
|
|
27242
|
+
const SLOT_TOOL_IDS = ["browser"];
|
|
27243
|
+
const slotToolSchema = _enum(SLOT_TOOL_IDS);
|
|
27244
|
+
const slotModelConfigSchema = object({
|
|
27245
|
+
pairs: array(modelPairSchema).min(1),
|
|
27246
|
+
mode: pairSelectionModeSchema.default("auto"),
|
|
27247
|
+
pinnedPairId: string$2().optional()
|
|
27248
|
+
});
|
|
27249
|
+
const cardModelConfigSchema = record(string$2(), slotModelConfigSchema);
|
|
27250
|
+
function pickByMode(candidates, mode) {
|
|
27251
|
+
switch (mode) {
|
|
27252
|
+
case "preferFree":
|
|
27253
|
+
return candidates.find((p) => p.isFree) ?? candidates[0];
|
|
27254
|
+
case "freeOnly":
|
|
27255
|
+
return candidates.find((p) => p.isFree);
|
|
27256
|
+
case "paidOnly":
|
|
27257
|
+
return candidates.find((p) => !p.isFree);
|
|
27258
|
+
default:
|
|
27259
|
+
return candidates[0];
|
|
27443
27260
|
}
|
|
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
27261
|
}
|
|
27528
|
-
function
|
|
27529
|
-
|
|
27530
|
-
|
|
27531
|
-
|
|
27532
|
-
}
|
|
27533
|
-
if ((requestOptions == null ? void 0 : requestOptions.body) !== void 0) {
|
|
27534
|
-
fields.body = requestOptions.body;
|
|
27262
|
+
function resolvePair(cfg, activeLevel) {
|
|
27263
|
+
if (cfg.pinnedPairId) {
|
|
27264
|
+
const pinned = cfg.pairs.find((p) => p.id === cfg.pinnedPairId);
|
|
27265
|
+
if (pinned) return pinned;
|
|
27535
27266
|
}
|
|
27536
|
-
|
|
27537
|
-
|
|
27267
|
+
const startIdx = LEVEL_ORDER.indexOf(activeLevel);
|
|
27268
|
+
const order2 = [];
|
|
27269
|
+
for (let i2 = startIdx; i2 < LEVEL_ORDER.length; i2++) order2.push(i2);
|
|
27270
|
+
for (let i2 = startIdx - 1; i2 >= 0; i2--) order2.push(i2);
|
|
27271
|
+
for (const i2 of order2) {
|
|
27272
|
+
const candidates = cfg.pairs.filter((p) => p.level === LEVEL_ORDER[i2]);
|
|
27273
|
+
if (candidates.length === 0) continue;
|
|
27274
|
+
const pick3 = pickByMode(candidates, cfg.mode);
|
|
27275
|
+
if (pick3) return pick3;
|
|
27538
27276
|
}
|
|
27539
|
-
|
|
27540
|
-
|
|
27277
|
+
for (const i2 of order2) {
|
|
27278
|
+
const candidates = cfg.pairs.filter((p) => p.level === LEVEL_ORDER[i2]);
|
|
27279
|
+
if (candidates[0]) return candidates[0];
|
|
27541
27280
|
}
|
|
27542
|
-
|
|
27281
|
+
const fallback = cfg.pairs[0];
|
|
27282
|
+
if (!fallback) throw new Error("resolvePair: slot has no model pairs");
|
|
27283
|
+
return fallback;
|
|
27543
27284
|
}
|
|
27544
|
-
|
|
27545
|
-
|
|
27546
|
-
return
|
|
27285
|
+
const promptValueSchema = preprocess$1(
|
|
27286
|
+
(v2) => {
|
|
27287
|
+
if (typeof v2 === "string") return { source: "inline", text: v2 };
|
|
27288
|
+
return v2;
|
|
27289
|
+
},
|
|
27290
|
+
discriminatedUnion("source", [
|
|
27291
|
+
object({ source: literal("inline"), text: string$2() }),
|
|
27292
|
+
object({ source: literal("file"), path: string$2() })
|
|
27293
|
+
])
|
|
27294
|
+
);
|
|
27295
|
+
const EMPTY_INLINE_PROMPT = { source: "inline", text: "" };
|
|
27296
|
+
const workflowSlotSchema = object({
|
|
27297
|
+
id: string$2(),
|
|
27298
|
+
type: workflowSlotTypeSchema,
|
|
27299
|
+
name: string$2(),
|
|
27300
|
+
order: number$2().int().nonnegative(),
|
|
27301
|
+
enabled: boolean$1(),
|
|
27302
|
+
prompt: promptValueSchema.default(EMPTY_INLINE_PROMPT),
|
|
27303
|
+
// Model tiers for this slot, in priority order (top = highest). Copied to the
|
|
27304
|
+
// card at creation; the card's active level + mode select which pair runs.
|
|
27305
|
+
pairs: array(modelPairSchema).min(1),
|
|
27306
|
+
mode: pairSelectionModeSchema.default("auto"),
|
|
27307
|
+
// Tools this slot may use (e.g. "browser"). Workflow-only, not ticket-editable.
|
|
27308
|
+
tools: array(slotToolSchema).default([]),
|
|
27309
|
+
// review slots only: may set the card's active level on reopen.
|
|
27310
|
+
canAdjustLevel: boolean$1().default(false),
|
|
27311
|
+
// plan slots only: re-run even if a plan already exists on the card.
|
|
27312
|
+
rerun: boolean$1().default(false)
|
|
27313
|
+
});
|
|
27314
|
+
const workflowSchema = object({
|
|
27315
|
+
id: string$2(),
|
|
27316
|
+
name: string$2(),
|
|
27317
|
+
isDefault: boolean$1().default(false),
|
|
27318
|
+
forStory: boolean$1().default(false),
|
|
27319
|
+
slots: array(workflowSlotSchema)
|
|
27320
|
+
});
|
|
27321
|
+
function highestWorkflowLevel(workflow) {
|
|
27322
|
+
let bestIdx = -1;
|
|
27323
|
+
for (const slot of (workflow == null ? void 0 : workflow.slots) ?? []) {
|
|
27324
|
+
for (const p of slot.pairs) bestIdx = Math.max(bestIdx, LEVEL_ORDER.indexOf(p.level));
|
|
27547
27325
|
}
|
|
27548
|
-
return
|
|
27326
|
+
return LEVEL_ORDER[bestIdx] ?? "medium";
|
|
27549
27327
|
}
|
|
27550
|
-
|
|
27551
|
-
|
|
27552
|
-
|
|
27553
|
-
|
|
27554
|
-
|
|
27328
|
+
const DEFAULT_GIT_INSTRUCTIONS = `# Git conventions
|
|
27329
|
+
|
|
27330
|
+
These rules govern how to write commit messages, PR titles, and PR
|
|
27331
|
+
descriptions.
|
|
27332
|
+
|
|
27333
|
+
## PR title
|
|
27334
|
+
- Imperative, present tense: "Add board view", "Fix race in poller".
|
|
27335
|
+
Not past tense, not gerund.
|
|
27336
|
+
- ≤70 characters; aim for 50.
|
|
27337
|
+
- Describe what shipped, not the task. "Add board view" beats
|
|
27338
|
+
"Implement board view feature".
|
|
27339
|
+
- No prefixes like \`feat:\` / \`[FEAT]\` / \`fix:\`.
|
|
27340
|
+
- No ticket IDs in the title (put them in the description if needed).
|
|
27341
|
+
- No trailing period.
|
|
27342
|
+
|
|
27343
|
+
## PR description
|
|
27344
|
+
Keep it focused. Two sections, nothing more unless genuinely useful:
|
|
27345
|
+
|
|
27346
|
+
## Summary
|
|
27347
|
+
- What changed and why. Use as many bullets as the scope warrants —
|
|
27348
|
+
a one-line fix is one bullet; a refactor touching 20 files may
|
|
27349
|
+
need ten. Don't pad, don't truncate.
|
|
27350
|
+
|
|
27351
|
+
## Test plan
|
|
27352
|
+
- What you actually ran or clicked, and the outcome.
|
|
27353
|
+
- Type-check and lint passing are not a test plan on their own.
|
|
27354
|
+
- If something couldn't be verified, say so in one line.
|
|
27355
|
+
|
|
27356
|
+
Do NOT include:
|
|
27357
|
+
- Iteration narration ("Round N", "addressed feedback", "after review").
|
|
27358
|
+
- Commit SHAs or branch names — GitHub already shows both.
|
|
27359
|
+
- Paths to internal planning docs, scratch files, or task tracker URLs.
|
|
27360
|
+
- "Verification:" sections that only list a passing type-check or lint.
|
|
27361
|
+
- Self-congratulation ("clean", "all checks pass", "ready to merge").
|
|
27362
|
+
- Restating the task description verbatim.
|
|
27363
|
+
|
|
27364
|
+
## Commit messages
|
|
27365
|
+
- Short imperative subject line, ≤72 chars. That's usually enough.
|
|
27366
|
+
- Skip the body unless a reviewer reading the diff alone would be
|
|
27367
|
+
confused about *why* the change exists.
|
|
27368
|
+
- Reference an issue only if a concrete one exists to close
|
|
27369
|
+
(\`Closes #123\`). Never invent issue numbers.
|
|
27370
|
+
`;
|
|
27371
|
+
const runtimeBoardColumnIdSchema = _enum([
|
|
27372
|
+
"todo",
|
|
27373
|
+
"in_progress",
|
|
27374
|
+
"reopened",
|
|
27375
|
+
"ready_for_review",
|
|
27376
|
+
"blocked",
|
|
27377
|
+
"done"
|
|
27378
|
+
]);
|
|
27379
|
+
const reviewActorSchema = object({
|
|
27380
|
+
type: _enum(["ai", "human", "external"]),
|
|
27381
|
+
id: string$2(),
|
|
27382
|
+
source: string$2().optional()
|
|
27383
|
+
});
|
|
27384
|
+
const reviewIssueSchema = object({
|
|
27385
|
+
file: string$2().optional(),
|
|
27386
|
+
line: number$2().optional(),
|
|
27387
|
+
severity: _enum(["blocking", "warning", "info"]),
|
|
27388
|
+
message: string$2()
|
|
27389
|
+
});
|
|
27390
|
+
const reviewAttachmentSchema = object({
|
|
27391
|
+
type: string$2(),
|
|
27392
|
+
// "image" | "file" | any mime category
|
|
27393
|
+
name: string$2(),
|
|
27394
|
+
mimeType: string$2(),
|
|
27395
|
+
path: string$2()
|
|
27396
|
+
// absolute path in ~/.whipped/attachments/
|
|
27397
|
+
});
|
|
27398
|
+
const runtimeReviewCommentSchema = object({
|
|
27399
|
+
id: string$2(),
|
|
27400
|
+
type: string$2(),
|
|
27401
|
+
actor: reviewActorSchema,
|
|
27402
|
+
status: _enum(["pass", "fail", "warning", "skipped"]).optional(),
|
|
27403
|
+
createdAt: number$2(),
|
|
27404
|
+
streamId: string$2().optional(),
|
|
27405
|
+
summary: string$2(),
|
|
27406
|
+
issues: array(reviewIssueSchema).optional(),
|
|
27407
|
+
attachments: array(reviewAttachmentSchema).optional(),
|
|
27408
|
+
metadata: record(string$2(), unknown$1()).optional()
|
|
27409
|
+
});
|
|
27410
|
+
const runtimeActivityEntrySchema = object({
|
|
27411
|
+
timestamp: number$2(),
|
|
27412
|
+
message: string$2()
|
|
27413
|
+
});
|
|
27414
|
+
const runtimeTaskSessionStateSchema = _enum(["running", "stopped", "completed", "failed", "killed"]);
|
|
27415
|
+
const runtimeTerminalSessionEntrySchema = object({
|
|
27416
|
+
streamId: string$2(),
|
|
27417
|
+
type: string$2(),
|
|
27418
|
+
startedAt: number$2(),
|
|
27419
|
+
endedAt: number$2().optional(),
|
|
27420
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27421
|
+
state: runtimeTaskSessionStateSchema.optional()
|
|
27422
|
+
});
|
|
27423
|
+
const runtimeCardPrioritySchema = _enum(["urgent", "high", "medium", "low"]);
|
|
27424
|
+
const cardTypeSchema = _enum(["task", "story", "subtask"]);
|
|
27425
|
+
const runtimePrMetaSchema = object({
|
|
27426
|
+
url: string$2().optional(),
|
|
27427
|
+
title: string$2().optional(),
|
|
27428
|
+
description: string$2().optional(),
|
|
27429
|
+
updatedAt: number$2().optional(),
|
|
27430
|
+
updatedBy: string$2().optional()
|
|
27431
|
+
});
|
|
27432
|
+
const runtimeBoardCardSchema = object({
|
|
27433
|
+
id: string$2(),
|
|
27434
|
+
description: string$2(),
|
|
27435
|
+
descriptionAttachments: array(reviewAttachmentSchema).optional().default([]),
|
|
27436
|
+
columnId: runtimeBoardColumnIdSchema,
|
|
27437
|
+
type: cardTypeSchema.default("task"),
|
|
27438
|
+
readyForDev: boolean$1().default(false),
|
|
27439
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27440
|
+
priority: runtimeCardPrioritySchema.optional(),
|
|
27441
|
+
// Single-parent stacking: this card continues in the parent's worktree/branch
|
|
27442
|
+
// and starts once the parent reaches ready_for_review. Mutually exclusive with waitsFor.
|
|
27443
|
+
dependsOn: string$2().optional(),
|
|
27444
|
+
// Many-parent gate (tasks only): this card starts only once ALL listed cards are
|
|
27445
|
+
// done (merged), in a fresh worktree branched from baseRef. Mutually exclusive with dependsOn.
|
|
27446
|
+
waitsFor: array(string$2()).default([]),
|
|
27447
|
+
// Story-only: the IDs of this story's subtasks. The story triggers its orchestrator
|
|
27448
|
+
// workflow once every subtask reaches ready_for_review.
|
|
27449
|
+
subtaskIds: array(string$2()).default([]),
|
|
27450
|
+
autoFixAttempts: number$2().int().nonnegative().default(0),
|
|
27451
|
+
baseRef: string$2(),
|
|
27452
|
+
createdAt: number$2(),
|
|
27453
|
+
updatedAt: number$2(),
|
|
27454
|
+
githubIssueUrl: string$2().optional(),
|
|
27455
|
+
pr: runtimePrMetaSchema.optional(),
|
|
27456
|
+
workflowId: string$2().optional(),
|
|
27457
|
+
// Plan written by the one-shot plan agent; injected into the dev agent's prompt.
|
|
27458
|
+
plan: string$2().optional(),
|
|
27459
|
+
// Workflow-wide capability level; every slot resolves it to its own pair.
|
|
27460
|
+
activeLevel: tierLevelSchema.default("medium"),
|
|
27461
|
+
// Per-slot model config, snapshotted from the workflow at creation and editable
|
|
27462
|
+
// per ticket (slotId → {pairs, mode, pinnedPairId}).
|
|
27463
|
+
modelConfig: cardModelConfigSchema.optional(),
|
|
27464
|
+
reviewComments: array(runtimeReviewCommentSchema).default([]),
|
|
27465
|
+
activityLog: array(runtimeActivityEntrySchema).default([]),
|
|
27466
|
+
terminalSessions: array(runtimeTerminalSessionEntrySchema).default([]),
|
|
27467
|
+
githubCommentIds: array(string$2()).default([]),
|
|
27468
|
+
worktreePath: string$2().optional(),
|
|
27469
|
+
branchName: string$2().optional(),
|
|
27470
|
+
slackMessageTs: string$2().optional(),
|
|
27471
|
+
slackChannelId: string$2().optional()
|
|
27472
|
+
});
|
|
27473
|
+
const runtimeBoardColumnSchema = object({
|
|
27474
|
+
id: runtimeBoardColumnIdSchema,
|
|
27475
|
+
title: string$2(),
|
|
27476
|
+
taskIds: array(string$2())
|
|
27477
|
+
});
|
|
27478
|
+
const runtimeBoardDataSchema = object({
|
|
27479
|
+
columns: array(runtimeBoardColumnSchema),
|
|
27480
|
+
cards: record(string$2(), runtimeBoardCardSchema)
|
|
27481
|
+
});
|
|
27482
|
+
const runtimeGlobalConfigSchema = object({
|
|
27483
|
+
defaultAgent: runtimeAgentIdSchema.default("claude"),
|
|
27484
|
+
maxParallelTasks: number$2().int().positive().default(4),
|
|
27485
|
+
maxParallelQA: number$2().int().positive().default(1),
|
|
27486
|
+
maxAutoFixAttempts: number$2().int().nonnegative().default(3),
|
|
27487
|
+
pollingIntervalSeconds: number$2().int().positive().default(30),
|
|
27488
|
+
prPollingIntervalSeconds: number$2().int().positive().default(60),
|
|
27489
|
+
terminalApp: string$2().optional(),
|
|
27490
|
+
slackEnabled: boolean$1().default(true),
|
|
27491
|
+
slackBotToken: string$2().optional(),
|
|
27492
|
+
slackSigningSecret: string$2().optional(),
|
|
27493
|
+
slackAppConfigToken: string$2().optional(),
|
|
27494
|
+
slackClientId: string$2().optional(),
|
|
27495
|
+
slackClientSecret: string$2().optional(),
|
|
27496
|
+
slackAppId: string$2().optional(),
|
|
27497
|
+
slackOauthAuthorizeUrl: string$2().optional(),
|
|
27498
|
+
slackPublicUrl: string$2().optional(),
|
|
27499
|
+
slackBotName: string$2().default("Whipped"),
|
|
27500
|
+
slackInstallerUserId: string$2().optional(),
|
|
27501
|
+
autoStartTunnel: boolean$1().default(false),
|
|
27502
|
+
tunnelId: string$2().optional(),
|
|
27503
|
+
tunnelDomain: string$2().optional(),
|
|
27504
|
+
tunnelName: string$2().default("whipped"),
|
|
27505
|
+
// Auth: single shared password (scrypt hash) + HMAC secret for signed session
|
|
27506
|
+
// cookies + machine token for local agent machinery (MCP/hooks). Never expose
|
|
27507
|
+
// these over the API — see configController's response.
|
|
27508
|
+
authPasswordHash: string$2().optional(),
|
|
27509
|
+
authSessionSecret: string$2().optional(),
|
|
27510
|
+
authMachineToken: string$2().optional()
|
|
27511
|
+
});
|
|
27512
|
+
const runtimeGithubConfigSchema = object({
|
|
27513
|
+
token: string$2()
|
|
27514
|
+
});
|
|
27515
|
+
const runtimeWorktreeSetupSchema = object({
|
|
27516
|
+
filesToCopy: array(string$2()).default([]),
|
|
27517
|
+
installCommand: string$2().default("")
|
|
27518
|
+
});
|
|
27519
|
+
const runtimeProjectSecretSchema = object({
|
|
27520
|
+
key: string$2().min(1),
|
|
27521
|
+
value: string$2()
|
|
27522
|
+
});
|
|
27523
|
+
const BUILTIN_SECRET_KEYS = ["GITHUB_TOKEN"];
|
|
27524
|
+
const runtimeProjectConfigSchema = object({
|
|
27525
|
+
name: string$2().optional(),
|
|
27526
|
+
defaultAgent: runtimeAgentIdSchema.optional(),
|
|
27527
|
+
maxParallelTasks: number$2().int().positive().optional(),
|
|
27528
|
+
maxAutoFixAttempts: number$2().int().nonnegative().optional(),
|
|
27529
|
+
pollingIntervalSeconds: number$2().int().positive().optional(),
|
|
27530
|
+
// What happens when a card passes review (polling/dispatch is always on; per-ticket
|
|
27531
|
+
// readyForDev gates pickup). "off" parks it in ready_for_review, "pr" auto-creates a
|
|
27532
|
+
// GitHub PR, "yolo" merges the branch straight into the local baseRef and pushes.
|
|
27533
|
+
deliveryMode: _enum(["off", "pr", "yolo"]).default("off"),
|
|
27534
|
+
autoCommit: boolean$1().default(true),
|
|
27535
|
+
defaultBaseBranch: string$2().optional(),
|
|
27536
|
+
github: runtimeGithubConfigSchema.optional(),
|
|
27537
|
+
worktreeSetup: runtimeWorktreeSetupSchema.optional(),
|
|
27538
|
+
startCommand: string$2().default(""),
|
|
27539
|
+
workflows: array(workflowSchema).default([]),
|
|
27540
|
+
secrets: array(runtimeProjectSecretSchema).default([]),
|
|
27541
|
+
systemPrompt: string$2().optional(),
|
|
27542
|
+
// Freeform instructions injected into the dev agent's prompt to shape PR
|
|
27543
|
+
// titles, descriptions, and commit messages. Empty/absent → daemon falls
|
|
27544
|
+
// back to DEFAULT_GIT_INSTRUCTIONS.
|
|
27545
|
+
gitInstructions: string$2().optional(),
|
|
27546
|
+
// Which agent binary/model/effort the assistant agent runs as. Absent → claude.
|
|
27547
|
+
assistantModel: agentModelChoiceSchema.optional()
|
|
27548
|
+
});
|
|
27549
|
+
object({
|
|
27550
|
+
workspaceId: string$2(),
|
|
27551
|
+
repoPath: string$2(),
|
|
27552
|
+
board: runtimeBoardDataSchema,
|
|
27553
|
+
revision: number$2(),
|
|
27554
|
+
projectConfig: runtimeProjectConfigSchema
|
|
27555
|
+
});
|
|
27556
|
+
object({
|
|
27557
|
+
board: runtimeBoardDataSchema,
|
|
27558
|
+
revision: number$2()
|
|
27559
|
+
});
|
|
27560
|
+
const runtimeVisualElementSchema = object({
|
|
27561
|
+
elementSelector: string$2().optional(),
|
|
27562
|
+
elementText: string$2().optional(),
|
|
27563
|
+
componentName: string$2().optional(),
|
|
27564
|
+
componentChain: array(string$2()).optional(),
|
|
27565
|
+
sourceFile: string$2().optional(),
|
|
27566
|
+
sourceLine: number$2().optional(),
|
|
27567
|
+
// The page the element was captured on. Selections can span pages, so this is
|
|
27568
|
+
// per-element rather than relying on the visualComment-level pageUrl.
|
|
27569
|
+
pageUrl: string$2().optional()
|
|
27570
|
+
});
|
|
27571
|
+
const runtimeVisualCommentSchema = object({
|
|
27572
|
+
pageUrl: string$2().optional(),
|
|
27573
|
+
elements: array(runtimeVisualElementSchema).default([])
|
|
27574
|
+
});
|
|
27575
|
+
const runtimeCardCreateRequestSchema = object({
|
|
27576
|
+
description: string$2(),
|
|
27577
|
+
type: cardTypeSchema.optional(),
|
|
27578
|
+
// Browser-extension element references; folded into the description server-side.
|
|
27579
|
+
visualComment: runtimeVisualCommentSchema.optional(),
|
|
27580
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27581
|
+
priority: runtimeCardPrioritySchema.optional(),
|
|
27582
|
+
readyForDev: boolean$1().optional(),
|
|
27583
|
+
dependsOn: string$2().optional(),
|
|
27584
|
+
waitsFor: array(string$2()).optional(),
|
|
27585
|
+
subtaskIds: array(string$2()).optional(),
|
|
27586
|
+
columnId: runtimeBoardColumnIdSchema.optional(),
|
|
27587
|
+
baseRef: string$2().optional(),
|
|
27588
|
+
githubIssueUrl: string$2().optional(),
|
|
27589
|
+
workflowId: string$2().optional(),
|
|
27590
|
+
descriptionAttachments: array(reviewAttachmentSchema).optional(),
|
|
27591
|
+
branchName: string$2().optional(),
|
|
27592
|
+
// Optional per-ticket overrides edited before creation. When omitted, the card
|
|
27593
|
+
// snapshots the resolved workflow's pairs and defaults the active level to the
|
|
27594
|
+
// workflow's highest configured tier.
|
|
27595
|
+
modelConfig: cardModelConfigSchema.optional(),
|
|
27596
|
+
activeLevel: tierLevelSchema.optional()
|
|
27597
|
+
});
|
|
27598
|
+
object({
|
|
27599
|
+
cardId: string$2(),
|
|
27600
|
+
targetColumnId: runtimeBoardColumnIdSchema,
|
|
27601
|
+
targetIndex: number$2().int().nonnegative().optional(),
|
|
27602
|
+
revision: number$2()
|
|
27603
|
+
});
|
|
27604
|
+
object({
|
|
27605
|
+
cardId: string$2(),
|
|
27606
|
+
description: string$2().optional(),
|
|
27607
|
+
descriptionAttachments: array(reviewAttachmentSchema).optional(),
|
|
27608
|
+
type: cardTypeSchema.optional(),
|
|
27609
|
+
agentId: runtimeAgentIdSchema.optional(),
|
|
27610
|
+
priority: runtimeCardPrioritySchema.optional(),
|
|
27611
|
+
readyForDev: boolean$1().optional(),
|
|
27612
|
+
dependsOn: string$2().optional(),
|
|
27613
|
+
waitsFor: array(string$2()).optional(),
|
|
27614
|
+
subtaskIds: array(string$2()).optional(),
|
|
27615
|
+
workflowId: string$2().optional(),
|
|
27616
|
+
branchName: string$2().optional(),
|
|
27617
|
+
plan: string$2().optional(),
|
|
27618
|
+
activeLevel: tierLevelSchema.optional(),
|
|
27619
|
+
modelConfig: cardModelConfigSchema.optional(),
|
|
27620
|
+
revision: number$2()
|
|
27621
|
+
});
|
|
27622
|
+
const memoryScopeSchema = _enum(["global", "project"]);
|
|
27623
|
+
const memoryTypeSchema = _enum([
|
|
27624
|
+
"fact",
|
|
27625
|
+
"convention",
|
|
27626
|
+
"decision",
|
|
27627
|
+
"preference",
|
|
27628
|
+
"rule",
|
|
27629
|
+
"lesson",
|
|
27630
|
+
"sharp_edge"
|
|
27631
|
+
]);
|
|
27632
|
+
const MEMORY_TYPE_OPTIONS = [
|
|
27633
|
+
{ value: "fact", label: "Fact" },
|
|
27634
|
+
{ value: "convention", label: "Convention" },
|
|
27635
|
+
{ value: "decision", label: "Decision" },
|
|
27636
|
+
{ value: "preference", label: "Preference" },
|
|
27637
|
+
{ value: "rule", label: "Rule" },
|
|
27638
|
+
{ value: "lesson", label: "Lesson" },
|
|
27639
|
+
{ value: "sharp_edge", label: "Sharp edge" }
|
|
27640
|
+
];
|
|
27641
|
+
const memorySourceTypeSchema = _enum(["user_correction", "explicit_save", "task_lesson", "manual_human"]);
|
|
27642
|
+
const memoryStatusSchema = _enum(["pending", "approved"]);
|
|
27643
|
+
const runtimeMemoryOriginAgentSchema = object({
|
|
27644
|
+
agent: string$2(),
|
|
27645
|
+
model: string$2().optional()
|
|
27646
|
+
});
|
|
27647
|
+
object({
|
|
27648
|
+
id: string$2(),
|
|
27649
|
+
scope: memoryScopeSchema,
|
|
27650
|
+
workspaceId: string$2().nullable(),
|
|
27651
|
+
originWorkspaceId: string$2().nullable().optional(),
|
|
27652
|
+
type: memoryTypeSchema,
|
|
27653
|
+
title: string$2(),
|
|
27654
|
+
content: string$2(),
|
|
27655
|
+
sourceType: memorySourceTypeSchema,
|
|
27656
|
+
importance: number$2().int().min(1).max(3).default(1),
|
|
27657
|
+
tags: array(string$2()).default([]),
|
|
27658
|
+
boundWorkspaceIds: array(string$2()).default([]),
|
|
27659
|
+
originCardId: string$2().nullable().optional(),
|
|
27660
|
+
originAgent: runtimeMemoryOriginAgentSchema.nullable().optional(),
|
|
27661
|
+
status: memoryStatusSchema.default("approved"),
|
|
27662
|
+
createdAt: number$2(),
|
|
27663
|
+
updatedAt: number$2()
|
|
27664
|
+
});
|
|
27665
|
+
function normalizeTag$1(raw2) {
|
|
27666
|
+
return raw2.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
27667
|
+
}
|
|
27668
|
+
_enum(["interval", "calendar"]);
|
|
27669
|
+
const recurringScheduleSchema = discriminatedUnion("kind", [
|
|
27670
|
+
object({ kind: literal("interval"), intervalSeconds: number$2().int().positive() }),
|
|
27671
|
+
object({ kind: literal("calendar"), cronExpr: string$2().min(1), timezone: string$2().min(1) })
|
|
27672
|
+
]);
|
|
27673
|
+
const recurringRunStatusSchema = _enum(["running", "ok", "error", "killed"]);
|
|
27674
|
+
const recurringRunTriggerSchema = _enum(["schedule", "manual"]);
|
|
27675
|
+
const recurringAgentRunSchema = object({
|
|
27676
|
+
id: string$2(),
|
|
27677
|
+
startedAt: number$2(),
|
|
27678
|
+
endedAt: number$2().optional(),
|
|
27679
|
+
status: recurringRunStatusSchema,
|
|
27680
|
+
summary: string$2().optional(),
|
|
27681
|
+
tokens: number$2().optional(),
|
|
27682
|
+
trigger: recurringRunTriggerSchema.default("schedule"),
|
|
27683
|
+
streamId: string$2().optional()
|
|
27684
|
+
});
|
|
27685
|
+
object({
|
|
27686
|
+
id: string$2(),
|
|
27687
|
+
name: string$2(),
|
|
27688
|
+
instructions: string$2().default(""),
|
|
27689
|
+
schedule: recurringScheduleSchema,
|
|
27690
|
+
model: agentModelChoiceSchema,
|
|
27691
|
+
enabled: boolean$1().default(true),
|
|
27692
|
+
lastRunAt: number$2().optional(),
|
|
27693
|
+
nextRunAt: number$2().optional(),
|
|
27694
|
+
journal: string$2().default(""),
|
|
27695
|
+
createdAt: number$2(),
|
|
27696
|
+
updatedAt: number$2(),
|
|
27697
|
+
recentRuns: array(recurringAgentRunSchema).default([])
|
|
27698
|
+
});
|
|
27699
|
+
object({
|
|
27700
|
+
name: string$2().min(1),
|
|
27701
|
+
instructions: string$2().optional(),
|
|
27702
|
+
schedule: recurringScheduleSchema,
|
|
27703
|
+
model: agentModelChoiceSchema.optional(),
|
|
27704
|
+
enabled: boolean$1().optional()
|
|
27705
|
+
});
|
|
27706
|
+
object({
|
|
27707
|
+
id: string$2(),
|
|
27708
|
+
name: string$2().min(1).optional(),
|
|
27709
|
+
instructions: string$2().optional(),
|
|
27710
|
+
schedule: recurringScheduleSchema.optional(),
|
|
27711
|
+
model: agentModelChoiceSchema.optional(),
|
|
27712
|
+
enabled: boolean$1().optional(),
|
|
27713
|
+
journal: string$2().optional()
|
|
27714
|
+
});
|
|
27715
|
+
const projectFolderSchema = object({
|
|
27716
|
+
id: string$2(),
|
|
27717
|
+
name: string$2(),
|
|
27718
|
+
collapsed: boolean$1().default(false),
|
|
27719
|
+
projectIds: array(string$2())
|
|
27720
|
+
});
|
|
27721
|
+
const topLevelItemSchema = discriminatedUnion("type", [
|
|
27722
|
+
object({ type: literal("folder"), id: string$2() }),
|
|
27723
|
+
object({ type: literal("project"), workspaceId: string$2() })
|
|
27724
|
+
]);
|
|
27725
|
+
object({
|
|
27726
|
+
version: literal(1),
|
|
27727
|
+
topLevel: array(topLevelItemSchema),
|
|
27728
|
+
folders: record(string$2(), projectFolderSchema)
|
|
27729
|
+
});
|
|
27730
|
+
object({
|
|
27731
|
+
workspaceId: string$2(),
|
|
27732
|
+
repoPath: string$2(),
|
|
27733
|
+
name: string$2(),
|
|
27734
|
+
lastUpdated: number$2()
|
|
27735
|
+
});
|
|
27736
|
+
const addProjectSchema = object({
|
|
27737
|
+
repoPath: string$2().min(1, "Repository path is required"),
|
|
27738
|
+
deliveryMode: _enum(["off", "pr", "yolo"]),
|
|
27739
|
+
defaultBaseBranch: string$2().optional(),
|
|
27740
|
+
assistantModel: agentModelChoiceSchema
|
|
27741
|
+
});
|
|
27742
|
+
function stringifyQuery(query) {
|
|
27743
|
+
const parts = [];
|
|
27744
|
+
for (const [key, value] of Object.entries(query)) {
|
|
27745
|
+
if (value === void 0 || value === null || value === "") {
|
|
27746
|
+
continue;
|
|
27747
|
+
}
|
|
27748
|
+
parts.push(
|
|
27749
|
+
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`
|
|
27750
|
+
);
|
|
27751
|
+
}
|
|
27752
|
+
return parts.join("&");
|
|
27753
|
+
}
|
|
27754
|
+
function buildUrl(baseUrl, path2, query) {
|
|
27755
|
+
const isAbsolute = /^https?:\/\//.test(baseUrl);
|
|
27756
|
+
if (isAbsolute) {
|
|
27757
|
+
const normalizedBase = baseUrl.replace(/\/?$/, "/");
|
|
27758
|
+
const url = new URL(path2.join("/"), normalizedBase);
|
|
27759
|
+
if (query) {
|
|
27760
|
+
url.search = stringifyQuery(query);
|
|
27761
|
+
}
|
|
27762
|
+
return url.toString();
|
|
27763
|
+
}
|
|
27764
|
+
const cleanBase = `/${baseUrl.replace(/^\/|\/$/g, "")}`;
|
|
27765
|
+
const pathStr = path2.length > 0 ? `/${path2.join("/")}` : "";
|
|
27766
|
+
const queryStr = query ? stringifyQuery(query) : "";
|
|
27767
|
+
return `${cleanBase}${pathStr}${queryStr ? `?${queryStr}` : ""}`;
|
|
27768
|
+
}
|
|
27769
|
+
function __DEV__() {
|
|
27770
|
+
return typeof process !== "undefined" && true;
|
|
27771
|
+
}
|
|
27772
|
+
function generateTags(path2) {
|
|
27773
|
+
return path2.map((_2, i2) => path2.slice(0, i2 + 1).join("/"));
|
|
27774
|
+
}
|
|
27775
|
+
function containsFile(value) {
|
|
27776
|
+
if (value instanceof File || value instanceof Blob) return true;
|
|
27777
|
+
if (Array.isArray(value)) return value.some(containsFile);
|
|
27778
|
+
if (value && typeof value === "object") {
|
|
27779
|
+
return Object.values(value).some(containsFile);
|
|
27780
|
+
}
|
|
27781
|
+
return false;
|
|
27782
|
+
}
|
|
27783
|
+
function isJsonBody(body) {
|
|
27784
|
+
if (body === null || body === void 0) return false;
|
|
27785
|
+
if (body instanceof FormData) return false;
|
|
27786
|
+
if (body instanceof Blob) return false;
|
|
27787
|
+
if (body instanceof ArrayBuffer) return false;
|
|
27788
|
+
if (body instanceof URLSearchParams) return false;
|
|
27789
|
+
if (body instanceof ReadableStream) return false;
|
|
27790
|
+
if (typeof body === "string") return false;
|
|
27791
|
+
if (typeof body === "object") {
|
|
27792
|
+
return true;
|
|
27793
|
+
}
|
|
27794
|
+
return false;
|
|
27795
|
+
}
|
|
27796
|
+
async function resolveHeaders(headers) {
|
|
27797
|
+
if (!headers) return void 0;
|
|
27798
|
+
if (typeof headers === "function") {
|
|
27799
|
+
return await headers();
|
|
27800
|
+
}
|
|
27801
|
+
return headers;
|
|
27802
|
+
}
|
|
27803
|
+
function headersInitToRecord(headers) {
|
|
27804
|
+
return Object.fromEntries(new Headers(headers));
|
|
27805
|
+
}
|
|
27806
|
+
async function resolveHeadersToRecord(headers) {
|
|
27807
|
+
const resolved = await resolveHeaders(headers);
|
|
27808
|
+
if (!resolved) return {};
|
|
27809
|
+
return headersInitToRecord(resolved);
|
|
27810
|
+
}
|
|
27811
|
+
async function mergeHeaders(defaultHeaders, requestHeaders) {
|
|
27812
|
+
const resolved1 = await resolveHeaders(defaultHeaders);
|
|
27813
|
+
const resolved2 = await resolveHeaders(requestHeaders);
|
|
27814
|
+
if (!resolved1 && !resolved2) return void 0;
|
|
27815
|
+
if (!resolved1) return resolved2;
|
|
27816
|
+
if (!resolved2) return resolved1;
|
|
27817
|
+
return {
|
|
27818
|
+
...Object.fromEntries(new Headers(resolved1)),
|
|
27819
|
+
...Object.fromEntries(new Headers(resolved2))
|
|
27820
|
+
};
|
|
27821
|
+
}
|
|
27822
|
+
function removeHeaderKeys(headers, keysToRemove) {
|
|
27823
|
+
if (!headers) return void 0;
|
|
27824
|
+
const headersObj = new Headers(headers);
|
|
27825
|
+
for (const key of keysToRemove) {
|
|
27826
|
+
headersObj.delete(key);
|
|
27827
|
+
}
|
|
27828
|
+
const entries = [...headersObj.entries()];
|
|
27829
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
27830
|
+
}
|
|
27831
|
+
function objectToFormData(obj) {
|
|
27832
|
+
const formData = new FormData();
|
|
27833
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
27834
|
+
if (value === null || value === void 0) {
|
|
27835
|
+
continue;
|
|
27836
|
+
}
|
|
27837
|
+
if (value instanceof Blob || value instanceof File) {
|
|
27838
|
+
formData.append(key, value);
|
|
27839
|
+
} else if (Array.isArray(value)) {
|
|
27840
|
+
for (const entry of value) {
|
|
27841
|
+
if (entry instanceof Blob || entry instanceof File) {
|
|
27842
|
+
formData.append(key, entry);
|
|
27843
|
+
} else if (typeof entry === "object" && entry !== null) {
|
|
27844
|
+
formData.append(key, JSON.stringify(entry));
|
|
27845
|
+
} else {
|
|
27846
|
+
formData.append(key, String(entry));
|
|
27847
|
+
}
|
|
27848
|
+
}
|
|
27849
|
+
} else if (typeof value === "object") {
|
|
27850
|
+
formData.append(key, JSON.stringify(value));
|
|
27851
|
+
} else {
|
|
27852
|
+
formData.append(key, String(value));
|
|
27853
|
+
}
|
|
27854
|
+
}
|
|
27855
|
+
return formData;
|
|
27856
|
+
}
|
|
27857
|
+
function objectToUrlEncoded(obj) {
|
|
27858
|
+
const params = new URLSearchParams();
|
|
27859
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
27860
|
+
if (value === void 0 || value === null) {
|
|
27861
|
+
continue;
|
|
27862
|
+
}
|
|
27863
|
+
if (Array.isArray(value)) {
|
|
27864
|
+
for (const item of value) {
|
|
27865
|
+
if (item !== void 0 && item !== null) {
|
|
27866
|
+
params.append(key, String(item));
|
|
27867
|
+
}
|
|
27868
|
+
}
|
|
27869
|
+
} else if (typeof value === "object") {
|
|
27870
|
+
params.append(key, JSON.stringify(value));
|
|
27871
|
+
} else {
|
|
27872
|
+
params.append(key, String(value));
|
|
27873
|
+
}
|
|
27874
|
+
}
|
|
27875
|
+
return params.toString();
|
|
27876
|
+
}
|
|
27877
|
+
function sortObjectKeys(obj, seen2 = /* @__PURE__ */ new WeakSet()) {
|
|
27878
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
27879
|
+
if (seen2.has(obj)) {
|
|
27880
|
+
return "[Circular]";
|
|
27881
|
+
}
|
|
27882
|
+
seen2.add(obj);
|
|
27883
|
+
if (Array.isArray(obj)) {
|
|
27884
|
+
return obj.map((item) => sortObjectKeys(item, seen2));
|
|
27885
|
+
}
|
|
27886
|
+
return Object.keys(obj).sort().reduce(
|
|
27887
|
+
(sorted, key) => {
|
|
27888
|
+
sorted[key] = sortObjectKeys(
|
|
27889
|
+
obj[key],
|
|
27890
|
+
seen2
|
|
27891
|
+
);
|
|
27892
|
+
return sorted;
|
|
27893
|
+
},
|
|
27894
|
+
{}
|
|
27895
|
+
);
|
|
27896
|
+
}
|
|
27897
|
+
function isSpooshBody(value) {
|
|
27898
|
+
return typeof value === "object" && value !== null && "__spooshBody" in value && value.__spooshBody === true;
|
|
27899
|
+
}
|
|
27900
|
+
function resolveRequestBody(rawBody) {
|
|
27901
|
+
if (rawBody === void 0 || rawBody === null) {
|
|
27902
|
+
return void 0;
|
|
27903
|
+
}
|
|
27904
|
+
if (isSpooshBody(rawBody)) {
|
|
27905
|
+
const body = rawBody;
|
|
27906
|
+
switch (body.kind) {
|
|
27907
|
+
case "form":
|
|
27908
|
+
return {
|
|
27909
|
+
body: objectToFormData(body.value),
|
|
27910
|
+
removeHeaders: ["Content-Type"]
|
|
27911
|
+
};
|
|
27912
|
+
case "json":
|
|
27913
|
+
return {
|
|
27914
|
+
body: JSON.stringify(body.value),
|
|
27915
|
+
headers: { "Content-Type": "application/json" }
|
|
27916
|
+
};
|
|
27917
|
+
case "urlencoded":
|
|
27918
|
+
return {
|
|
27919
|
+
body: objectToUrlEncoded(body.value),
|
|
27920
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" }
|
|
27921
|
+
};
|
|
27922
|
+
}
|
|
27923
|
+
}
|
|
27924
|
+
if (isJsonBody(rawBody)) {
|
|
27925
|
+
if (__DEV__() && containsFile(rawBody)) {
|
|
27926
|
+
console.warn(
|
|
27927
|
+
"[spoosh] Plain object body contains File/Blob. Use form() wrapper for multipart upload."
|
|
27928
|
+
);
|
|
27929
|
+
}
|
|
27930
|
+
return {
|
|
27931
|
+
body: JSON.stringify(rawBody),
|
|
27932
|
+
headers: { "Content-Type": "application/json" }
|
|
27933
|
+
};
|
|
27934
|
+
}
|
|
27935
|
+
if (rawBody instanceof FormData) {
|
|
27936
|
+
return { body: rawBody, removeHeaders: ["Content-Type"] };
|
|
27937
|
+
}
|
|
27938
|
+
return { body: rawBody };
|
|
27939
|
+
}
|
|
27940
|
+
function normalizeTag(tag) {
|
|
27941
|
+
return tag.startsWith("/") ? tag.slice(1) : tag;
|
|
27942
|
+
}
|
|
27943
|
+
function matchTag(entryTag, pattern) {
|
|
27944
|
+
const normalizedTag = normalizeTag(entryTag);
|
|
27945
|
+
const normalizedPattern = normalizeTag(pattern);
|
|
27946
|
+
if (normalizedPattern.endsWith("/*")) {
|
|
27947
|
+
const prefix2 = normalizedPattern.slice(0, -2);
|
|
27948
|
+
return prefix2 === "" ? normalizedTag.length > 0 : normalizedTag.startsWith(prefix2 + "/");
|
|
27949
|
+
}
|
|
27950
|
+
return normalizedTag === normalizedPattern;
|
|
27951
|
+
}
|
|
27952
|
+
function matchTags(entryTag, patterns) {
|
|
27953
|
+
return patterns.some((pattern) => matchTag(entryTag, pattern));
|
|
27954
|
+
}
|
|
27955
|
+
function resolveTags(options, resolvedPath) {
|
|
27956
|
+
const tagsOption = options == null ? void 0 : options.tags;
|
|
27957
|
+
if (!tagsOption) {
|
|
27958
|
+
const tag2 = resolvedPath.join("/");
|
|
27959
|
+
return tag2 ? [normalizeTag(tag2)] : [];
|
|
27960
|
+
}
|
|
27961
|
+
if (typeof tagsOption === "string") {
|
|
27962
|
+
return [normalizeTag(tagsOption)];
|
|
27963
|
+
}
|
|
27964
|
+
if (Array.isArray(tagsOption)) {
|
|
27965
|
+
return [...new Set(tagsOption.map(normalizeTag))];
|
|
27966
|
+
}
|
|
27967
|
+
const tag = resolvedPath.join("/");
|
|
27968
|
+
return tag ? [normalizeTag(tag)] : [];
|
|
27969
|
+
}
|
|
27970
|
+
function resolvePath(path2, params) {
|
|
27971
|
+
if (!params) return path2;
|
|
27972
|
+
return path2.map((segment) => {
|
|
27973
|
+
if (segment.startsWith(":")) {
|
|
27974
|
+
const paramName = segment.slice(1);
|
|
27975
|
+
const value = params[paramName];
|
|
27976
|
+
if (value === void 0) {
|
|
27977
|
+
throw new Error(`Missing path parameter: ${paramName}`);
|
|
27978
|
+
}
|
|
27979
|
+
return String(value);
|
|
27980
|
+
}
|
|
27981
|
+
return segment;
|
|
27982
|
+
});
|
|
27983
|
+
}
|
|
27984
|
+
function resolvePathString(path2, params) {
|
|
27985
|
+
if (!params) return path2;
|
|
27986
|
+
return path2.split("/").map((segment) => {
|
|
27987
|
+
if (segment.startsWith(":")) {
|
|
27988
|
+
const paramName = segment.slice(1);
|
|
27989
|
+
const value = params[paramName];
|
|
27990
|
+
return value !== void 0 ? String(value) : segment;
|
|
27991
|
+
}
|
|
27992
|
+
return segment;
|
|
27993
|
+
}).join("/");
|
|
27994
|
+
}
|
|
27995
|
+
var isAbortError = (err) => err instanceof DOMException && err.name === "AbortError";
|
|
27996
|
+
var fetchTransport = async (url, init) => {
|
|
27997
|
+
const res = await fetch(url, init);
|
|
27998
|
+
const contentType = res.headers.get("content-type");
|
|
27999
|
+
const isJson = contentType == null ? void 0 : contentType.includes("application/json");
|
|
28000
|
+
const isText = (contentType == null ? void 0 : contentType.includes("text/")) || (contentType == null ? void 0 : contentType.includes("application/xml"));
|
|
28001
|
+
let data;
|
|
28002
|
+
if (isJson) {
|
|
28003
|
+
data = await res.json();
|
|
28004
|
+
} else if (isText) {
|
|
28005
|
+
data = await res.text();
|
|
28006
|
+
} else {
|
|
28007
|
+
data = void 0;
|
|
28008
|
+
}
|
|
28009
|
+
return { ok: res.ok, status: res.status, headers: res.headers, data };
|
|
28010
|
+
};
|
|
28011
|
+
var xhrTransport = (url, init, options) => {
|
|
28012
|
+
return new Promise((resolve, reject) => {
|
|
28013
|
+
const xhr = new XMLHttpRequest();
|
|
28014
|
+
xhr.open(init.method ?? "GET", url);
|
|
28015
|
+
if (init.headers) {
|
|
28016
|
+
const headers = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
|
|
28017
|
+
headers.forEach((value, key) => {
|
|
28018
|
+
xhr.setRequestHeader(key, value);
|
|
28019
|
+
});
|
|
28020
|
+
}
|
|
28021
|
+
if (init.credentials === "include") {
|
|
28022
|
+
xhr.withCredentials = true;
|
|
28023
|
+
}
|
|
28024
|
+
const onAbort = () => xhr.abort();
|
|
28025
|
+
if (init.signal) {
|
|
28026
|
+
if (init.signal.aborted) {
|
|
28027
|
+
xhr.abort();
|
|
28028
|
+
return;
|
|
28029
|
+
}
|
|
28030
|
+
init.signal.addEventListener("abort", onAbort);
|
|
28031
|
+
}
|
|
28032
|
+
const cleanup = () => {
|
|
28033
|
+
var _a3;
|
|
28034
|
+
(_a3 = init.signal) == null ? void 0 : _a3.removeEventListener("abort", onAbort);
|
|
28035
|
+
};
|
|
28036
|
+
if (options == null ? void 0 : options.onProgress) {
|
|
28037
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
28038
|
+
options.onProgress(event, xhr);
|
|
28039
|
+
});
|
|
28040
|
+
xhr.addEventListener("progress", (event) => {
|
|
28041
|
+
options.onProgress(event, xhr);
|
|
28042
|
+
});
|
|
28043
|
+
}
|
|
28044
|
+
xhr.addEventListener("load", () => {
|
|
28045
|
+
cleanup();
|
|
28046
|
+
const status = xhr.status;
|
|
28047
|
+
const ok2 = status >= 200 && status < 300;
|
|
28048
|
+
const responseHeaders = new Headers();
|
|
28049
|
+
const rawHeaders = xhr.getAllResponseHeaders().trim();
|
|
28050
|
+
if (rawHeaders) {
|
|
28051
|
+
rawHeaders.split("\r\n").forEach((line) => {
|
|
28052
|
+
const idx = line.indexOf(": ");
|
|
28053
|
+
if (idx > 0) {
|
|
28054
|
+
responseHeaders.append(
|
|
28055
|
+
line.substring(0, idx),
|
|
28056
|
+
line.substring(idx + 2)
|
|
28057
|
+
);
|
|
28058
|
+
}
|
|
28059
|
+
});
|
|
28060
|
+
}
|
|
28061
|
+
const contentType = responseHeaders.get("content-type");
|
|
28062
|
+
const isJson = contentType == null ? void 0 : contentType.includes("application/json");
|
|
28063
|
+
let data;
|
|
28064
|
+
try {
|
|
28065
|
+
data = isJson ? JSON.parse(xhr.responseText) : xhr.responseText;
|
|
28066
|
+
} catch {
|
|
28067
|
+
data = xhr.responseText;
|
|
28068
|
+
}
|
|
28069
|
+
resolve({ ok: ok2, status, headers: responseHeaders, data });
|
|
28070
|
+
});
|
|
28071
|
+
xhr.addEventListener("error", () => {
|
|
28072
|
+
cleanup();
|
|
28073
|
+
reject(new TypeError("Network request failed"));
|
|
28074
|
+
});
|
|
28075
|
+
xhr.addEventListener("abort", () => {
|
|
28076
|
+
cleanup();
|
|
28077
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
28078
|
+
});
|
|
28079
|
+
xhr.send(init.body);
|
|
28080
|
+
});
|
|
28081
|
+
};
|
|
28082
|
+
async function executeFetch(baseUrl, path2, method, defaultOptions2, requestOptions, nextTags) {
|
|
28083
|
+
return executeCoreFetch({
|
|
28084
|
+
baseUrl,
|
|
28085
|
+
path: path2,
|
|
28086
|
+
method,
|
|
28087
|
+
defaultOptions: defaultOptions2,
|
|
28088
|
+
requestOptions,
|
|
28089
|
+
middlewareFetchInit: void 0,
|
|
28090
|
+
nextTags
|
|
28091
|
+
});
|
|
28092
|
+
}
|
|
28093
|
+
function buildInputFields(requestOptions) {
|
|
28094
|
+
const fields = {};
|
|
28095
|
+
if ((requestOptions == null ? void 0 : requestOptions.query) !== void 0) {
|
|
28096
|
+
fields.query = requestOptions.query;
|
|
28097
|
+
}
|
|
28098
|
+
if ((requestOptions == null ? void 0 : requestOptions.body) !== void 0) {
|
|
28099
|
+
fields.body = requestOptions.body;
|
|
28100
|
+
}
|
|
28101
|
+
if ((requestOptions == null ? void 0 : requestOptions.params) !== void 0) {
|
|
28102
|
+
fields.params = requestOptions.params;
|
|
28103
|
+
}
|
|
28104
|
+
if (Object.keys(fields).length === 0) {
|
|
28105
|
+
return {};
|
|
28106
|
+
}
|
|
28107
|
+
return { input: fields };
|
|
28108
|
+
}
|
|
28109
|
+
function resolveTransport(option) {
|
|
28110
|
+
if (option === "xhr" && typeof XMLHttpRequest !== "undefined") {
|
|
28111
|
+
return xhrTransport;
|
|
28112
|
+
}
|
|
28113
|
+
return fetchTransport;
|
|
28114
|
+
}
|
|
28115
|
+
async function executeCoreFetch(config2) {
|
|
28116
|
+
const {
|
|
28117
|
+
baseUrl,
|
|
28118
|
+
path: path2,
|
|
28119
|
+
method,
|
|
27555
28120
|
defaultOptions: defaultOptions2,
|
|
27556
28121
|
requestOptions,
|
|
27557
28122
|
middlewareFetchInit,
|
|
@@ -29595,19 +30160,19 @@ function resolveInvalidateTags(path2, params, invalidateOption, autoInvalidate,
|
|
|
29595
30160
|
return ["*"];
|
|
29596
30161
|
}
|
|
29597
30162
|
if (typeof invalidateOption === "string") {
|
|
29598
|
-
const normalized = normalizeTag
|
|
30163
|
+
const normalized = normalizeTag(invalidateOption);
|
|
29599
30164
|
if (normalized === "*") {
|
|
29600
30165
|
return ["*"];
|
|
29601
30166
|
}
|
|
29602
30167
|
return [normalized];
|
|
29603
30168
|
}
|
|
29604
30169
|
if (Array.isArray(invalidateOption)) {
|
|
29605
|
-
return [...new Set(invalidateOption.map(normalizeTag
|
|
30170
|
+
return [...new Set(invalidateOption.map(normalizeTag))];
|
|
29606
30171
|
}
|
|
29607
30172
|
if (!autoInvalidate) {
|
|
29608
30173
|
return false;
|
|
29609
30174
|
}
|
|
29610
|
-
const resolvedPath = normalizeTag
|
|
30175
|
+
const resolvedPath = normalizeTag(resolvePathString(path2, params));
|
|
29611
30176
|
const segments = resolvedPath.split("/");
|
|
29612
30177
|
const depth = calculateSegmentDepth(resolvedPath, groups);
|
|
29613
30178
|
const baseSegments = segments.slice(0, depth);
|
|
@@ -29669,7 +30234,7 @@ function invalidationPlugin(config2 = {}) {
|
|
|
29669
30234
|
eventEmitter.emit("refetchAll", void 0);
|
|
29670
30235
|
return;
|
|
29671
30236
|
}
|
|
29672
|
-
const patterns = rawPatterns.map(normalizeTag
|
|
30237
|
+
const patterns = rawPatterns.map(normalizeTag);
|
|
29673
30238
|
if (patterns.includes("*")) {
|
|
29674
30239
|
et == null ? void 0 : et.emit("Refetch all (manual)", { color: "warning" });
|
|
29675
30240
|
eventEmitter.emit("refetchAll", void 0);
|
|
@@ -31156,14 +31721,186 @@ function FolderPickerDialog({ initialPath, onSelect, onClose }) {
|
|
|
31156
31721
|
}
|
|
31157
31722
|
) });
|
|
31158
31723
|
}
|
|
31724
|
+
function AgentBinarySelect({
|
|
31725
|
+
value,
|
|
31726
|
+
onChange,
|
|
31727
|
+
floatingStrategy,
|
|
31728
|
+
menuClassName
|
|
31729
|
+
}) {
|
|
31730
|
+
const available = useRead((api) => api("agents/available").GET());
|
|
31731
|
+
const availableIds = new Set((available.data ?? []).map((a2) => a2.id));
|
|
31732
|
+
const isMissing = (id) => available.data != null && !availableIds.has(id);
|
|
31733
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
31734
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31735
|
+
Select_default,
|
|
31736
|
+
{
|
|
31737
|
+
value,
|
|
31738
|
+
floatingStrategy,
|
|
31739
|
+
menuClassName,
|
|
31740
|
+
onChange: (v2) => onChange(v2),
|
|
31741
|
+
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: [
|
|
31742
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: isMissing(o2.value) ? "text-[#8888a0]" : "", children: o2.label }),
|
|
31743
|
+
isMissing(o2.value) && /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { size: 11, className: "text-amber-500 ml-auto shrink-0" })
|
|
31744
|
+
] }) }, o2.value))
|
|
31745
|
+
}
|
|
31746
|
+
),
|
|
31747
|
+
isMissing(value) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 text-[10px] text-amber-400", children: [
|
|
31748
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { size: 11, className: "shrink-0" }),
|
|
31749
|
+
"Not installed — this agent won't run."
|
|
31750
|
+
] })
|
|
31751
|
+
] });
|
|
31752
|
+
}
|
|
31753
|
+
function ModelSelect({
|
|
31754
|
+
agentId,
|
|
31755
|
+
value,
|
|
31756
|
+
onChange,
|
|
31757
|
+
floatingStrategy,
|
|
31758
|
+
menuClassName
|
|
31759
|
+
}) {
|
|
31760
|
+
const staticOptions = MODEL_OPTIONS[agentId];
|
|
31761
|
+
const isDynamic = agentId === "opencode" || agentId === "cursor";
|
|
31762
|
+
const modelsRead = useRead(
|
|
31763
|
+
(api) => api("agents/models").GET({
|
|
31764
|
+
query: { agent: agentId === "cursor" ? "cursor" : "opencode" }
|
|
31765
|
+
}),
|
|
31766
|
+
{ enabled: isDynamic }
|
|
31767
|
+
);
|
|
31768
|
+
const dynamicModels = modelsRead.data ?? [];
|
|
31769
|
+
const isFetching = modelsRead.fetching;
|
|
31770
|
+
const options = isDynamic ? dynamicModels : staticOptions;
|
|
31771
|
+
const [customChosen, setCustomChosen] = reactExports.useState(false);
|
|
31772
|
+
const isPresetValue = value === "" || options.some((o2) => o2.value === value);
|
|
31773
|
+
const customMode = customChosen || !isPresetValue;
|
|
31774
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
31775
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
31776
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31777
|
+
Select_default,
|
|
31778
|
+
{
|
|
31779
|
+
floatingStrategy,
|
|
31780
|
+
menuClassName,
|
|
31781
|
+
value: customMode ? "__custom__" : value,
|
|
31782
|
+
onChange: (v2) => {
|
|
31783
|
+
if (v2 === "__custom__") {
|
|
31784
|
+
setCustomChosen(true);
|
|
31785
|
+
} else {
|
|
31786
|
+
setCustomChosen(false);
|
|
31787
|
+
onChange(v2);
|
|
31788
|
+
}
|
|
31789
|
+
},
|
|
31790
|
+
filterable: true,
|
|
31791
|
+
children: [
|
|
31792
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "", label: "Default" }),
|
|
31793
|
+
options.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value)),
|
|
31794
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "__custom__", label: "Custom..." })
|
|
31795
|
+
]
|
|
31796
|
+
}
|
|
31797
|
+
) }),
|
|
31798
|
+
isDynamic && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31799
|
+
"button",
|
|
31800
|
+
{
|
|
31801
|
+
type: "button",
|
|
31802
|
+
onClick: () => void modelsRead.trigger(),
|
|
31803
|
+
disabled: isFetching,
|
|
31804
|
+
title: "Refresh model list",
|
|
31805
|
+
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",
|
|
31806
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31807
|
+
"svg",
|
|
31808
|
+
{
|
|
31809
|
+
className: classNames("w-4 h-4", isFetching ? "animate-spin" : ""),
|
|
31810
|
+
fill: "none",
|
|
31811
|
+
viewBox: "0 0 24 24",
|
|
31812
|
+
stroke: "currentColor",
|
|
31813
|
+
strokeWidth: 2,
|
|
31814
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31815
|
+
"path",
|
|
31816
|
+
{
|
|
31817
|
+
strokeLinecap: "round",
|
|
31818
|
+
strokeLinejoin: "round",
|
|
31819
|
+
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"
|
|
31820
|
+
}
|
|
31821
|
+
)
|
|
31822
|
+
}
|
|
31823
|
+
)
|
|
31824
|
+
}
|
|
31825
|
+
)
|
|
31826
|
+
] }),
|
|
31827
|
+
customMode && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31828
|
+
Input_default,
|
|
31829
|
+
{
|
|
31830
|
+
value,
|
|
31831
|
+
onChange: (e) => onChange(e.target.value),
|
|
31832
|
+
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"
|
|
31833
|
+
}
|
|
31834
|
+
)
|
|
31835
|
+
] });
|
|
31836
|
+
}
|
|
31837
|
+
function AgentModelPicker({
|
|
31838
|
+
value,
|
|
31839
|
+
onChange,
|
|
31840
|
+
floatingStrategy,
|
|
31841
|
+
menuClassName
|
|
31842
|
+
}) {
|
|
31843
|
+
const agentId = value.agentId ?? "claude";
|
|
31844
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-start", children: [
|
|
31845
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full sm:w-32 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31846
|
+
AgentBinarySelect,
|
|
31847
|
+
{
|
|
31848
|
+
value: agentId,
|
|
31849
|
+
floatingStrategy,
|
|
31850
|
+
menuClassName,
|
|
31851
|
+
onChange: (v2) => onChange({ ...value, agentId: v2, model: null })
|
|
31852
|
+
}
|
|
31853
|
+
) }),
|
|
31854
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31855
|
+
ModelSelect,
|
|
31856
|
+
{
|
|
31857
|
+
agentId,
|
|
31858
|
+
value: value.model ?? "",
|
|
31859
|
+
onChange: (v2) => onChange({ ...value, model: v2 || null }),
|
|
31860
|
+
floatingStrategy,
|
|
31861
|
+
menuClassName
|
|
31862
|
+
}
|
|
31863
|
+
) }),
|
|
31864
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full sm:w-36 shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31865
|
+
Select_default,
|
|
31866
|
+
{
|
|
31867
|
+
value: value.effort ?? "",
|
|
31868
|
+
floatingStrategy,
|
|
31869
|
+
menuClassName,
|
|
31870
|
+
onChange: (v2) => onChange({ ...value, effort: v2 || null }),
|
|
31871
|
+
children: [
|
|
31872
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: "", label: "Default effort" }),
|
|
31873
|
+
EFFORT_OPTIONS.map((o2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: o2.value, label: o2.label }, o2.value))
|
|
31874
|
+
]
|
|
31875
|
+
}
|
|
31876
|
+
) })
|
|
31877
|
+
] });
|
|
31878
|
+
}
|
|
31879
|
+
function BranchSelect({ branches, value, onChange, placeholder = "Select branch" }) {
|
|
31880
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31881
|
+
Select_default,
|
|
31882
|
+
{
|
|
31883
|
+
value,
|
|
31884
|
+
onChange: (v2) => onChange(v2),
|
|
31885
|
+
placeholder,
|
|
31886
|
+
filterable: true,
|
|
31887
|
+
prefix: /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { size: 13, className: "text-[#8888a0]" }),
|
|
31888
|
+
children: branches.map((b2) => /* @__PURE__ */ jsxRuntimeExports.jsx(SelectOption_default, { value: b2, label: b2 }, b2))
|
|
31889
|
+
}
|
|
31890
|
+
);
|
|
31891
|
+
}
|
|
31159
31892
|
function ConfigureStep({
|
|
31160
31893
|
repoPath,
|
|
31894
|
+
branches,
|
|
31161
31895
|
adding,
|
|
31162
31896
|
onBack,
|
|
31163
31897
|
onAdd
|
|
31164
31898
|
}) {
|
|
31899
|
+
const { setValue } = useFormContext();
|
|
31165
31900
|
const folderName = repoPath.split("/").filter(Boolean).at(-1) ?? repoPath;
|
|
31166
31901
|
const deliveryMode = useWatch({ name: "deliveryMode" });
|
|
31902
|
+
const defaultBaseBranch = useWatch({ name: "defaultBaseBranch" }) ?? "";
|
|
31903
|
+
const assistantModel = useWatch({ name: "assistantModel" }) ?? DEFAULT_AGENT_MODEL_CHOICE;
|
|
31167
31904
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
|
|
31168
31905
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-6 flex flex-col gap-5", children: [
|
|
31169
31906
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
@@ -31194,12 +31931,36 @@ function ConfigureStep({
|
|
|
31194
31931
|
] })
|
|
31195
31932
|
] })
|
|
31196
31933
|
] }),
|
|
31934
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3.5", children: [
|
|
31935
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-medium uppercase text-[#4a4a5a] tracking-[1px]", children: "Git defaults" }),
|
|
31936
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
31937
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31938
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#c0c0d0]", children: "Default base branch" }),
|
|
31939
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-0.5 text-[#4a4a5a]", children: "Used when creating new tasks and stories." })
|
|
31940
|
+
] }),
|
|
31941
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-40", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31942
|
+
BranchSelect,
|
|
31943
|
+
{
|
|
31944
|
+
branches,
|
|
31945
|
+
value: defaultBaseBranch,
|
|
31946
|
+
onChange: (v2) => setValue("defaultBaseBranch", v2 || void 0, { shouldDirty: true }),
|
|
31947
|
+
placeholder: "main"
|
|
31948
|
+
}
|
|
31949
|
+
) })
|
|
31950
|
+
] })
|
|
31951
|
+
] }),
|
|
31197
31952
|
/* @__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("
|
|
31953
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-medium uppercase text-[#4a4a5a] tracking-[1px]", children: "Assistant" }),
|
|
31954
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
31955
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] text-[#c0c0d0]", children: "Agent & model" }),
|
|
31956
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-[#4a4a5a]", children: "Which agent runs the in-app assistant." }),
|
|
31957
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31958
|
+
AgentModelPicker,
|
|
31959
|
+
{
|
|
31960
|
+
value: assistantModel,
|
|
31961
|
+
onChange: (next2) => setValue("assistantModel", next2, { shouldDirty: true })
|
|
31962
|
+
}
|
|
31963
|
+
) })
|
|
31203
31964
|
] })
|
|
31204
31965
|
] })
|
|
31205
31966
|
] }),
|
|
@@ -31341,7 +32102,8 @@ function AddProjectDialog({ onClose, onAdded }) {
|
|
|
31341
32102
|
values: {
|
|
31342
32103
|
repoPath: "",
|
|
31343
32104
|
deliveryMode: "off",
|
|
31344
|
-
|
|
32105
|
+
defaultBaseBranch: void 0,
|
|
32106
|
+
assistantModel: DEFAULT_AGENT_MODEL_CHOICE
|
|
31345
32107
|
}
|
|
31346
32108
|
});
|
|
31347
32109
|
const { control, getValues, setValue } = methods;
|
|
@@ -31364,12 +32126,19 @@ function AddProjectDialog({ onClose, onAdded }) {
|
|
|
31364
32126
|
const pathStatus = !trimmed ? "idle" : trimmed !== debouncedPath || checking ? "checking" : checkError ? "invalid" : pathData ? pathData.valid ? "valid" : "invalid" : "checking";
|
|
31365
32127
|
const pathError = checkError ? "Failed to check path" : pathStatus === "invalid" ? (pathData == null ? void 0 : pathData.error) ?? null : null;
|
|
31366
32128
|
const repoInfo = pathStatus === "valid" && pathData ? { name: pathData.name, branch: pathData.branch, remote: pathData.remote } : { name: null, branch: null, remote: null };
|
|
32129
|
+
const currentBranch = repoInfo.branch;
|
|
32130
|
+
reactExports.useEffect(() => {
|
|
32131
|
+
if (currentBranch && !getValues("defaultBaseBranch")) {
|
|
32132
|
+
setValue("defaultBaseBranch", currentBranch);
|
|
32133
|
+
}
|
|
32134
|
+
}, [currentBranch, getValues, setValue]);
|
|
31367
32135
|
const addProjectWrite = useWrite((api) => api("projects").POST());
|
|
31368
32136
|
const handleAdd = methods.handleSubmit(async (values) => {
|
|
31369
32137
|
var _a3, _b2;
|
|
31370
32138
|
const initialConfig = {
|
|
31371
32139
|
deliveryMode: values.deliveryMode,
|
|
31372
|
-
|
|
32140
|
+
defaultBaseBranch: ((_a3 = values.defaultBaseBranch) == null ? void 0 : _a3.trim()) || void 0,
|
|
32141
|
+
assistantModel: values.assistantModel
|
|
31373
32142
|
};
|
|
31374
32143
|
const res = await addProjectWrite.trigger({
|
|
31375
32144
|
body: { repoPath: values.repoPath.trim(), initialConfig }
|
|
@@ -31471,6 +32240,7 @@ function AddProjectDialog({ onClose, onAdded }) {
|
|
|
31471
32240
|
ConfigureStep,
|
|
31472
32241
|
{
|
|
31473
32242
|
repoPath: getValues("repoPath"),
|
|
32243
|
+
branches: (pathData == null ? void 0 : pathData.branches) ?? [],
|
|
31474
32244
|
adding: addProjectWrite.loading,
|
|
31475
32245
|
onBack: () => setStep("select"),
|
|
31476
32246
|
onAdd: () => void handleAdd()
|
|
@@ -48654,195 +49424,34 @@ const ConnectedDroppable = connect_default(makeMapStateToProps, mapDispatchToPro
|
|
|
48654
49424
|
return {
|
|
48655
49425
|
...attachDefaultPropsToOwnProps(ownProps),
|
|
48656
49426
|
...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 };
|
|
49427
|
+
...dispatchProps
|
|
49428
|
+
};
|
|
49429
|
+
}, {
|
|
49430
|
+
context: StoreContext,
|
|
49431
|
+
areStatePropsEqual: isStrictEqual
|
|
49432
|
+
})(Droppable);
|
|
49433
|
+
function EmptyFolderSlot({ dp }) {
|
|
49434
|
+
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: [
|
|
49435
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-1 h-1 rounded-full bg-[#2a2a35]" }),
|
|
49436
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-[#3a3a45]", children: "Drop project here" })
|
|
49437
|
+
] }) });
|
|
48836
49438
|
}
|
|
48837
|
-
function
|
|
48838
|
-
|
|
48839
|
-
|
|
49439
|
+
function FolderHeader({
|
|
49440
|
+
folderId,
|
|
49441
|
+
folder,
|
|
48840
49442
|
dp,
|
|
48841
49443
|
snap,
|
|
48842
|
-
|
|
48843
|
-
|
|
48844
|
-
|
|
48845
|
-
|
|
49444
|
+
expanded,
|
|
49445
|
+
hovered,
|
|
49446
|
+
editing,
|
|
49447
|
+
editName,
|
|
49448
|
+
editRef,
|
|
49449
|
+
onToggleCollapse,
|
|
49450
|
+
onStartRename,
|
|
49451
|
+
onDeleteFolder,
|
|
49452
|
+
onEditNameChange,
|
|
49453
|
+
onCommitRename,
|
|
49454
|
+
onCancelRename
|
|
48846
49455
|
}) {
|
|
48847
49456
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
48848
49457
|
"div",
|
|
@@ -48850,916 +49459,514 @@ function ProjectItem({
|
|
|
48850
49459
|
ref: dp.innerRef,
|
|
48851
49460
|
...dp.draggableProps,
|
|
48852
49461
|
...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
|
-
),
|
|
49462
|
+
onClick: () => onToggleCollapse(folderId),
|
|
49463
|
+
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
49464
|
style: {
|
|
48860
49465
|
...dp.draggableProps.style,
|
|
48861
|
-
background:
|
|
48862
|
-
borderLeft: isActive2 && !snap.isDragging ? "2px solid #7c6aff" : "2px solid transparent"
|
|
49466
|
+
background: snap.isDragging ? "#1f1f28" : hovered ? "#7c6aff15" : "transparent"
|
|
48863
49467
|
},
|
|
48864
49468
|
children: [
|
|
48865
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48866
|
-
|
|
49469
|
+
/* @__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 }) }),
|
|
49470
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Folder, { size: 13, className: classNames("shrink-0", hovered ? "text-[#7c6aff]" : "text-[#60607a]") }),
|
|
49471
|
+
editing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49472
|
+
"input",
|
|
48867
49473
|
{
|
|
48868
|
-
|
|
48869
|
-
|
|
49474
|
+
ref: editRef,
|
|
49475
|
+
value: editName,
|
|
49476
|
+
onChange: (e) => onEditNameChange(e.target.value),
|
|
49477
|
+
onBlur: onCommitRename,
|
|
49478
|
+
onClick: (e) => e.stopPropagation(),
|
|
49479
|
+
onKeyDown: (e) => {
|
|
49480
|
+
if (e.key === "Enter") onCommitRename();
|
|
49481
|
+
if (e.key === "Escape") onCancelRename();
|
|
49482
|
+
},
|
|
49483
|
+
className: "flex-1 min-w-0 outline-none text-[11px] rounded px-1 bg-[#0c0c0f] border border-[#3a3a55] text-[#f0f0f5]"
|
|
48870
49484
|
}
|
|
48871
|
-
)
|
|
48872
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49485
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
48873
49486
|
"span",
|
|
48874
49487
|
{
|
|
48875
49488
|
className: classNames(
|
|
48876
|
-
"flex-1 min-w-0 truncate text-[
|
|
48877
|
-
|
|
49489
|
+
"flex-1 min-w-0 truncate text-[11px] font-medium tracking-[0.2px]",
|
|
49490
|
+
hovered ? "text-[#c0c0d0]" : "text-[#8888a0]"
|
|
48878
49491
|
),
|
|
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) => {
|
|
49492
|
+
onDoubleClick: (e) => {
|
|
48886
49493
|
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
|
-
});
|
|
49494
|
+
onStartRename(folderId);
|
|
48897
49495
|
},
|
|
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 })
|
|
49496
|
+
children: folder.name
|
|
49145
49497
|
}
|
|
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(
|
|
49498
|
+
),
|
|
49499
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity", children: [
|
|
49500
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49158
49501
|
"button",
|
|
49159
49502
|
{
|
|
49160
|
-
onClick:
|
|
49161
|
-
|
|
49162
|
-
|
|
49163
|
-
|
|
49503
|
+
onClick: (e) => {
|
|
49504
|
+
e.stopPropagation();
|
|
49505
|
+
onStartRename(folderId);
|
|
49506
|
+
},
|
|
49507
|
+
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#2a2a35] transition-colors text-[#60607a]",
|
|
49508
|
+
title: "Rename",
|
|
49509
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Pencil, { size: 10 })
|
|
49510
|
+
}
|
|
49511
|
+
),
|
|
49512
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49513
|
+
"button",
|
|
49514
|
+
{
|
|
49515
|
+
onClick: (e) => {
|
|
49516
|
+
e.stopPropagation();
|
|
49517
|
+
onDeleteFolder(folderId);
|
|
49518
|
+
},
|
|
49519
|
+
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#ef444420] transition-colors text-[#60607a]",
|
|
49520
|
+
title: "Delete",
|
|
49521
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
|
|
49164
49522
|
}
|
|
49165
49523
|
)
|
|
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
|
-
] });
|
|
49524
|
+
] })
|
|
49525
|
+
]
|
|
49526
|
+
}
|
|
49527
|
+
);
|
|
49199
49528
|
}
|
|
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];
|
|
49529
|
+
function genId() {
|
|
49530
|
+
return Math.random().toString(36).slice(2, 10);
|
|
49531
|
+
}
|
|
49532
|
+
function buildFlat(layout, expandAll, isDragging2 = false) {
|
|
49533
|
+
var _a3, _b2;
|
|
49534
|
+
const flat = [];
|
|
49535
|
+
for (const item of layout.topLevel) {
|
|
49536
|
+
if (item.type === "folder") {
|
|
49537
|
+
flat.push({ kind: "folder-header", folderId: item.id });
|
|
49538
|
+
const expanded = expandAll || !((_a3 = layout.folders[item.id]) == null ? void 0 : _a3.collapsed);
|
|
49539
|
+
if (expanded) {
|
|
49540
|
+
const projectIds = ((_b2 = layout.folders[item.id]) == null ? void 0 : _b2.projectIds) ?? [];
|
|
49541
|
+
for (const wsId of projectIds) {
|
|
49542
|
+
flat.push({ kind: "project", workspaceId: wsId, folderId: item.id });
|
|
49543
|
+
}
|
|
49544
|
+
if (isDragging2 && projectIds.length === 0) {
|
|
49545
|
+
flat.push({ kind: "empty-folder-slot", folderId: item.id });
|
|
49546
|
+
}
|
|
49547
|
+
}
|
|
49548
|
+
} else {
|
|
49549
|
+
flat.push({ kind: "project", workspaceId: item.workspaceId, folderId: null });
|
|
49550
|
+
}
|
|
49287
49551
|
}
|
|
49552
|
+
return flat;
|
|
49288
49553
|
}
|
|
49289
|
-
function
|
|
49290
|
-
|
|
49291
|
-
|
|
49292
|
-
|
|
49293
|
-
|
|
49294
|
-
|
|
49295
|
-
const
|
|
49296
|
-
for (
|
|
49297
|
-
|
|
49298
|
-
|
|
49299
|
-
|
|
49300
|
-
|
|
49301
|
-
|
|
49302
|
-
|
|
49554
|
+
function flatToLayout(flat, existing) {
|
|
49555
|
+
var _a3;
|
|
49556
|
+
const topLevel = [];
|
|
49557
|
+
const folders = Object.fromEntries(
|
|
49558
|
+
Object.entries(existing.folders).map(([k, v2]) => [k, { ...v2, projectIds: [] }])
|
|
49559
|
+
);
|
|
49560
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
49561
|
+
for (const item of flat) {
|
|
49562
|
+
if (item.kind === "empty-folder-slot") continue;
|
|
49563
|
+
if (item.kind === "folder-header") {
|
|
49564
|
+
if (!seen2.has(item.folderId)) {
|
|
49565
|
+
seen2.add(item.folderId);
|
|
49566
|
+
topLevel.push({ type: "folder", id: item.folderId });
|
|
49567
|
+
}
|
|
49568
|
+
} else if (item.folderId !== null) {
|
|
49569
|
+
(_a3 = folders[item.folderId]) == null ? void 0 : _a3.projectIds.push(item.workspaceId);
|
|
49570
|
+
} else {
|
|
49571
|
+
topLevel.push({ type: "project", workspaceId: item.workspaceId });
|
|
49572
|
+
}
|
|
49303
49573
|
}
|
|
49304
|
-
|
|
49305
|
-
|
|
49306
|
-
|
|
49574
|
+
return { ...existing, topLevel, folders };
|
|
49575
|
+
}
|
|
49576
|
+
function folderAtDest(flat, destIndex) {
|
|
49577
|
+
const after = flat[destIndex];
|
|
49578
|
+
if (!after) {
|
|
49579
|
+
const prev = flat[destIndex - 1];
|
|
49580
|
+
if (!prev || prev.kind === "folder-header") return null;
|
|
49581
|
+
if (prev.kind === "empty-folder-slot") return prev.folderId;
|
|
49582
|
+
return prev.folderId;
|
|
49307
49583
|
}
|
|
49308
|
-
|
|
49309
|
-
if (
|
|
49310
|
-
return
|
|
49584
|
+
if (after.kind === "folder-header") return after.folderId;
|
|
49585
|
+
if (after.kind === "empty-folder-slot") return after.folderId;
|
|
49586
|
+
return after.folderId;
|
|
49311
49587
|
}
|
|
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));
|
|
49588
|
+
function syncLayout(layout, projects) {
|
|
49589
|
+
const known = new Set(projects.map((p) => p.workspaceId));
|
|
49590
|
+
const topLevel = layout.topLevel.filter((i2) => i2.type === "folder" || known.has(i2.workspaceId));
|
|
49591
|
+
const folders = Object.fromEntries(
|
|
49592
|
+
Object.entries(layout.folders).map(([id, f]) => [
|
|
49593
|
+
id,
|
|
49594
|
+
{ ...f, projectIds: f.projectIds.filter((id2) => known.has(id2)) }
|
|
49595
|
+
])
|
|
49596
|
+
);
|
|
49597
|
+
const inLayout = /* @__PURE__ */ new Set();
|
|
49598
|
+
for (const i2 of topLevel) {
|
|
49599
|
+
if (i2.type === "project") inLayout.add(i2.workspaceId);
|
|
49352
49600
|
}
|
|
49353
|
-
|
|
49601
|
+
for (const f of Object.values(folders)) {
|
|
49602
|
+
for (const id of f.projectIds) inLayout.add(id);
|
|
49603
|
+
}
|
|
49604
|
+
const newItems = projects.filter((p) => !inLayout.has(p.workspaceId)).map((p) => ({ type: "project", workspaceId: p.workspaceId }));
|
|
49605
|
+
return { ...layout, topLevel: [...topLevel, ...newItems], folders };
|
|
49354
49606
|
}
|
|
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, "");
|
|
49607
|
+
function ProjectItem({
|
|
49608
|
+
project,
|
|
49609
|
+
workspaceId,
|
|
49610
|
+
dp,
|
|
49611
|
+
snap,
|
|
49612
|
+
isActive: isActive2,
|
|
49613
|
+
indent: indent2,
|
|
49614
|
+
onSwitch,
|
|
49615
|
+
onRemove
|
|
49616
|
+
}) {
|
|
49617
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
49618
|
+
"div",
|
|
49619
|
+
{
|
|
49620
|
+
ref: dp.innerRef,
|
|
49621
|
+
...dp.draggableProps,
|
|
49622
|
+
...dp.dragHandleProps,
|
|
49623
|
+
onClick: () => onSwitch(workspaceId),
|
|
49624
|
+
className: classNames(
|
|
49625
|
+
"group flex items-center gap-2 h-8 pr-2 my-px mx-1 rounded-md cursor-pointer select-none transition-colors",
|
|
49626
|
+
indent2 ? "pl-10" : "pl-3",
|
|
49627
|
+
snap.isDragging ? "opacity-70" : isActive2 ? "" : "hover:bg-[#1a1a1f]"
|
|
49628
|
+
),
|
|
49629
|
+
style: {
|
|
49630
|
+
...dp.draggableProps.style,
|
|
49631
|
+
background: isActive2 && !snap.isDragging ? "#7c6aff18" : "transparent",
|
|
49632
|
+
borderLeft: isActive2 && !snap.isDragging ? "2px solid #7c6aff" : "2px solid transparent"
|
|
49633
|
+
},
|
|
49634
|
+
children: [
|
|
49635
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49636
|
+
"div",
|
|
49637
|
+
{
|
|
49638
|
+
className: classNames("w-1.5 h-1.5 rounded-full shrink-0", isActive2 ? "bg-[#7c6aff]" : "bg-[#2a2a35]"),
|
|
49639
|
+
style: isActive2 ? { boxShadow: "0 0 6px #7c6aff80" } : void 0
|
|
49640
|
+
}
|
|
49641
|
+
),
|
|
49642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49643
|
+
"span",
|
|
49644
|
+
{
|
|
49645
|
+
className: classNames(
|
|
49646
|
+
"flex-1 min-w-0 truncate text-[12px]",
|
|
49647
|
+
isActive2 ? "text-[#f0f0f5] font-medium" : "text-[#8888a0] font-normal"
|
|
49648
|
+
),
|
|
49649
|
+
children: project.name
|
|
49650
|
+
}
|
|
49651
|
+
),
|
|
49652
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49653
|
+
"button",
|
|
49654
|
+
{
|
|
49655
|
+
onClick: (e) => {
|
|
49656
|
+
e.stopPropagation();
|
|
49657
|
+
ConfirmDialog_default.show({
|
|
49658
|
+
title: "Remove project",
|
|
49659
|
+
content: `Remove "${project.name}" from Whipped? This will stop all running agents and delete all associated worktrees and data.`,
|
|
49660
|
+
confirmButtonLabel: "Remove",
|
|
49661
|
+
cancelButtonLabel: "Cancel",
|
|
49662
|
+
onConfirm: async ({ dismiss: dismiss2 }) => {
|
|
49663
|
+
await onRemove(workspaceId);
|
|
49664
|
+
dismiss2();
|
|
49665
|
+
}
|
|
49666
|
+
});
|
|
49667
|
+
},
|
|
49668
|
+
className: "flex items-center justify-center w-5 h-5 rounded hover:bg-[#ef444420] transition-colors text-[#60607a] hover:text-[#ef4444]",
|
|
49669
|
+
title: "Remove project",
|
|
49670
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 10 })
|
|
49671
|
+
}
|
|
49672
|
+
) })
|
|
49673
|
+
]
|
|
49674
|
+
}
|
|
49675
|
+
);
|
|
49694
49676
|
}
|
|
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
|
-
|
|
49677
|
+
const ProjectsSidebar = React.forwardRef(function ProjectsSidebar2({ projects, activeWorkspaceId, onSwitch, onRemove }, ref) {
|
|
49678
|
+
const [layout, setLayout] = reactExports.useState({ version: 1, topLevel: [], folders: {} });
|
|
49679
|
+
const [isDragging2, setIsDragging] = reactExports.useState(false);
|
|
49680
|
+
const [hoveredFolderId, setHoveredFolderId] = reactExports.useState(null);
|
|
49681
|
+
const [editingId, setEditingId] = reactExports.useState(null);
|
|
49682
|
+
const [editName, setEditName] = reactExports.useState("");
|
|
49683
|
+
const editRef = reactExports.useRef(null);
|
|
49684
|
+
const saveTimer = reactExports.useRef(null);
|
|
49685
|
+
const { trigger: fetchLayout } = useRead((api) => api("projects/layout").GET(), { enabled: false });
|
|
49686
|
+
const { trigger: saveLayout } = useWrite((api) => api("projects/layout").PUT());
|
|
49687
|
+
reactExports.useEffect(() => {
|
|
49688
|
+
fetchLayout().then((res) => setLayout((prev) => syncLayout(res.data ?? prev, projects))).catch(() => {
|
|
49689
|
+
});
|
|
49690
|
+
}, []);
|
|
49691
|
+
reactExports.useEffect(() => {
|
|
49692
|
+
setLayout((prev) => syncLayout(prev, projects));
|
|
49693
|
+
}, [projects]);
|
|
49694
|
+
const persist = (next2) => {
|
|
49695
|
+
if (saveTimer.current) clearTimeout(saveTimer.current);
|
|
49696
|
+
saveTimer.current = setTimeout(() => {
|
|
49697
|
+
saveLayout({ body: next2 }).catch(() => {
|
|
49698
|
+
});
|
|
49699
|
+
}, 300);
|
|
49700
|
+
};
|
|
49701
|
+
const update2 = (next2) => {
|
|
49702
|
+
setLayout(next2);
|
|
49703
|
+
persist(next2);
|
|
49704
|
+
};
|
|
49705
|
+
const addFolder = () => {
|
|
49706
|
+
const id = genId();
|
|
49707
|
+
const next2 = {
|
|
49708
|
+
...layout,
|
|
49709
|
+
topLevel: [...layout.topLevel, { type: "folder", id }],
|
|
49710
|
+
folders: { ...layout.folders, [id]: { id, name: "New Folder", collapsed: false, projectIds: [] } }
|
|
49711
|
+
};
|
|
49712
|
+
update2(next2);
|
|
49713
|
+
setEditingId(id);
|
|
49714
|
+
setEditName("New Folder");
|
|
49715
|
+
setTimeout(() => {
|
|
49716
|
+
var _a3, _b2;
|
|
49717
|
+
(_a3 = editRef.current) == null ? void 0 : _a3.focus();
|
|
49718
|
+
(_b2 = editRef.current) == null ? void 0 : _b2.select();
|
|
49719
|
+
}, 50);
|
|
49720
|
+
};
|
|
49721
|
+
reactExports.useImperativeHandle(ref, () => ({ addFolder }));
|
|
49722
|
+
const startRename = (id) => {
|
|
49723
|
+
var _a3;
|
|
49724
|
+
setEditingId(id);
|
|
49725
|
+
setEditName(((_a3 = layout.folders[id]) == null ? void 0 : _a3.name) ?? "");
|
|
49726
|
+
setTimeout(() => {
|
|
49727
|
+
var _a4, _b2;
|
|
49728
|
+
(_a4 = editRef.current) == null ? void 0 : _a4.focus();
|
|
49729
|
+
(_b2 = editRef.current) == null ? void 0 : _b2.select();
|
|
49730
|
+
}, 50);
|
|
49731
|
+
};
|
|
49732
|
+
const commitRename = () => {
|
|
49733
|
+
if (!editingId) return;
|
|
49734
|
+
update2({
|
|
49735
|
+
...layout,
|
|
49736
|
+
folders: {
|
|
49737
|
+
...layout.folders,
|
|
49738
|
+
[editingId]: { ...layout.folders[editingId], name: editName.trim() || "Untitled" }
|
|
49739
|
+
}
|
|
49740
|
+
});
|
|
49741
|
+
setEditingId(null);
|
|
49742
|
+
};
|
|
49743
|
+
const deleteFolder = (id) => {
|
|
49744
|
+
const folder = layout.folders[id];
|
|
49745
|
+
if (!folder) return;
|
|
49746
|
+
const idx = layout.topLevel.findIndex((i2) => i2.type === "folder" && i2.id === id);
|
|
49747
|
+
const returned = folder.projectIds.map((ws2) => ({ type: "project", workspaceId: ws2 }));
|
|
49748
|
+
const topLevel = [...layout.topLevel];
|
|
49749
|
+
topLevel.splice(idx, 1, ...returned);
|
|
49750
|
+
const folders = { ...layout.folders };
|
|
49751
|
+
delete folders[id];
|
|
49752
|
+
update2({ ...layout, topLevel, folders });
|
|
49753
|
+
};
|
|
49754
|
+
const toggleCollapse = (id) => {
|
|
49755
|
+
const f = layout.folders[id];
|
|
49756
|
+
if (!f) return;
|
|
49757
|
+
update2({ ...layout, folders: { ...layout.folders, [id]: { ...f, collapsed: !f.collapsed } } });
|
|
49758
|
+
};
|
|
49759
|
+
const onDragUpdate2 = reactExports.useCallback(
|
|
49760
|
+
(update22) => {
|
|
49761
|
+
if (!update22.destination) {
|
|
49762
|
+
setHoveredFolderId(null);
|
|
49763
|
+
return;
|
|
49764
|
+
}
|
|
49765
|
+
const flat2 = buildFlat(layout, true, true);
|
|
49766
|
+
flat2.splice(update22.source.index, 1);
|
|
49767
|
+
const folderId = folderAtDest(flat2, update22.destination.index);
|
|
49768
|
+
setHoveredFolderId(folderId);
|
|
49769
|
+
},
|
|
49770
|
+
[layout]
|
|
49771
|
+
);
|
|
49772
|
+
const onDragEnd2 = (result) => {
|
|
49773
|
+
setIsDragging(false);
|
|
49774
|
+
setHoveredFolderId(null);
|
|
49775
|
+
if (!result.destination) return;
|
|
49776
|
+
const { draggableId, source, destination } = result;
|
|
49777
|
+
if (source.index === destination.index) return;
|
|
49778
|
+
const flat2 = buildFlat(layout, true, true);
|
|
49779
|
+
if (draggableId.startsWith("fh:")) {
|
|
49780
|
+
const folderId = draggableId.slice(3);
|
|
49781
|
+
flat2.splice(source.index, 1);
|
|
49782
|
+
const group = [];
|
|
49783
|
+
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)) {
|
|
49784
|
+
group.push(flat2.splice(source.index, 1)[0]);
|
|
49785
|
+
}
|
|
49786
|
+
const at2 = Math.min(destination.index, flat2.length);
|
|
49787
|
+
flat2.splice(at2, 0, { kind: "folder-header", folderId }, ...group);
|
|
49788
|
+
} else {
|
|
49789
|
+
const [moved] = flat2.splice(source.index, 1);
|
|
49790
|
+
const newFolderId = folderAtDest(flat2, destination.index);
|
|
49791
|
+
flat2.splice(destination.index, 0, { ...moved, folderId: newFolderId });
|
|
49792
|
+
}
|
|
49793
|
+
update2(flatToLayout(flat2, layout));
|
|
49794
|
+
};
|
|
49795
|
+
const projectMap = Object.fromEntries(projects.map((p) => [p.workspaceId, p]));
|
|
49796
|
+
const flat = buildFlat(layout, isDragging2, isDragging2);
|
|
49797
|
+
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: [
|
|
49798
|
+
flat.map((item, index2) => {
|
|
49799
|
+
if (item.kind === "folder-header") {
|
|
49800
|
+
const folder = layout.folders[item.folderId];
|
|
49801
|
+
if (!folder) return null;
|
|
49802
|
+
const expanded = !folder.collapsed || isDragging2;
|
|
49803
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(PublicDraggable, { draggableId: `fh:${item.folderId}`, index: index2, children: (dp, snap) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49804
|
+
FolderHeader,
|
|
49805
|
+
{
|
|
49806
|
+
folderId: item.folderId,
|
|
49807
|
+
folder,
|
|
49808
|
+
dp,
|
|
49809
|
+
snap,
|
|
49810
|
+
expanded,
|
|
49811
|
+
hovered: hoveredFolderId === item.folderId,
|
|
49812
|
+
editing: editingId === item.folderId,
|
|
49813
|
+
editName,
|
|
49814
|
+
editRef,
|
|
49815
|
+
onToggleCollapse: toggleCollapse,
|
|
49816
|
+
onStartRename: startRename,
|
|
49817
|
+
onDeleteFolder: deleteFolder,
|
|
49818
|
+
onEditNameChange: setEditName,
|
|
49819
|
+
onCommitRename: commitRename,
|
|
49820
|
+
onCancelRename: () => setEditingId(null)
|
|
49821
|
+
}
|
|
49822
|
+
) }, `fh:${item.folderId}`);
|
|
49823
|
+
}
|
|
49824
|
+
if (item.kind === "empty-folder-slot") {
|
|
49825
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49826
|
+
PublicDraggable,
|
|
49827
|
+
{
|
|
49828
|
+
draggableId: `slot:${item.folderId}`,
|
|
49829
|
+
index: index2,
|
|
49830
|
+
isDragDisabled: true,
|
|
49831
|
+
children: (dp) => /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyFolderSlot, { dp })
|
|
49832
|
+
},
|
|
49833
|
+
`slot:${item.folderId}`
|
|
49834
|
+
);
|
|
49835
|
+
}
|
|
49836
|
+
const project = projectMap[item.workspaceId];
|
|
49837
|
+
if (!project) return null;
|
|
49838
|
+
const isActive2 = item.workspaceId === activeWorkspaceId;
|
|
49839
|
+
const indent2 = item.folderId !== null;
|
|
49840
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(PublicDraggable, { draggableId: `p:${item.workspaceId}`, index: index2, children: (dp, snap) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49841
|
+
ProjectItem,
|
|
49842
|
+
{
|
|
49843
|
+
project,
|
|
49844
|
+
workspaceId: item.workspaceId,
|
|
49845
|
+
dp,
|
|
49846
|
+
snap,
|
|
49847
|
+
isActive: isActive2,
|
|
49848
|
+
indent: indent2,
|
|
49849
|
+
onSwitch,
|
|
49850
|
+
onRemove
|
|
49851
|
+
}
|
|
49852
|
+
) }, `p:${item.workspaceId}`);
|
|
49853
|
+
}),
|
|
49854
|
+
provided.placeholder
|
|
49855
|
+
] }) }) });
|
|
49762
49856
|
});
|
|
49857
|
+
function CardDetailHeader({
|
|
49858
|
+
card,
|
|
49859
|
+
workspaceId,
|
|
49860
|
+
projectName,
|
|
49861
|
+
externalUrl,
|
|
49862
|
+
isStory,
|
|
49863
|
+
isReadyForReview,
|
|
49864
|
+
hasStartCommand = false,
|
|
49865
|
+
merging,
|
|
49866
|
+
onMerge,
|
|
49867
|
+
onPR,
|
|
49868
|
+
onDelete,
|
|
49869
|
+
onClose
|
|
49870
|
+
}) {
|
|
49871
|
+
var _a3, _b2, _c3;
|
|
49872
|
+
const { session: runSession, start: startRun, stop: stopRun } = useRunSession(workspaceId);
|
|
49873
|
+
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: [
|
|
49874
|
+
/* @__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 }) }),
|
|
49875
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49876
|
+
projectName && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
49877
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-[#60607a]", children: projectName }),
|
|
49878
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-[#2a2a35]", children: "/" })
|
|
49879
|
+
] }),
|
|
49880
|
+
/* @__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 }),
|
|
49881
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
49882
|
+
externalUrl && !((_b2 = card.pr) == null ? void 0 : _b2.url) && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49883
|
+
"a",
|
|
49884
|
+
{
|
|
49885
|
+
href: externalUrl,
|
|
49886
|
+
target: "_blank",
|
|
49887
|
+
rel: "noreferrer",
|
|
49888
|
+
className: "text-[#60607a] hover:text-gray-300 transition-colors",
|
|
49889
|
+
title: "Open external link",
|
|
49890
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 15 })
|
|
49891
|
+
}
|
|
49892
|
+
),
|
|
49893
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49894
|
+
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(
|
|
49895
|
+
"button",
|
|
49896
|
+
{
|
|
49897
|
+
onClick: () => void stopRun(),
|
|
49898
|
+
className: "cursor-pointer text-[#60607a] hover:text-red-400 transition-colors",
|
|
49899
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Square, { size: 15, className: "fill-current" })
|
|
49900
|
+
}
|
|
49901
|
+
) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49902
|
+
Tooltip_default,
|
|
49903
|
+
{
|
|
49904
|
+
delayDuration: 0,
|
|
49905
|
+
content: runSession.status === "running" ? "Another task is running" : "Run",
|
|
49906
|
+
side: "bottom",
|
|
49907
|
+
triggerAsChild: true,
|
|
49908
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49909
|
+
"button",
|
|
49910
|
+
{
|
|
49911
|
+
onClick: () => void startRun(card.id),
|
|
49912
|
+
disabled: runSession.status === "running",
|
|
49913
|
+
className: "cursor-pointer text-[#60607a] hover:text-emerald-400 transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
49914
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { size: 15 })
|
|
49915
|
+
}
|
|
49916
|
+
)
|
|
49917
|
+
}
|
|
49918
|
+
) }),
|
|
49919
|
+
!isStory && isReadyForReview && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
49920
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49921
|
+
Tooltip_default,
|
|
49922
|
+
{
|
|
49923
|
+
delayDuration: 0,
|
|
49924
|
+
content: merging ? "Merging..." : `Merge into ${card.baseRef}`,
|
|
49925
|
+
side: "bottom",
|
|
49926
|
+
triggerAsChild: true,
|
|
49927
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49928
|
+
"button",
|
|
49929
|
+
{
|
|
49930
|
+
onClick: onMerge,
|
|
49931
|
+
disabled: merging,
|
|
49932
|
+
className: "cursor-pointer text-[#60607a] hover:text-emerald-400 transition-colors disabled:opacity-40",
|
|
49933
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitMerge, { size: 15 })
|
|
49934
|
+
}
|
|
49935
|
+
)
|
|
49936
|
+
}
|
|
49937
|
+
),
|
|
49938
|
+
((_c3 = card.pr) == null ? void 0 : _c3.url) ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49939
|
+
"a",
|
|
49940
|
+
{
|
|
49941
|
+
href: card.pr.url,
|
|
49942
|
+
target: "_blank",
|
|
49943
|
+
rel: "noreferrer",
|
|
49944
|
+
title: "Open Pull Request",
|
|
49945
|
+
className: "cursor-pointer text-green-400 hover:text-green-300 transition-colors",
|
|
49946
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitPullRequest, { size: 15 })
|
|
49947
|
+
}
|
|
49948
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: `Create PR against ${card.baseRef}`, side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49949
|
+
"button",
|
|
49950
|
+
{
|
|
49951
|
+
onClick: onPR,
|
|
49952
|
+
disabled: merging,
|
|
49953
|
+
className: "cursor-pointer text-[#60607a] hover:text-green-400 transition-colors disabled:opacity-40",
|
|
49954
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(GitPullRequest, { size: 15 })
|
|
49955
|
+
}
|
|
49956
|
+
) })
|
|
49957
|
+
] }),
|
|
49958
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-[18px] bg-[#2a2a35] shrink-0" }),
|
|
49959
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip_default, { delayDuration: 0, content: "Delete task", side: "bottom", triggerAsChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
49960
|
+
"button",
|
|
49961
|
+
{
|
|
49962
|
+
onClick: onDelete,
|
|
49963
|
+
className: "cursor-pointer text-[#60607a] hover:text-red-400 transition-colors",
|
|
49964
|
+
title: "Delete task",
|
|
49965
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 15 })
|
|
49966
|
+
}
|
|
49967
|
+
) })
|
|
49968
|
+
] });
|
|
49969
|
+
}
|
|
49763
49970
|
const COLUMN_LABELS = {
|
|
49764
49971
|
todo: "Todo",
|
|
49765
49972
|
in_progress: "In Progress",
|
|
@@ -73705,19 +73912,6 @@ function CommitMsgDialog({
|
|
|
73705
73912
|
] })
|
|
73706
73913
|
] });
|
|
73707
73914
|
}
|
|
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
73915
|
function CreatePRDialog({
|
|
73722
73916
|
dismiss: dismiss2,
|
|
73723
73917
|
workspaceId,
|
|
@@ -74358,90 +74552,6 @@ function cardToFormModelConfig(cfg) {
|
|
|
74358
74552
|
}
|
|
74359
74553
|
return out;
|
|
74360
74554
|
}
|
|
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
74555
|
function ModelTiersDialog({
|
|
74446
74556
|
pairs,
|
|
74447
74557
|
defaultBinary,
|
|
@@ -74564,13 +74674,12 @@ function TierRow({
|
|
|
74564
74674
|
}
|
|
74565
74675
|
),
|
|
74566
74676
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
74567
|
-
|
|
74677
|
+
AgentBinarySelect,
|
|
74568
74678
|
{
|
|
74569
74679
|
floatingStrategy: "fixed",
|
|
74570
74680
|
value: pair.binary,
|
|
74571
74681
|
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))
|
|
74682
|
+
menuClassName: "w-fit"
|
|
74574
74683
|
}
|
|
74575
74684
|
),
|
|
74576
74685
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -79344,7 +79453,7 @@ function TagInput({
|
|
|
79344
79453
|
}) {
|
|
79345
79454
|
const [draft, setDraft] = reactExports.useState("");
|
|
79346
79455
|
const add2 = (raw2) => {
|
|
79347
|
-
const tag = normalizeTag(raw2);
|
|
79456
|
+
const tag = normalizeTag$1(raw2);
|
|
79348
79457
|
if (!tag || value.includes(tag)) return;
|
|
79349
79458
|
onChange([...value, tag]);
|
|
79350
79459
|
setDraft("");
|
|
@@ -79764,49 +79873,6 @@ function MemorySection({ workspaceId }) {
|
|
|
79764
79873
|
] })
|
|
79765
79874
|
] });
|
|
79766
79875
|
}
|
|
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
79876
|
function SaveRow({ saving, onSave }) {
|
|
79811
79877
|
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
79878
|
}
|