@sideboard-ai/core 0.1.318 → 0.1.320
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{abletime-TKAFNXCM.js → abletime-CRRLEYTE.js} +6 -4
- package/dist/{abletime-KWOBUL46.js → abletime-ICW6Q2AB.js} +6 -4
- package/dist/{abletime-oauth-S4AXA4WR.js → abletime-oauth-P3KPPJE4.js} +3 -3
- package/dist/{abletime-oauth-IUIAGLFJ.js → abletime-oauth-Q76XBSPG.js} +3 -3
- package/dist/{abletime-rest-RWN4EPY3.js → abletime-rest-DNFAYYLP.js} +3 -3
- package/dist/{abletime-rest-ORBELZQO.js → abletime-rest-DQ3PNKXP.js} +3 -3
- package/dist/{agents-KABJUDPI.js → agents-CJZYJOWP.js} +7 -7
- package/dist/{agents-2AR7I6B6.js → agents-F2E2HACB.js} +7 -7
- package/dist/{app-settings-CZVFMOI5.js → app-settings-KMPVI2B7.js} +1 -1
- package/dist/{app-settings-V6YPYY57.js → app-settings-P3H4SEIK.js} +1 -1
- package/dist/{chunk-YEIHCSZS.js → chunk-4GZC6DDH.js} +2 -0
- package/dist/{chunk-XOZNEAWF.js → chunk-56M6VEXI.js} +3 -3
- package/dist/{chunk-7SCVGGF6.js → chunk-5OQONGHO.js} +5 -5
- package/dist/{chunk-A6C67DY5.js → chunk-5S3YP5KH.js} +4 -4
- package/dist/{chunk-I5CLCWUK.js → chunk-72PUPPV2.js} +9 -5
- package/dist/{chunk-BXTISNKW.js → chunk-B7UL36WH.js} +428 -99
- package/dist/{chunk-W5QZWAUB.js → chunk-BTIXTH4N.js} +9 -5
- package/dist/{chunk-AESO2KJS.js → chunk-CB5Z5C3J.js} +2 -2
- package/dist/{chunk-2HOZMSKQ.js → chunk-DFUXW2IT.js} +2 -2
- package/dist/{chunk-ST2UQBJT.js → chunk-DJZRDTZY.js} +6 -6
- package/dist/{chunk-TUJFCJJU.js → chunk-EDXTP2VR.js} +2 -2
- package/dist/{chunk-I5TESHDN.js → chunk-EQ52JR3Q.js} +5 -5
- package/dist/{chunk-FDXHNROD.js → chunk-EQ5JY3MJ.js} +2 -2
- package/dist/{chunk-E52SQENB.js → chunk-FZKAAAEB.js} +3 -1
- package/dist/{chunk-VZAJVX36.js → chunk-HHPTGIKS.js} +2 -2
- package/dist/{chunk-23ZUL2EX.js → chunk-IDPFLXRY.js} +429 -100
- package/dist/{chunk-GCHSJCCX.js → chunk-IFU4W4C4.js} +3 -1
- package/dist/{chunk-IAPO7ZFG.js → chunk-LLIEU2ZB.js} +5 -5
- package/dist/{chunk-MBYGWNLQ.js → chunk-OAFBHCSM.js} +1 -1
- package/dist/{chunk-NRSC4N5X.js → chunk-P74GXA5V.js} +6 -6
- package/dist/{chunk-A46CIARU.js → chunk-PNLGWAYE.js} +2 -2
- package/dist/{chunk-53OCOGND.js → chunk-QGY3UNNL.js} +2 -2
- package/dist/{chunk-7Q327QF2.js → chunk-QIC2JXHW.js} +5 -5
- package/dist/{chunk-YALFZKSC.js → chunk-RHJPP26T.js} +11 -11
- package/dist/{chunk-AZ4GEEGL.js → chunk-UK2KESBN.js} +2 -2
- package/dist/{chunk-7ADEYEMH.js → chunk-V76MQ7MH.js} +5 -5
- package/dist/{chunk-HOLB6ZFZ.js → chunk-XMHMVEIY.js} +2 -0
- package/dist/{chunk-GH7UMULC.js → chunk-ZYZBCLJR.js} +6 -6
- package/dist/{conductor-MG2RAQNT.js → conductor-FPFY6Z5S.js} +6 -6
- package/dist/{conductor-NIUBJLTS.js → conductor-JA5W3L7C.js} +6 -6
- package/dist/{coordinator-prompt-3CT3D5UM.js → coordinator-prompt-M75TAN43.js} +4 -4
- package/dist/{coordinator-prompt-X74F3JIC.js → coordinator-prompt-NUC2ZXMJ.js} +4 -4
- package/dist/{global-workspace-BUWMRNW5.js → global-workspace-5A4H34AF.js} +4 -4
- package/dist/{global-workspace-FTNJEML3.js → global-workspace-SCLQUNUI.js} +4 -4
- package/dist/index.cjs +861 -475
- package/dist/index.d.cts +56 -13
- package/dist/index.d.ts +56 -13
- package/dist/index.js +54 -31
- package/dist/mcp/run-stdio.cjs +459 -95
- package/dist/mcp/run-stdio.js +23 -23
- package/dist/{optional-cli-EMSZBYDE.js → optional-cli-2V3SLME5.js} +3 -3
- package/dist/{optional-cli-6GGESWGE.js → optional-cli-MRNQKVIR.js} +4 -4
- package/dist/{orchestrator-N54V3B76.js → orchestrator-7BDZ5GWD.js} +10 -10
- package/dist/{orchestrator-2SXK4U65.js → orchestrator-NPFWU3XU.js} +10 -10
- package/dist/{thread-store-PLNIWFZ4.js → thread-store-JWHVXLDX.js} +1 -1
- package/dist/{thread-store-7BBA63KV.js → thread-store-QHYN2ZMQ.js} +1 -1
- package/dist/{workspaces-2V5UYPYC.js → workspaces-5QA3YM4L.js} +4 -4
- package/dist/{workspaces-MGKEAYNM.js → workspaces-KWMBOTQD.js} +4 -4
- package/dist/{worktree-THAXW5U7.js → worktree-7EATHVYQ.js} +3 -3
- package/dist/{worktree-XJKLDYOL.js → worktree-O6BANO2I.js} +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1925,7 +1925,9 @@ function planHistoryRetention(archived, thresholds = {}) {
|
|
|
1925
1925
|
if (archivedUpdatedMs(thread) < cutoff) expiredIds.add(thread.id);
|
|
1926
1926
|
}
|
|
1927
1927
|
}
|
|
1928
|
-
const remaining = oldestFirst.filter(
|
|
1928
|
+
const remaining = oldestFirst.filter(
|
|
1929
|
+
(t) => !expiredIds.has(t.id) && !t.ephemeralAutomationId?.trim()
|
|
1930
|
+
);
|
|
1929
1931
|
const overflow = remaining.length > maxCount ? remaining.slice(0, remaining.length - maxCount) : [];
|
|
1930
1932
|
const stripIds = [];
|
|
1931
1933
|
const purgeIds = [...expiredIds];
|
|
@@ -5257,6 +5259,7 @@ function normalizeThread(raw) {
|
|
|
5257
5259
|
quotaContinuedFromId: raw.quotaContinuedFromId ?? null,
|
|
5258
5260
|
accountId: raw.accountId === null ? null : typeof raw.accountId === "string" && raw.accountId.trim() ? raw.accountId.trim() : void 0,
|
|
5259
5261
|
archivedAt: typeof raw.archivedAt === "string" && raw.archivedAt.trim() ? raw.archivedAt.trim() : void 0,
|
|
5262
|
+
ephemeralAutomationId: typeof raw.ephemeralAutomationId === "string" && raw.ephemeralAutomationId.trim() ? raw.ephemeralAutomationId.trim() : void 0,
|
|
5260
5263
|
compactedMessages: Array.isArray(raw.compactedMessages) ? raw.compactedMessages : void 0
|
|
5261
5264
|
};
|
|
5262
5265
|
}
|
|
@@ -5443,6 +5446,7 @@ function updateThread(id, patch) {
|
|
|
5443
5446
|
} else {
|
|
5444
5447
|
delete next.archivedAt;
|
|
5445
5448
|
}
|
|
5449
|
+
if (!next.ephemeralAutomationId?.trim()) delete next.ephemeralAutomationId;
|
|
5446
5450
|
writeThread(next);
|
|
5447
5451
|
return next;
|
|
5448
5452
|
}
|
|
@@ -6093,13 +6097,13 @@ function toolDescription(name, input) {
|
|
|
6093
6097
|
else if (/notify_orchestrator$/i.test(name)) return "Notify orchestrator";
|
|
6094
6098
|
else if (/set_workspace_tags$/i.test(name)) return "Set workspace tags";
|
|
6095
6099
|
if (/(?:list|set|delete)_env$/i.test(name)) return /list_env$/i.test(name) ? "List env vars" : /set_env$/i.test(name) ? "Set env var" : "Delete env var";
|
|
6096
|
-
if (/list_schedules$/i.test(name)) return "List
|
|
6100
|
+
if (/list_schedules$/i.test(name)) return "List automations";
|
|
6097
6101
|
if (/create_schedule$/i.test(name)) {
|
|
6098
|
-
return str2(input?.name) ? `
|
|
6102
|
+
return str2(input?.name) ? `Automation ${str2(input?.name)}` : "Create automation";
|
|
6099
6103
|
}
|
|
6100
|
-
if (/update_schedule$/i.test(name)) return "Update
|
|
6101
|
-
if (/delete_schedule$/i.test(name)) return "Delete
|
|
6102
|
-
if (/run_schedule$/i.test(name)) return "Run
|
|
6104
|
+
if (/update_schedule$/i.test(name)) return "Update automation";
|
|
6105
|
+
if (/delete_schedule$/i.test(name)) return "Delete automation";
|
|
6106
|
+
if (/run_schedule$/i.test(name)) return "Run automation";
|
|
6103
6107
|
if (isSkillToolName(name)) {
|
|
6104
6108
|
const cmd = skillCommandFromInput(input);
|
|
6105
6109
|
return cmd ? `Using /${cmd}` : "Using skill";
|
|
@@ -8302,7 +8306,7 @@ function parseDurationMs(every) {
|
|
|
8302
8306
|
}
|
|
8303
8307
|
function defaultScheduleName(prompt) {
|
|
8304
8308
|
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
8305
|
-
if (!line) return "Untitled
|
|
8309
|
+
if (!line) return "Untitled automation";
|
|
8306
8310
|
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
8307
8311
|
}
|
|
8308
8312
|
function resolveScheduleThreadId(raw, env = process.env) {
|
|
@@ -8373,6 +8377,37 @@ function normalizeWhen(raw) {
|
|
|
8373
8377
|
}
|
|
8374
8378
|
throw new Error("Schedule `when` must be once, every, or cron");
|
|
8375
8379
|
}
|
|
8380
|
+
function normalizeOptionalBool(raw) {
|
|
8381
|
+
if (raw === true || raw === false) return raw;
|
|
8382
|
+
return null;
|
|
8383
|
+
}
|
|
8384
|
+
function normalizeAutonomy2(raw) {
|
|
8385
|
+
return raw === "default" || raw === "full" ? raw : null;
|
|
8386
|
+
}
|
|
8387
|
+
function normalizeAttachments(raw) {
|
|
8388
|
+
if (!Array.isArray(raw)) return [];
|
|
8389
|
+
const out = [];
|
|
8390
|
+
for (const item of raw) {
|
|
8391
|
+
if (!item || typeof item !== "object") continue;
|
|
8392
|
+
const row2 = item;
|
|
8393
|
+
if (typeof row2.id !== "string" || !row2.id.trim()) continue;
|
|
8394
|
+
if (typeof row2.name !== "string" || !row2.name) continue;
|
|
8395
|
+
if (typeof row2.content !== "string") continue;
|
|
8396
|
+
if (!ATTACHMENT_KINDS.has(row2.kind)) continue;
|
|
8397
|
+
const next = {
|
|
8398
|
+
id: row2.id,
|
|
8399
|
+
name: row2.name,
|
|
8400
|
+
kind: row2.kind,
|
|
8401
|
+
content: row2.content
|
|
8402
|
+
};
|
|
8403
|
+
if (typeof row2.path === "string" && row2.path) next.path = row2.path;
|
|
8404
|
+
if (typeof row2.previewDataUrl === "string" && row2.previewDataUrl) {
|
|
8405
|
+
next.previewDataUrl = row2.previewDataUrl;
|
|
8406
|
+
}
|
|
8407
|
+
out.push(next);
|
|
8408
|
+
}
|
|
8409
|
+
return out;
|
|
8410
|
+
}
|
|
8376
8411
|
function normalizeTask(raw) {
|
|
8377
8412
|
const when = normalizeWhen(raw.when);
|
|
8378
8413
|
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
@@ -8385,6 +8420,11 @@ function normalizeTask(raw) {
|
|
|
8385
8420
|
threadId: raw.threadId?.trim() || null,
|
|
8386
8421
|
agent,
|
|
8387
8422
|
model: raw.model?.trim() || null,
|
|
8423
|
+
effort: normalizeThinkingEffort(raw.effort),
|
|
8424
|
+
fast: normalizeOptionalBool(raw.fast),
|
|
8425
|
+
planMode: normalizeOptionalBool(raw.planMode),
|
|
8426
|
+
autonomy: normalizeAutonomy2(raw.autonomy),
|
|
8427
|
+
attachments: normalizeAttachments(raw.attachments),
|
|
8388
8428
|
nextRunAt: raw.nextRunAt,
|
|
8389
8429
|
lastRunAt: raw.lastRunAt ?? null,
|
|
8390
8430
|
lastThreadId: raw.lastThreadId ?? null,
|
|
@@ -8431,6 +8471,11 @@ function buildTask(input, now) {
|
|
|
8431
8471
|
threadId: input.threadId?.trim() || null,
|
|
8432
8472
|
agent,
|
|
8433
8473
|
model: input.model?.trim() || null,
|
|
8474
|
+
effort: input.effort != null ? normalizeThinkingEffort(input.effort) : null,
|
|
8475
|
+
fast: normalizeOptionalBool(input.fast),
|
|
8476
|
+
planMode: normalizeOptionalBool(input.planMode),
|
|
8477
|
+
autonomy: normalizeAutonomy2(input.autonomy),
|
|
8478
|
+
attachments: normalizeAttachments(input.attachments),
|
|
8434
8479
|
nextRunAt,
|
|
8435
8480
|
lastRunAt: null,
|
|
8436
8481
|
lastThreadId: null,
|
|
@@ -8475,7 +8520,7 @@ function createSchedule(input) {
|
|
|
8475
8520
|
function updateSchedule(id, patch) {
|
|
8476
8521
|
const rows = readAll();
|
|
8477
8522
|
const idx = rows.findIndex((row2) => row2.id === id || id.length >= 8 && row2.id.startsWith(id));
|
|
8478
|
-
if (idx < 0) throw new Error(`
|
|
8523
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
8479
8524
|
const prev = rows[idx];
|
|
8480
8525
|
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
8481
8526
|
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
@@ -8490,6 +8535,11 @@ function updateSchedule(id, patch) {
|
|
|
8490
8535
|
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
8491
8536
|
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
8492
8537
|
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
8538
|
+
effort: patch.effort !== void 0 ? normalizeThinkingEffort(patch.effort) : prev.effort,
|
|
8539
|
+
fast: patch.fast !== void 0 ? normalizeOptionalBool(patch.fast) : prev.fast,
|
|
8540
|
+
planMode: patch.planMode !== void 0 ? normalizeOptionalBool(patch.planMode) : prev.planMode,
|
|
8541
|
+
autonomy: patch.autonomy !== void 0 ? normalizeAutonomy2(patch.autonomy) : prev.autonomy,
|
|
8542
|
+
attachments: patch.attachments !== void 0 ? normalizeAttachments(patch.attachments) : prev.attachments,
|
|
8493
8543
|
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
8494
8544
|
lastError: whenChanged ? null : prev.lastError,
|
|
8495
8545
|
updatedAt: nowIso2()
|
|
@@ -8504,13 +8554,13 @@ function deleteSchedule(id) {
|
|
|
8504
8554
|
const next = rows.filter(
|
|
8505
8555
|
(row2) => row2.id !== id && !(id.length >= 8 && row2.id.startsWith(id))
|
|
8506
8556
|
);
|
|
8507
|
-
if (next.length === rows.length) throw new Error(`
|
|
8557
|
+
if (next.length === rows.length) throw new Error(`Automation not found: ${id}`);
|
|
8508
8558
|
writeAll(next);
|
|
8509
8559
|
}
|
|
8510
8560
|
function recordScheduleRun(id, result) {
|
|
8511
8561
|
const rows = readAll();
|
|
8512
8562
|
const idx = rows.findIndex((row2) => row2.id === id);
|
|
8513
|
-
if (idx < 0) throw new Error(`
|
|
8563
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
8514
8564
|
const prev = rows[idx];
|
|
8515
8565
|
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
8516
8566
|
const next = {
|
|
@@ -8526,7 +8576,7 @@ function recordScheduleRun(id, result) {
|
|
|
8526
8576
|
writeAll(rows);
|
|
8527
8577
|
return next;
|
|
8528
8578
|
}
|
|
8529
|
-
var import_node_crypto8, import_node_fs15, import_node_path18, import_croner, DURATION_RE, UNIT_MS;
|
|
8579
|
+
var import_node_crypto8, import_node_fs15, import_node_path18, import_croner, DURATION_RE, UNIT_MS, ATTACHMENT_KINDS;
|
|
8530
8580
|
var init_schedules = __esm({
|
|
8531
8581
|
"src/store/schedules.ts"() {
|
|
8532
8582
|
"use strict";
|
|
@@ -8535,6 +8585,7 @@ var init_schedules = __esm({
|
|
|
8535
8585
|
import_node_path18 = require("path");
|
|
8536
8586
|
import_croner = require("croner");
|
|
8537
8587
|
init_orchestrator_capable();
|
|
8588
|
+
init_thinking_effort();
|
|
8538
8589
|
init_paths();
|
|
8539
8590
|
init_private_file();
|
|
8540
8591
|
init_app_settings();
|
|
@@ -8545,6 +8596,14 @@ var init_schedules = __esm({
|
|
|
8545
8596
|
h: 36e5,
|
|
8546
8597
|
d: 864e5
|
|
8547
8598
|
};
|
|
8599
|
+
ATTACHMENT_KINDS = /* @__PURE__ */ new Set([
|
|
8600
|
+
"transcript",
|
|
8601
|
+
"file",
|
|
8602
|
+
"issue",
|
|
8603
|
+
"workspace",
|
|
8604
|
+
"diff-comment",
|
|
8605
|
+
"code-ref"
|
|
8606
|
+
]);
|
|
8548
8607
|
}
|
|
8549
8608
|
});
|
|
8550
8609
|
|
|
@@ -8601,6 +8660,303 @@ var init_desktop_host = __esm({
|
|
|
8601
8660
|
}
|
|
8602
8661
|
});
|
|
8603
8662
|
|
|
8663
|
+
// src/paths/workspace-scratch.ts
|
|
8664
|
+
function attachmentsGitignoreBody() {
|
|
8665
|
+
return ATTACHMENTS_GITIGNORE;
|
|
8666
|
+
}
|
|
8667
|
+
function isWorkspaceScratchPath(relativePath) {
|
|
8668
|
+
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
8669
|
+
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === CLI_DIR || p.startsWith(`${CLI_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
|
|
8670
|
+
}
|
|
8671
|
+
var ATTACHMENTS_DIR, CLI_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
|
|
8672
|
+
var init_workspace_scratch = __esm({
|
|
8673
|
+
"src/paths/workspace-scratch.ts"() {
|
|
8674
|
+
"use strict";
|
|
8675
|
+
ATTACHMENTS_DIR = ".context/attachments";
|
|
8676
|
+
CLI_DIR = ".context/cli";
|
|
8677
|
+
DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
|
|
8678
|
+
LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
8679
|
+
LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
|
|
8680
|
+
ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
|
|
8681
|
+
*
|
|
8682
|
+
!.gitignore
|
|
8683
|
+
`;
|
|
8684
|
+
}
|
|
8685
|
+
});
|
|
8686
|
+
|
|
8687
|
+
// src/composer/stage-files.ts
|
|
8688
|
+
function fileExtension(filePath) {
|
|
8689
|
+
const base = (0, import_node_path20.basename)(filePath).toLowerCase();
|
|
8690
|
+
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
8691
|
+
}
|
|
8692
|
+
function isImageFilePath(filePath) {
|
|
8693
|
+
return IMAGE_EXTENSIONS.has(fileExtension(filePath));
|
|
8694
|
+
}
|
|
8695
|
+
function imageMimeType(filePath) {
|
|
8696
|
+
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
8697
|
+
}
|
|
8698
|
+
function ensureAttachmentsDir(worktreePath) {
|
|
8699
|
+
const dir = (0, import_node_path20.join)(worktreePath, ATTACHMENTS_DIR);
|
|
8700
|
+
(0, import_node_fs17.mkdirSync)(dir, { recursive: true });
|
|
8701
|
+
const gi = (0, import_node_path20.join)(dir, ".gitignore");
|
|
8702
|
+
if (!(0, import_node_fs17.existsSync)(gi)) {
|
|
8703
|
+
(0, import_node_fs17.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
8704
|
+
}
|
|
8705
|
+
return dir;
|
|
8706
|
+
}
|
|
8707
|
+
function uniqueAttachmentName(dir, originalName) {
|
|
8708
|
+
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
8709
|
+
if (!(0, import_node_fs17.existsSync)((0, import_node_path20.join)(dir, safe))) return safe;
|
|
8710
|
+
const ext = (0, import_node_path20.extname)(safe);
|
|
8711
|
+
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
8712
|
+
for (let i = 1; i < 1e4; i++) {
|
|
8713
|
+
const candidate = `${stem}-${i}${ext}`;
|
|
8714
|
+
if (!(0, import_node_fs17.existsSync)((0, import_node_path20.join)(dir, candidate))) return candidate;
|
|
8715
|
+
}
|
|
8716
|
+
return `${stem}-${(0, import_node_crypto9.randomUUID)()}${ext}`;
|
|
8717
|
+
}
|
|
8718
|
+
function previewDataUrlFromBuf(filePath, buf) {
|
|
8719
|
+
if (!isImageFilePath(filePath)) return void 0;
|
|
8720
|
+
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
8721
|
+
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
8722
|
+
}
|
|
8723
|
+
function attachmentFromBuffer(name, buf, opts) {
|
|
8724
|
+
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
8725
|
+
if (isImageFilePath(name)) {
|
|
8726
|
+
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
8727
|
+
return {
|
|
8728
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8729
|
+
name,
|
|
8730
|
+
kind: "file",
|
|
8731
|
+
path: opts.path,
|
|
8732
|
+
previewDataUrl,
|
|
8733
|
+
content: [
|
|
8734
|
+
`Image attached: ${pathHint}`,
|
|
8735
|
+
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
8736
|
+
].join("\n")
|
|
8737
|
+
};
|
|
8738
|
+
}
|
|
8739
|
+
if (buf.length > MAX_INLINE_BYTES) {
|
|
8740
|
+
return {
|
|
8741
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8742
|
+
name,
|
|
8743
|
+
kind: "file",
|
|
8744
|
+
path: opts.path,
|
|
8745
|
+
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
8746
|
+
};
|
|
8747
|
+
}
|
|
8748
|
+
if (buf.includes(0)) {
|
|
8749
|
+
return {
|
|
8750
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8751
|
+
name,
|
|
8752
|
+
kind: "file",
|
|
8753
|
+
path: opts.path,
|
|
8754
|
+
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
8755
|
+
};
|
|
8756
|
+
}
|
|
8757
|
+
return {
|
|
8758
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8759
|
+
name,
|
|
8760
|
+
kind: "file",
|
|
8761
|
+
path: opts.path,
|
|
8762
|
+
content: buf.toString("utf8")
|
|
8763
|
+
};
|
|
8764
|
+
}
|
|
8765
|
+
function attachmentFromAbsolutePath(absolutePath) {
|
|
8766
|
+
const name = (0, import_node_path20.basename)(absolutePath);
|
|
8767
|
+
try {
|
|
8768
|
+
const st = (0, import_node_fs17.statSync)(absolutePath);
|
|
8769
|
+
if (!st.isFile()) {
|
|
8770
|
+
return {
|
|
8771
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8772
|
+
name,
|
|
8773
|
+
kind: "file",
|
|
8774
|
+
content: `(not a file: ${absolutePath})`
|
|
8775
|
+
};
|
|
8776
|
+
}
|
|
8777
|
+
const buf = (0, import_node_fs17.readFileSync)(absolutePath);
|
|
8778
|
+
return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
|
|
8779
|
+
} catch (err) {
|
|
8780
|
+
return {
|
|
8781
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8782
|
+
name,
|
|
8783
|
+
kind: "file",
|
|
8784
|
+
content: `(could not read ${absolutePath}: ${err instanceof Error ? err.message : String(err)})`
|
|
8785
|
+
};
|
|
8786
|
+
}
|
|
8787
|
+
}
|
|
8788
|
+
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
8789
|
+
if (absolutePaths.length === 0) return [];
|
|
8790
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
8791
|
+
const out = [];
|
|
8792
|
+
for (const abs of absolutePaths) {
|
|
8793
|
+
const originalName = (0, import_node_path20.basename)(abs);
|
|
8794
|
+
try {
|
|
8795
|
+
const st = (0, import_node_fs17.statSync)(abs);
|
|
8796
|
+
if (!st.isFile()) continue;
|
|
8797
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
8798
|
+
const destAbs = (0, import_node_path20.join)(dir, name);
|
|
8799
|
+
(0, import_node_fs17.copyFileSync)(abs, destAbs);
|
|
8800
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
8801
|
+
const buf = (0, import_node_fs17.readFileSync)(destAbs);
|
|
8802
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
8803
|
+
} catch (err) {
|
|
8804
|
+
out.push({
|
|
8805
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8806
|
+
name: originalName,
|
|
8807
|
+
kind: "file",
|
|
8808
|
+
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
8809
|
+
});
|
|
8810
|
+
}
|
|
8811
|
+
}
|
|
8812
|
+
return out;
|
|
8813
|
+
}
|
|
8814
|
+
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
8815
|
+
if (buffers2.length === 0) return [];
|
|
8816
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
8817
|
+
const out = [];
|
|
8818
|
+
for (const item of buffers2) {
|
|
8819
|
+
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
8820
|
+
try {
|
|
8821
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
8822
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
8823
|
+
const destAbs = (0, import_node_path20.join)(dir, name);
|
|
8824
|
+
(0, import_node_fs17.writeFileSync)(destAbs, buf);
|
|
8825
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
8826
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
8827
|
+
} catch (err) {
|
|
8828
|
+
out.push({
|
|
8829
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8830
|
+
name: originalName,
|
|
8831
|
+
kind: "file",
|
|
8832
|
+
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
8833
|
+
});
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
return out;
|
|
8837
|
+
}
|
|
8838
|
+
function attachmentsFromBuffers(buffers2) {
|
|
8839
|
+
return buffers2.map((item) => {
|
|
8840
|
+
const name = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
8841
|
+
try {
|
|
8842
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
8843
|
+
return attachmentFromBuffer(name, buf, { sourceLabel: name });
|
|
8844
|
+
} catch (err) {
|
|
8845
|
+
return {
|
|
8846
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8847
|
+
name,
|
|
8848
|
+
kind: "file",
|
|
8849
|
+
content: `(could not attach ${name}: ${err instanceof Error ? err.message : String(err)})`
|
|
8850
|
+
};
|
|
8851
|
+
}
|
|
8852
|
+
});
|
|
8853
|
+
}
|
|
8854
|
+
function isWorktreeRelativePath(p) {
|
|
8855
|
+
if (!p || p.includes("..")) return false;
|
|
8856
|
+
if (p.startsWith("/")) return false;
|
|
8857
|
+
if (/^[A-Za-z]:[\\/]/.test(p)) return false;
|
|
8858
|
+
return true;
|
|
8859
|
+
}
|
|
8860
|
+
function dataUrlToBase64(url) {
|
|
8861
|
+
if (!url) return null;
|
|
8862
|
+
const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
|
|
8863
|
+
return m?.[1] ?? null;
|
|
8864
|
+
}
|
|
8865
|
+
function persistPendingFileAttachments(worktreePath, attachments) {
|
|
8866
|
+
if (attachments.length === 0) return attachments;
|
|
8867
|
+
const keep = [];
|
|
8868
|
+
const buffers2 = [];
|
|
8869
|
+
for (const att of attachments) {
|
|
8870
|
+
if (att.kind !== "file") {
|
|
8871
|
+
keep.push(att);
|
|
8872
|
+
continue;
|
|
8873
|
+
}
|
|
8874
|
+
if (att.path && isWorktreeRelativePath(att.path)) {
|
|
8875
|
+
keep.push(att);
|
|
8876
|
+
continue;
|
|
8877
|
+
}
|
|
8878
|
+
const fromPreview = dataUrlToBase64(att.previewDataUrl);
|
|
8879
|
+
if (fromPreview) {
|
|
8880
|
+
buffers2.push({ name: att.name, dataBase64: fromPreview });
|
|
8881
|
+
continue;
|
|
8882
|
+
}
|
|
8883
|
+
if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
|
|
8884
|
+
buffers2.push({
|
|
8885
|
+
name: att.name,
|
|
8886
|
+
dataBase64: Buffer.from(att.content, "utf8").toString("base64")
|
|
8887
|
+
});
|
|
8888
|
+
continue;
|
|
8889
|
+
}
|
|
8890
|
+
keep.push(att);
|
|
8891
|
+
}
|
|
8892
|
+
if (buffers2.length === 0) return attachments;
|
|
8893
|
+
return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers2)];
|
|
8894
|
+
}
|
|
8895
|
+
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
8896
|
+
const out = [];
|
|
8897
|
+
for (const rel of relativePaths) {
|
|
8898
|
+
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
8899
|
+
out.push({
|
|
8900
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8901
|
+
name: (0, import_node_path20.basename)(rel) || "file",
|
|
8902
|
+
kind: "file",
|
|
8903
|
+
content: `(invalid path: ${rel})`
|
|
8904
|
+
});
|
|
8905
|
+
continue;
|
|
8906
|
+
}
|
|
8907
|
+
const name = (0, import_node_path20.basename)(rel);
|
|
8908
|
+
try {
|
|
8909
|
+
const abs = (0, import_node_path20.join)(worktreePath, rel);
|
|
8910
|
+
const st = (0, import_node_fs17.statSync)(abs);
|
|
8911
|
+
if (!st.isFile()) continue;
|
|
8912
|
+
const buf = (0, import_node_fs17.readFileSync)(abs);
|
|
8913
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
8914
|
+
} catch (err) {
|
|
8915
|
+
out.push({
|
|
8916
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
8917
|
+
name,
|
|
8918
|
+
kind: "file",
|
|
8919
|
+
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
8920
|
+
});
|
|
8921
|
+
}
|
|
8922
|
+
}
|
|
8923
|
+
return out;
|
|
8924
|
+
}
|
|
8925
|
+
var import_node_fs17, import_node_path20, import_node_crypto9, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
8926
|
+
var init_stage_files = __esm({
|
|
8927
|
+
"src/composer/stage-files.ts"() {
|
|
8928
|
+
"use strict";
|
|
8929
|
+
import_node_fs17 = require("fs");
|
|
8930
|
+
import_node_path20 = require("path");
|
|
8931
|
+
import_node_crypto9 = require("crypto");
|
|
8932
|
+
init_workspace_scratch();
|
|
8933
|
+
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8934
|
+
"png",
|
|
8935
|
+
"jpg",
|
|
8936
|
+
"jpeg",
|
|
8937
|
+
"gif",
|
|
8938
|
+
"webp",
|
|
8939
|
+
"svg",
|
|
8940
|
+
"bmp",
|
|
8941
|
+
"ico"
|
|
8942
|
+
]);
|
|
8943
|
+
IMAGE_MIME_BY_EXT = {
|
|
8944
|
+
png: "image/png",
|
|
8945
|
+
jpg: "image/jpeg",
|
|
8946
|
+
jpeg: "image/jpeg",
|
|
8947
|
+
gif: "image/gif",
|
|
8948
|
+
webp: "image/webp",
|
|
8949
|
+
svg: "image/svg+xml",
|
|
8950
|
+
bmp: "image/bmp",
|
|
8951
|
+
ico: "image/x-icon"
|
|
8952
|
+
};
|
|
8953
|
+
MAX_INLINE_BYTES = 4e5;
|
|
8954
|
+
MAX_PREVIEW_BYTES = 5e6;
|
|
8955
|
+
IMAGE_HINT_RE = /^Image attached:/;
|
|
8956
|
+
PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
|
|
8957
|
+
}
|
|
8958
|
+
});
|
|
8959
|
+
|
|
8604
8960
|
// src/threads/injected-notices.ts
|
|
8605
8961
|
function isSlackExternalReplyText(text7) {
|
|
8606
8962
|
return text7.startsWith("Slack reply from ") && text7.includes("not a command");
|
|
@@ -8685,18 +9041,18 @@ function mcpWaitForTurnTimeoutMs(requested) {
|
|
|
8685
9041
|
if (!Number.isFinite(n)) return MCP_WAIT_FOR_TURN_MAX_MS;
|
|
8686
9042
|
return Math.min(Math.max(1e3, Math.floor(n)), MCP_WAIT_FOR_TURN_MAX_MS);
|
|
8687
9043
|
}
|
|
8688
|
-
function mcpWaitTaskHint(
|
|
9044
|
+
function mcpWaitTaskHint(taskState2, status, blockedReason) {
|
|
8689
9045
|
const why = blockedReason?.trim();
|
|
8690
|
-
if (why &&
|
|
8691
|
-
if (
|
|
9046
|
+
if (why && taskState2 !== "failed" && taskState2 !== "canceled") {
|
|
9047
|
+
if (taskState2 === "submitted" || taskState2 === "working") {
|
|
8692
9048
|
return `Child is blocked: ${why} It has not finished the turn. Do not send_to_chat a check-in.`;
|
|
8693
9049
|
}
|
|
8694
|
-
if (
|
|
9050
|
+
if (taskState2 === "input-required") {
|
|
8695
9051
|
return `Child is blocked: ${why} Wait for the user in that chat \u2014 do not send_to_chat a check-in.`;
|
|
8696
9052
|
}
|
|
8697
9053
|
return `Child is blocked: ${why} Help if this is your child; otherwise tell the user. Do not send_to_chat a check-in.`;
|
|
8698
9054
|
}
|
|
8699
|
-
switch (
|
|
9055
|
+
switch (taskState2) {
|
|
8700
9056
|
case "submitted":
|
|
8701
9057
|
return MCP_WAIT_QUEUED_HINT;
|
|
8702
9058
|
case "working":
|
|
@@ -8752,17 +9108,17 @@ var init_wait_for_turn = __esm({
|
|
|
8752
9108
|
|
|
8753
9109
|
// src/agents/path.ts
|
|
8754
9110
|
function prependPathDir(env, dir) {
|
|
8755
|
-
if (!dir || !(0,
|
|
9111
|
+
if (!dir || !(0, import_node_fs18.existsSync)(dir)) return;
|
|
8756
9112
|
const current = env.PATH ?? "";
|
|
8757
|
-
const parts = current.split(
|
|
9113
|
+
const parts = current.split(import_node_path21.delimiter).filter(Boolean);
|
|
8758
9114
|
if (parts.includes(dir)) {
|
|
8759
9115
|
env.PATH = current;
|
|
8760
9116
|
return;
|
|
8761
9117
|
}
|
|
8762
|
-
env.PATH = [dir, ...parts].join(
|
|
9118
|
+
env.PATH = [dir, ...parts].join(import_node_path21.delimiter);
|
|
8763
9119
|
}
|
|
8764
9120
|
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os6.homedir)()) {
|
|
8765
|
-
return (0,
|
|
9121
|
+
return (0, import_node_path21.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
|
|
8766
9122
|
}
|
|
8767
9123
|
function isConductorBundledCli(filePath) {
|
|
8768
9124
|
const p = (filePath ?? "").replace(/\\/g, "/");
|
|
@@ -8771,21 +9127,21 @@ function isConductorBundledCli(filePath) {
|
|
|
8771
9127
|
function ensureAgentPath(env = process.env) {
|
|
8772
9128
|
const home = env.HOME || env.USERPROFILE || (0, import_node_os6.homedir)();
|
|
8773
9129
|
const current = env.PATH ?? "";
|
|
8774
|
-
const parts = current.split(
|
|
9130
|
+
const parts = current.split(import_node_path21.delimiter).filter(Boolean);
|
|
8775
9131
|
const seen = new Set(parts);
|
|
8776
9132
|
const extras = [
|
|
8777
|
-
...EXTRA_BIN_DIRS.map((rel) => (0,
|
|
9133
|
+
...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path21.join)(home, rel)),
|
|
8778
9134
|
"/opt/homebrew/bin",
|
|
8779
9135
|
"/usr/local/bin",
|
|
8780
9136
|
// Keep after Homebrew/npm so a user-installed CLI still wins.
|
|
8781
9137
|
conductorBundledBinDir(home)
|
|
8782
9138
|
];
|
|
8783
9139
|
for (const dir of extras.reverse()) {
|
|
8784
|
-
if (!dir || seen.has(dir) || !(0,
|
|
9140
|
+
if (!dir || seen.has(dir) || !(0, import_node_fs18.existsSync)(dir)) continue;
|
|
8785
9141
|
parts.unshift(dir);
|
|
8786
9142
|
seen.add(dir);
|
|
8787
9143
|
}
|
|
8788
|
-
const next = parts.join(
|
|
9144
|
+
const next = parts.join(import_node_path21.delimiter);
|
|
8789
9145
|
env.PATH = next;
|
|
8790
9146
|
return next;
|
|
8791
9147
|
}
|
|
@@ -8793,7 +9149,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
|
|
|
8793
9149
|
ensureAgentPath(env);
|
|
8794
9150
|
const prefix = npmGlobalPrefix(env);
|
|
8795
9151
|
if (prefix) {
|
|
8796
|
-
const binDir = process.platform === "win32" ? prefix : (0,
|
|
9152
|
+
const binDir = process.platform === "win32" ? prefix : (0, import_node_path21.join)(prefix, "bin");
|
|
8797
9153
|
prependPathDir(env, binDir);
|
|
8798
9154
|
}
|
|
8799
9155
|
return env.PATH ?? "";
|
|
@@ -8814,8 +9170,8 @@ function npmGlobalPrefix(env = process.env) {
|
|
|
8814
9170
|
function npmGlobalNodeModules(env = process.env) {
|
|
8815
9171
|
const prefix = npmGlobalPrefix(env);
|
|
8816
9172
|
if (!prefix) return null;
|
|
8817
|
-
const dir = process.platform === "win32" ? (0,
|
|
8818
|
-
return (0,
|
|
9173
|
+
const dir = process.platform === "win32" ? (0, import_node_path21.join)(prefix, "node_modules") : (0, import_node_path21.join)(prefix, "lib", "node_modules");
|
|
9174
|
+
return (0, import_node_fs18.existsSync)(dir) ? dir : null;
|
|
8819
9175
|
}
|
|
8820
9176
|
function posixShellSingleQuote(value) {
|
|
8821
9177
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -8838,14 +9194,14 @@ function withExportedPath(command, pathValue) {
|
|
|
8838
9194
|
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
8839
9195
|
return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
|
|
8840
9196
|
}
|
|
8841
|
-
var
|
|
9197
|
+
var import_node_fs18, import_node_child_process3, import_node_os6, import_node_path21, EXTRA_BIN_DIRS;
|
|
8842
9198
|
var init_path = __esm({
|
|
8843
9199
|
"src/agents/path.ts"() {
|
|
8844
9200
|
"use strict";
|
|
8845
|
-
|
|
9201
|
+
import_node_fs18 = require("fs");
|
|
8846
9202
|
import_node_child_process3 = require("child_process");
|
|
8847
9203
|
import_node_os6 = require("os");
|
|
8848
|
-
|
|
9204
|
+
import_node_path21 = require("path");
|
|
8849
9205
|
EXTRA_BIN_DIRS = [
|
|
8850
9206
|
".local/bin",
|
|
8851
9207
|
".cargo/bin",
|
|
@@ -8866,23 +9222,23 @@ var init_path = __esm({
|
|
|
8866
9222
|
function githubAgentAuthDir() {
|
|
8867
9223
|
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
8868
9224
|
if (override) return override;
|
|
8869
|
-
return (0,
|
|
9225
|
+
return (0, import_node_path22.join)((0, import_node_os7.homedir)(), ".sideboard-git-auth");
|
|
8870
9226
|
}
|
|
8871
9227
|
function githubCredentialStorePath() {
|
|
8872
|
-
return (0,
|
|
9228
|
+
return (0, import_node_path22.join)(githubAgentAuthDir(), "git-credentials");
|
|
8873
9229
|
}
|
|
8874
9230
|
function githubGhConfigDir() {
|
|
8875
|
-
return (0,
|
|
9231
|
+
return (0, import_node_path22.join)(githubAgentAuthDir(), "gh");
|
|
8876
9232
|
}
|
|
8877
9233
|
function writePrivateFile2(file, body) {
|
|
8878
|
-
(0,
|
|
9234
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path22.dirname)(file), { recursive: true, mode: 448 });
|
|
8879
9235
|
try {
|
|
8880
|
-
(0,
|
|
9236
|
+
(0, import_node_fs19.chmodSync)((0, import_node_path22.dirname)(file), 448);
|
|
8881
9237
|
} catch {
|
|
8882
9238
|
}
|
|
8883
|
-
(0,
|
|
9239
|
+
(0, import_node_fs19.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
8884
9240
|
try {
|
|
8885
|
-
(0,
|
|
9241
|
+
(0, import_node_fs19.chmodSync)(file, 384);
|
|
8886
9242
|
} catch {
|
|
8887
9243
|
}
|
|
8888
9244
|
}
|
|
@@ -8907,19 +9263,19 @@ function materializeGithubAgentAuth(token, user) {
|
|
|
8907
9263
|
const trimmed = token.trim();
|
|
8908
9264
|
if (!trimmed) return;
|
|
8909
9265
|
const root = githubAgentAuthDir();
|
|
8910
|
-
(0,
|
|
9266
|
+
(0, import_node_fs19.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
8911
9267
|
try {
|
|
8912
|
-
(0,
|
|
9268
|
+
(0, import_node_fs19.chmodSync)(root, 448);
|
|
8913
9269
|
} catch {
|
|
8914
9270
|
}
|
|
8915
9271
|
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
8916
9272
|
const ghDir = githubGhConfigDir();
|
|
8917
|
-
(0,
|
|
8918
|
-
writePrivateFile2((0,
|
|
8919
|
-
writePrivateFile2((0,
|
|
9273
|
+
(0, import_node_fs19.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
9274
|
+
writePrivateFile2((0, import_node_path22.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
9275
|
+
writePrivateFile2((0, import_node_path22.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
8920
9276
|
}
|
|
8921
9277
|
function githubAgentAuthReady() {
|
|
8922
|
-
return (0,
|
|
9278
|
+
return (0, import_node_fs19.existsSync)(githubCredentialStorePath()) && (0, import_node_fs19.existsSync)((0, import_node_path22.join)(githubGhConfigDir(), "hosts.yml"));
|
|
8923
9279
|
}
|
|
8924
9280
|
function githubCredentialHelperGitConfig() {
|
|
8925
9281
|
const file = githubCredentialStorePath();
|
|
@@ -8934,13 +9290,13 @@ function githubGhConfigEnv() {
|
|
|
8934
9290
|
GH_PROMPT_DISABLED: "1"
|
|
8935
9291
|
};
|
|
8936
9292
|
}
|
|
8937
|
-
var
|
|
9293
|
+
var import_node_fs19, import_node_os7, import_node_path22;
|
|
8938
9294
|
var init_github_agent_auth = __esm({
|
|
8939
9295
|
"src/git/github-agent-auth.ts"() {
|
|
8940
9296
|
"use strict";
|
|
8941
|
-
|
|
9297
|
+
import_node_fs19 = require("fs");
|
|
8942
9298
|
import_node_os7 = require("os");
|
|
8943
|
-
|
|
9299
|
+
import_node_path22 = require("path");
|
|
8944
9300
|
}
|
|
8945
9301
|
});
|
|
8946
9302
|
|
|
@@ -8949,11 +9305,11 @@ function isIndexLockError(text7) {
|
|
|
8949
9305
|
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text7);
|
|
8950
9306
|
}
|
|
8951
9307
|
function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
|
|
8952
|
-
const lockPath = (0,
|
|
9308
|
+
const lockPath = (0, import_node_path23.join)(gitDir, "index.lock");
|
|
8953
9309
|
try {
|
|
8954
|
-
if (!(0,
|
|
8955
|
-
if (now - (0,
|
|
8956
|
-
(0,
|
|
9310
|
+
if (!(0, import_node_fs20.existsSync)(lockPath)) return null;
|
|
9311
|
+
if (now - (0, import_node_fs20.statSync)(lockPath).mtimeMs < maxAgeMs) return null;
|
|
9312
|
+
(0, import_node_fs20.unlinkSync)(lockPath);
|
|
8957
9313
|
return lockPath;
|
|
8958
9314
|
} catch {
|
|
8959
9315
|
return null;
|
|
@@ -8968,12 +9324,12 @@ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
|
|
|
8968
9324
|
}
|
|
8969
9325
|
return removed;
|
|
8970
9326
|
}
|
|
8971
|
-
var
|
|
9327
|
+
var import_node_fs20, import_node_path23, STALE_INDEX_LOCK_MS;
|
|
8972
9328
|
var init_stale_lock = __esm({
|
|
8973
9329
|
"src/git/stale-lock.ts"() {
|
|
8974
9330
|
"use strict";
|
|
8975
|
-
|
|
8976
|
-
|
|
9331
|
+
import_node_fs20 = require("fs");
|
|
9332
|
+
import_node_path23 = require("path");
|
|
8977
9333
|
STALE_INDEX_LOCK_MS = 2e4;
|
|
8978
9334
|
}
|
|
8979
9335
|
});
|
|
@@ -9224,11 +9580,11 @@ async function ensureWorktreeSideboardIgnored(worktreePath) {
|
|
|
9224
9580
|
if (gitDir.exitCode !== 0) return;
|
|
9225
9581
|
const dir = gitDir.stdout.trim();
|
|
9226
9582
|
if (!dir) return;
|
|
9227
|
-
const excludePath = (0,
|
|
9228
|
-
(0,
|
|
9583
|
+
const excludePath = (0, import_node_path24.join)(dir, "info", "exclude");
|
|
9584
|
+
(0, import_node_fs21.mkdirSync)((0, import_node_path24.dirname)(excludePath), { recursive: true });
|
|
9229
9585
|
let body = "";
|
|
9230
9586
|
try {
|
|
9231
|
-
body = (0,
|
|
9587
|
+
body = (0, import_node_fs21.readFileSync)(excludePath, "utf8");
|
|
9232
9588
|
} catch {
|
|
9233
9589
|
body = "";
|
|
9234
9590
|
}
|
|
@@ -9244,7 +9600,7 @@ async function ensureWorktreeSideboardIgnored(worktreePath) {
|
|
|
9244
9600
|
` : body;
|
|
9245
9601
|
const header = body.includes(EXCLUDE_COMMENT) ? "" : `${EXCLUDE_COMMENT}
|
|
9246
9602
|
`;
|
|
9247
|
-
(0,
|
|
9603
|
+
(0, import_node_fs21.writeFileSync)(excludePath, `${prefix}${header}${missing.join("\n")}
|
|
9248
9604
|
`, "utf8");
|
|
9249
9605
|
}
|
|
9250
9606
|
const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
|
|
@@ -9259,12 +9615,12 @@ async function ensureWorktreeSideboardIgnored(worktreePath) {
|
|
|
9259
9615
|
timeoutMs: 8e3
|
|
9260
9616
|
});
|
|
9261
9617
|
}
|
|
9262
|
-
var
|
|
9618
|
+
var import_node_fs21, import_node_path24, WORKTREE_SIDEBOARD_EXCLUDE, WORKTREE_CONTEXT_EXCLUDE, EXCLUDE_COMMENT;
|
|
9263
9619
|
var init_worktree_exclude = __esm({
|
|
9264
9620
|
"src/git/worktree-exclude.ts"() {
|
|
9265
9621
|
"use strict";
|
|
9266
|
-
|
|
9267
|
-
|
|
9622
|
+
import_node_fs21 = require("fs");
|
|
9623
|
+
import_node_path24 = require("path");
|
|
9268
9624
|
init_run();
|
|
9269
9625
|
WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
|
|
9270
9626
|
WORKTREE_CONTEXT_EXCLUDE = ".context/";
|
|
@@ -9385,7 +9741,7 @@ async function warmGithubAgentAuth(opts) {
|
|
|
9385
9741
|
}
|
|
9386
9742
|
function normalizeWritableRoot(raw) {
|
|
9387
9743
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
9388
|
-
return trimmed && (0,
|
|
9744
|
+
return trimmed && (0, import_node_path25.isAbsolute)(trimmed) ? trimmed : null;
|
|
9389
9745
|
}
|
|
9390
9746
|
async function resolveCodexGitWritableRoots(cwd) {
|
|
9391
9747
|
const roots = /* @__PURE__ */ new Set();
|
|
@@ -9463,11 +9819,11 @@ function formatGitAuthModeDirective(mode) {
|
|
|
9463
9819
|
].join("\n");
|
|
9464
9820
|
}
|
|
9465
9821
|
}
|
|
9466
|
-
var
|
|
9822
|
+
var import_node_path25, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
9467
9823
|
var init_git_auth_mode = __esm({
|
|
9468
9824
|
"src/git/git-auth-mode.ts"() {
|
|
9469
9825
|
"use strict";
|
|
9470
|
-
|
|
9826
|
+
import_node_path25 = require("path");
|
|
9471
9827
|
init_app_settings();
|
|
9472
9828
|
init_github_agent_auth();
|
|
9473
9829
|
init_run();
|
|
@@ -10096,46 +10452,22 @@ var init_stack = __esm({
|
|
|
10096
10452
|
}
|
|
10097
10453
|
});
|
|
10098
10454
|
|
|
10099
|
-
// src/paths/workspace-scratch.ts
|
|
10100
|
-
function attachmentsGitignoreBody() {
|
|
10101
|
-
return ATTACHMENTS_GITIGNORE;
|
|
10102
|
-
}
|
|
10103
|
-
function isWorkspaceScratchPath(relativePath) {
|
|
10104
|
-
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
10105
|
-
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === CLI_DIR || p.startsWith(`${CLI_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
|
|
10106
|
-
}
|
|
10107
|
-
var ATTACHMENTS_DIR, CLI_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
|
|
10108
|
-
var init_workspace_scratch = __esm({
|
|
10109
|
-
"src/paths/workspace-scratch.ts"() {
|
|
10110
|
-
"use strict";
|
|
10111
|
-
ATTACHMENTS_DIR = ".context/attachments";
|
|
10112
|
-
CLI_DIR = ".context/cli";
|
|
10113
|
-
DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
|
|
10114
|
-
LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
10115
|
-
LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
|
|
10116
|
-
ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
|
|
10117
|
-
*
|
|
10118
|
-
!.gitignore
|
|
10119
|
-
`;
|
|
10120
|
-
}
|
|
10121
|
-
});
|
|
10122
|
-
|
|
10123
10455
|
// src/git/team-slugs.ts
|
|
10124
10456
|
function sameRepoPath2(a, b) {
|
|
10125
10457
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
10126
10458
|
}
|
|
10127
10459
|
function listLocalPlaceholderBranchSlugs(repoPath) {
|
|
10128
10460
|
const slugs = [];
|
|
10129
|
-
const headsDir = (0,
|
|
10130
|
-
const threadDir = (0,
|
|
10461
|
+
const headsDir = (0, import_node_path26.join)(repoPath, ".git", "refs", "heads");
|
|
10462
|
+
const threadDir = (0, import_node_path26.join)(headsDir, "thread");
|
|
10131
10463
|
try {
|
|
10132
|
-
if ((0,
|
|
10133
|
-
for (const name of (0,
|
|
10464
|
+
if ((0, import_node_fs22.existsSync)(threadDir)) {
|
|
10465
|
+
for (const name of (0, import_node_fs22.readdirSync)(threadDir)) {
|
|
10134
10466
|
if (!name.startsWith(".")) slugs.push(normalizeTakenSlug(name));
|
|
10135
10467
|
}
|
|
10136
10468
|
}
|
|
10137
|
-
if ((0,
|
|
10138
|
-
for (const entry of (0,
|
|
10469
|
+
if ((0, import_node_fs22.existsSync)(headsDir)) {
|
|
10470
|
+
for (const entry of (0, import_node_fs22.readdirSync)(headsDir, { withFileTypes: true })) {
|
|
10139
10471
|
if (entry.isFile() && !entry.name.startsWith(".")) {
|
|
10140
10472
|
slugs.push(normalizeTakenSlug(entry.name));
|
|
10141
10473
|
}
|
|
@@ -10149,8 +10481,8 @@ function listLocalPlaceholderBranchSlugs(repoPath) {
|
|
|
10149
10481
|
function collectTakenTeamSlugs(repoPath) {
|
|
10150
10482
|
const taken = /* @__PURE__ */ new Set();
|
|
10151
10483
|
const root = worktreesRoot(repoPath);
|
|
10152
|
-
if ((0,
|
|
10153
|
-
for (const entry of (0,
|
|
10484
|
+
if ((0, import_node_fs22.existsSync)(root)) {
|
|
10485
|
+
for (const entry of (0, import_node_fs22.readdirSync)(root, { withFileTypes: true })) {
|
|
10154
10486
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
10155
10487
|
for (const slug of takenSlugsFromThread({ worktreePath: entry.name })) {
|
|
10156
10488
|
taken.add(slug);
|
|
@@ -10175,18 +10507,18 @@ function allocateTeamSlug(repoPath) {
|
|
|
10175
10507
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
10176
10508
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
10177
10509
|
const team = allocateTeamName(taken);
|
|
10178
|
-
const path2 = (0,
|
|
10179
|
-
if (!(0,
|
|
10510
|
+
const path2 = (0, import_node_path26.join)(worktreesRoot(repoPath), team.slug);
|
|
10511
|
+
if (!(0, import_node_fs22.existsSync)(path2)) return team;
|
|
10180
10512
|
taken.add(team.slug);
|
|
10181
10513
|
}
|
|
10182
10514
|
throw new Error("No available soccer team worktree directories left");
|
|
10183
10515
|
}
|
|
10184
|
-
var
|
|
10516
|
+
var import_node_fs22, import_node_path26;
|
|
10185
10517
|
var init_team_slugs = __esm({
|
|
10186
10518
|
"src/git/team-slugs.ts"() {
|
|
10187
10519
|
"use strict";
|
|
10188
|
-
|
|
10189
|
-
|
|
10520
|
+
import_node_fs22 = require("fs");
|
|
10521
|
+
import_node_path26 = require("path");
|
|
10190
10522
|
init_paths();
|
|
10191
10523
|
init_thread_store();
|
|
10192
10524
|
init_teams();
|
|
@@ -10302,7 +10634,7 @@ async function resolveRepoRoot(cwd) {
|
|
|
10302
10634
|
}
|
|
10303
10635
|
function canonicalizeRepoPath(path2) {
|
|
10304
10636
|
try {
|
|
10305
|
-
return (0,
|
|
10637
|
+
return (0, import_node_fs23.realpathSync)(path2);
|
|
10306
10638
|
} catch {
|
|
10307
10639
|
return path2.replace(/\/+$/, "");
|
|
10308
10640
|
}
|
|
@@ -11220,8 +11552,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
|
|
|
11220
11552
|
}
|
|
11221
11553
|
async function createThreadWorktree(opts) {
|
|
11222
11554
|
let branchName = opts.slug;
|
|
11223
|
-
const worktreePath = (0,
|
|
11224
|
-
if ((0,
|
|
11555
|
+
const worktreePath = (0, import_node_path27.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
11556
|
+
if ((0, import_node_fs23.existsSync)(worktreePath)) {
|
|
11225
11557
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
11226
11558
|
}
|
|
11227
11559
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -11262,8 +11594,8 @@ ${add.stdout}`;
|
|
|
11262
11594
|
async function createExistingBranchWorktree(opts) {
|
|
11263
11595
|
const branchName = opts.branchName.trim();
|
|
11264
11596
|
if (!branchName) throw new Error("branch name required");
|
|
11265
|
-
const worktreePath = (0,
|
|
11266
|
-
if ((0,
|
|
11597
|
+
const worktreePath = (0, import_node_path27.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
11598
|
+
if ((0, import_node_fs23.existsSync)(worktreePath)) {
|
|
11267
11599
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
11268
11600
|
}
|
|
11269
11601
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -11602,11 +11934,11 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
11602
11934
|
const headRef = ghHeadRef(slug, opts.head);
|
|
11603
11935
|
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
11604
11936
|
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
11605
|
-
const bodyFile = (0,
|
|
11937
|
+
const bodyFile = (0, import_node_path27.join)(
|
|
11606
11938
|
(0, import_node_os8.tmpdir)(),
|
|
11607
|
-
`sideboard-pr-body-${process.pid}-${(0,
|
|
11939
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto10.randomBytes)(6).toString("hex")}.md`
|
|
11608
11940
|
);
|
|
11609
|
-
(0,
|
|
11941
|
+
(0, import_node_fs23.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
11610
11942
|
`, "utf8");
|
|
11611
11943
|
const bodyArgs = ["--body-file", bodyFile];
|
|
11612
11944
|
try {
|
|
@@ -11620,7 +11952,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
11620
11952
|
});
|
|
11621
11953
|
} finally {
|
|
11622
11954
|
try {
|
|
11623
|
-
(0,
|
|
11955
|
+
(0, import_node_fs23.unlinkSync)(bodyFile);
|
|
11624
11956
|
} catch {
|
|
11625
11957
|
}
|
|
11626
11958
|
}
|
|
@@ -11700,14 +12032,14 @@ function suggestSlug(source) {
|
|
|
11700
12032
|
const stamp = Date.now().toString(36).slice(-4);
|
|
11701
12033
|
return `${base || "thread"}-${stamp}`;
|
|
11702
12034
|
}
|
|
11703
|
-
var
|
|
12035
|
+
var import_node_crypto10, import_node_fs23, import_node_os8, import_node_path27, PR_INFO_JSON_FIELDS, PR_DETAILS_JSON_FIELDS;
|
|
11704
12036
|
var init_worktree = __esm({
|
|
11705
12037
|
"src/git/worktree.ts"() {
|
|
11706
12038
|
"use strict";
|
|
11707
|
-
|
|
11708
|
-
|
|
12039
|
+
import_node_crypto10 = require("crypto");
|
|
12040
|
+
import_node_fs23 = require("fs");
|
|
11709
12041
|
import_node_os8 = require("os");
|
|
11710
|
-
|
|
12042
|
+
import_node_path27 = require("path");
|
|
11711
12043
|
init_paths();
|
|
11712
12044
|
init_worktree_labels();
|
|
11713
12045
|
init_gh_errors();
|
|
@@ -11797,279 +12129,6 @@ var init_cloud_connect_constants = __esm({
|
|
|
11797
12129
|
}
|
|
11798
12130
|
});
|
|
11799
12131
|
|
|
11800
|
-
// src/composer/stage-files.ts
|
|
11801
|
-
function fileExtension(filePath) {
|
|
11802
|
-
const base = (0, import_node_path27.basename)(filePath).toLowerCase();
|
|
11803
|
-
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
11804
|
-
}
|
|
11805
|
-
function isImageFilePath(filePath) {
|
|
11806
|
-
return IMAGE_EXTENSIONS.has(fileExtension(filePath));
|
|
11807
|
-
}
|
|
11808
|
-
function imageMimeType(filePath) {
|
|
11809
|
-
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
11810
|
-
}
|
|
11811
|
-
function ensureAttachmentsDir(worktreePath) {
|
|
11812
|
-
const dir = (0, import_node_path27.join)(worktreePath, ATTACHMENTS_DIR);
|
|
11813
|
-
(0, import_node_fs23.mkdirSync)(dir, { recursive: true });
|
|
11814
|
-
const gi = (0, import_node_path27.join)(dir, ".gitignore");
|
|
11815
|
-
if (!(0, import_node_fs23.existsSync)(gi)) {
|
|
11816
|
-
(0, import_node_fs23.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
11817
|
-
}
|
|
11818
|
-
return dir;
|
|
11819
|
-
}
|
|
11820
|
-
function uniqueAttachmentName(dir, originalName) {
|
|
11821
|
-
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
11822
|
-
if (!(0, import_node_fs23.existsSync)((0, import_node_path27.join)(dir, safe))) return safe;
|
|
11823
|
-
const ext = (0, import_node_path27.extname)(safe);
|
|
11824
|
-
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
11825
|
-
for (let i = 1; i < 1e4; i++) {
|
|
11826
|
-
const candidate = `${stem}-${i}${ext}`;
|
|
11827
|
-
if (!(0, import_node_fs23.existsSync)((0, import_node_path27.join)(dir, candidate))) return candidate;
|
|
11828
|
-
}
|
|
11829
|
-
return `${stem}-${(0, import_node_crypto10.randomUUID)()}${ext}`;
|
|
11830
|
-
}
|
|
11831
|
-
function previewDataUrlFromBuf(filePath, buf) {
|
|
11832
|
-
if (!isImageFilePath(filePath)) return void 0;
|
|
11833
|
-
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
11834
|
-
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
11835
|
-
}
|
|
11836
|
-
function attachmentFromBuffer(name, buf, opts) {
|
|
11837
|
-
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
11838
|
-
if (isImageFilePath(name)) {
|
|
11839
|
-
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
11840
|
-
return {
|
|
11841
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11842
|
-
name,
|
|
11843
|
-
kind: "file",
|
|
11844
|
-
path: opts.path,
|
|
11845
|
-
previewDataUrl,
|
|
11846
|
-
content: [
|
|
11847
|
-
`Image attached: ${pathHint}`,
|
|
11848
|
-
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
11849
|
-
].join("\n")
|
|
11850
|
-
};
|
|
11851
|
-
}
|
|
11852
|
-
if (buf.length > MAX_INLINE_BYTES) {
|
|
11853
|
-
return {
|
|
11854
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11855
|
-
name,
|
|
11856
|
-
kind: "file",
|
|
11857
|
-
path: opts.path,
|
|
11858
|
-
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
11859
|
-
};
|
|
11860
|
-
}
|
|
11861
|
-
if (buf.includes(0)) {
|
|
11862
|
-
return {
|
|
11863
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11864
|
-
name,
|
|
11865
|
-
kind: "file",
|
|
11866
|
-
path: opts.path,
|
|
11867
|
-
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
11868
|
-
};
|
|
11869
|
-
}
|
|
11870
|
-
return {
|
|
11871
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11872
|
-
name,
|
|
11873
|
-
kind: "file",
|
|
11874
|
-
path: opts.path,
|
|
11875
|
-
content: buf.toString("utf8")
|
|
11876
|
-
};
|
|
11877
|
-
}
|
|
11878
|
-
function attachmentFromAbsolutePath(absolutePath) {
|
|
11879
|
-
const name = (0, import_node_path27.basename)(absolutePath);
|
|
11880
|
-
try {
|
|
11881
|
-
const st = (0, import_node_fs23.statSync)(absolutePath);
|
|
11882
|
-
if (!st.isFile()) {
|
|
11883
|
-
return {
|
|
11884
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11885
|
-
name,
|
|
11886
|
-
kind: "file",
|
|
11887
|
-
content: `(not a file: ${absolutePath})`
|
|
11888
|
-
};
|
|
11889
|
-
}
|
|
11890
|
-
const buf = (0, import_node_fs23.readFileSync)(absolutePath);
|
|
11891
|
-
return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
|
|
11892
|
-
} catch (err) {
|
|
11893
|
-
return {
|
|
11894
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11895
|
-
name,
|
|
11896
|
-
kind: "file",
|
|
11897
|
-
content: `(could not read ${absolutePath}: ${err instanceof Error ? err.message : String(err)})`
|
|
11898
|
-
};
|
|
11899
|
-
}
|
|
11900
|
-
}
|
|
11901
|
-
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
11902
|
-
if (absolutePaths.length === 0) return [];
|
|
11903
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
11904
|
-
const out = [];
|
|
11905
|
-
for (const abs of absolutePaths) {
|
|
11906
|
-
const originalName = (0, import_node_path27.basename)(abs);
|
|
11907
|
-
try {
|
|
11908
|
-
const st = (0, import_node_fs23.statSync)(abs);
|
|
11909
|
-
if (!st.isFile()) continue;
|
|
11910
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
11911
|
-
const destAbs = (0, import_node_path27.join)(dir, name);
|
|
11912
|
-
(0, import_node_fs23.copyFileSync)(abs, destAbs);
|
|
11913
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
11914
|
-
const buf = (0, import_node_fs23.readFileSync)(destAbs);
|
|
11915
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
11916
|
-
} catch (err) {
|
|
11917
|
-
out.push({
|
|
11918
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11919
|
-
name: originalName,
|
|
11920
|
-
kind: "file",
|
|
11921
|
-
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
11922
|
-
});
|
|
11923
|
-
}
|
|
11924
|
-
}
|
|
11925
|
-
return out;
|
|
11926
|
-
}
|
|
11927
|
-
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
11928
|
-
if (buffers2.length === 0) return [];
|
|
11929
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
11930
|
-
const out = [];
|
|
11931
|
-
for (const item of buffers2) {
|
|
11932
|
-
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
11933
|
-
try {
|
|
11934
|
-
const buf = Buffer.from(item.dataBase64, "base64");
|
|
11935
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
11936
|
-
const destAbs = (0, import_node_path27.join)(dir, name);
|
|
11937
|
-
(0, import_node_fs23.writeFileSync)(destAbs, buf);
|
|
11938
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
11939
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
11940
|
-
} catch (err) {
|
|
11941
|
-
out.push({
|
|
11942
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11943
|
-
name: originalName,
|
|
11944
|
-
kind: "file",
|
|
11945
|
-
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
11946
|
-
});
|
|
11947
|
-
}
|
|
11948
|
-
}
|
|
11949
|
-
return out;
|
|
11950
|
-
}
|
|
11951
|
-
function attachmentsFromBuffers(buffers2) {
|
|
11952
|
-
return buffers2.map((item) => {
|
|
11953
|
-
const name = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
11954
|
-
try {
|
|
11955
|
-
const buf = Buffer.from(item.dataBase64, "base64");
|
|
11956
|
-
return attachmentFromBuffer(name, buf, { sourceLabel: name });
|
|
11957
|
-
} catch (err) {
|
|
11958
|
-
return {
|
|
11959
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
11960
|
-
name,
|
|
11961
|
-
kind: "file",
|
|
11962
|
-
content: `(could not attach ${name}: ${err instanceof Error ? err.message : String(err)})`
|
|
11963
|
-
};
|
|
11964
|
-
}
|
|
11965
|
-
});
|
|
11966
|
-
}
|
|
11967
|
-
function isWorktreeRelativePath(p) {
|
|
11968
|
-
if (!p || p.includes("..")) return false;
|
|
11969
|
-
if (p.startsWith("/")) return false;
|
|
11970
|
-
if (/^[A-Za-z]:[\\/]/.test(p)) return false;
|
|
11971
|
-
return true;
|
|
11972
|
-
}
|
|
11973
|
-
function dataUrlToBase64(url) {
|
|
11974
|
-
if (!url) return null;
|
|
11975
|
-
const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
|
|
11976
|
-
return m?.[1] ?? null;
|
|
11977
|
-
}
|
|
11978
|
-
function persistPendingFileAttachments(worktreePath, attachments) {
|
|
11979
|
-
if (attachments.length === 0) return attachments;
|
|
11980
|
-
const keep = [];
|
|
11981
|
-
const buffers2 = [];
|
|
11982
|
-
for (const att of attachments) {
|
|
11983
|
-
if (att.kind !== "file") {
|
|
11984
|
-
keep.push(att);
|
|
11985
|
-
continue;
|
|
11986
|
-
}
|
|
11987
|
-
if (att.path && isWorktreeRelativePath(att.path)) {
|
|
11988
|
-
keep.push(att);
|
|
11989
|
-
continue;
|
|
11990
|
-
}
|
|
11991
|
-
const fromPreview = dataUrlToBase64(att.previewDataUrl);
|
|
11992
|
-
if (fromPreview) {
|
|
11993
|
-
buffers2.push({ name: att.name, dataBase64: fromPreview });
|
|
11994
|
-
continue;
|
|
11995
|
-
}
|
|
11996
|
-
if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
|
|
11997
|
-
buffers2.push({
|
|
11998
|
-
name: att.name,
|
|
11999
|
-
dataBase64: Buffer.from(att.content, "utf8").toString("base64")
|
|
12000
|
-
});
|
|
12001
|
-
continue;
|
|
12002
|
-
}
|
|
12003
|
-
keep.push(att);
|
|
12004
|
-
}
|
|
12005
|
-
if (buffers2.length === 0) return attachments;
|
|
12006
|
-
return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers2)];
|
|
12007
|
-
}
|
|
12008
|
-
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
12009
|
-
const out = [];
|
|
12010
|
-
for (const rel of relativePaths) {
|
|
12011
|
-
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
12012
|
-
out.push({
|
|
12013
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
12014
|
-
name: (0, import_node_path27.basename)(rel) || "file",
|
|
12015
|
-
kind: "file",
|
|
12016
|
-
content: `(invalid path: ${rel})`
|
|
12017
|
-
});
|
|
12018
|
-
continue;
|
|
12019
|
-
}
|
|
12020
|
-
const name = (0, import_node_path27.basename)(rel);
|
|
12021
|
-
try {
|
|
12022
|
-
const abs = (0, import_node_path27.join)(worktreePath, rel);
|
|
12023
|
-
const st = (0, import_node_fs23.statSync)(abs);
|
|
12024
|
-
if (!st.isFile()) continue;
|
|
12025
|
-
const buf = (0, import_node_fs23.readFileSync)(abs);
|
|
12026
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
12027
|
-
} catch (err) {
|
|
12028
|
-
out.push({
|
|
12029
|
-
id: (0, import_node_crypto10.randomUUID)(),
|
|
12030
|
-
name,
|
|
12031
|
-
kind: "file",
|
|
12032
|
-
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
12033
|
-
});
|
|
12034
|
-
}
|
|
12035
|
-
}
|
|
12036
|
-
return out;
|
|
12037
|
-
}
|
|
12038
|
-
var import_node_fs23, import_node_path27, import_node_crypto10, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
12039
|
-
var init_stage_files = __esm({
|
|
12040
|
-
"src/composer/stage-files.ts"() {
|
|
12041
|
-
"use strict";
|
|
12042
|
-
import_node_fs23 = require("fs");
|
|
12043
|
-
import_node_path27 = require("path");
|
|
12044
|
-
import_node_crypto10 = require("crypto");
|
|
12045
|
-
init_workspace_scratch();
|
|
12046
|
-
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
12047
|
-
"png",
|
|
12048
|
-
"jpg",
|
|
12049
|
-
"jpeg",
|
|
12050
|
-
"gif",
|
|
12051
|
-
"webp",
|
|
12052
|
-
"svg",
|
|
12053
|
-
"bmp",
|
|
12054
|
-
"ico"
|
|
12055
|
-
]);
|
|
12056
|
-
IMAGE_MIME_BY_EXT = {
|
|
12057
|
-
png: "image/png",
|
|
12058
|
-
jpg: "image/jpeg",
|
|
12059
|
-
jpeg: "image/jpeg",
|
|
12060
|
-
gif: "image/gif",
|
|
12061
|
-
webp: "image/webp",
|
|
12062
|
-
svg: "image/svg+xml",
|
|
12063
|
-
bmp: "image/bmp",
|
|
12064
|
-
ico: "image/x-icon"
|
|
12065
|
-
};
|
|
12066
|
-
MAX_INLINE_BYTES = 4e5;
|
|
12067
|
-
MAX_PREVIEW_BYTES = 5e6;
|
|
12068
|
-
IMAGE_HINT_RE = /^Image attached:/;
|
|
12069
|
-
PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
|
|
12070
|
-
}
|
|
12071
|
-
});
|
|
12072
|
-
|
|
12073
12132
|
// src/store/workspaces.ts
|
|
12074
12133
|
var workspaces_exports = {};
|
|
12075
12134
|
__export(workspaces_exports, {
|
|
@@ -12558,7 +12617,7 @@ var init_coordinator_prompt = __esm({
|
|
|
12558
12617
|
"- get_viewer_context / update_viewer_context \u2014 read or replace Settings \u2192 Agents (account) and Settings \u2192 Projects (per-repo) context. You can update a project: pass scope=project and repoPath from list_projects (this cwd is not a project). update_viewer_context requires confirmed=true after ask_user. Never write context unprompted.",
|
|
12559
12618
|
"- list_env / set_env / delete_env \u2014 Settings \u2192 Environment. scope=project requires repoPath from list_projects and stores the key under that project prefix (the project name, uppercased, plus _). APPLE_ID for sideboard is SIDEBOARD_APPLE_ID. scope=account is shared by every project and is not prefixed. list_env returns names only.",
|
|
12560
12619
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for phone remote / away-from-keyboard work, overnight schedules, or when the user will be away. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
12561
|
-
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014
|
|
12620
|
+
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 automations that send a prompt to a chat (chatId or self) or start a new Global chat (omit chatId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without chatId open a new chat each run and archive it when that run finishes (History keeps the latest run for that automation). Worktree agents have the same tools (`chatId=self` continues that coding chat). Jobs fire only while Sideboard.app is running; sleep skips until wake. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled (or call set_caffeinate). The desktop lists them in the sidebar after Board.",
|
|
12562
12621
|
"Projects:",
|
|
12563
12622
|
"- add_project / remove_project \u2014 register or unregister a git repo",
|
|
12564
12623
|
"Workspaces and chats:",
|
|
@@ -23328,6 +23387,77 @@ var init_steer_request = __esm({
|
|
|
23328
23387
|
}
|
|
23329
23388
|
});
|
|
23330
23389
|
|
|
23390
|
+
// src/orchestrator/ephemeral-automation.ts
|
|
23391
|
+
function ephemeralRunReadyToArchive(thread) {
|
|
23392
|
+
if (!thread.ephemeralAutomationId?.trim()) return false;
|
|
23393
|
+
if (thread.status !== "idle" && thread.status !== "error") return false;
|
|
23394
|
+
if (thread.queue.length > 0) return false;
|
|
23395
|
+
if (thread.agentBlock?.reason?.trim()) return false;
|
|
23396
|
+
if (thread.quotaResumeAt) return false;
|
|
23397
|
+
return true;
|
|
23398
|
+
}
|
|
23399
|
+
function markEphemeralAutomation(threadId, opts) {
|
|
23400
|
+
const id = opts.ephemeralAutomationId?.trim();
|
|
23401
|
+
const current = readThread(threadId);
|
|
23402
|
+
if (!current) throw new Error(`Thread not found: ${threadId}`);
|
|
23403
|
+
if (!id) return current;
|
|
23404
|
+
const title = opts.ephemeralTitle?.trim();
|
|
23405
|
+
return updateThread(threadId, {
|
|
23406
|
+
ephemeralAutomationId: id,
|
|
23407
|
+
...title ? { title, userSetTitle: true } : {}
|
|
23408
|
+
});
|
|
23409
|
+
}
|
|
23410
|
+
async function archiveEphemeralAutomationIfReady(threadId, archive) {
|
|
23411
|
+
const keep = await withThreadLock(threadId, async () => {
|
|
23412
|
+
const thread = readThread(threadId);
|
|
23413
|
+
if (!thread || !ephemeralRunReadyToArchive(thread)) return null;
|
|
23414
|
+
const automationId = thread.ephemeralAutomationId?.trim();
|
|
23415
|
+
if (!automationId) return null;
|
|
23416
|
+
await archive(thread.id);
|
|
23417
|
+
return {
|
|
23418
|
+
automationId,
|
|
23419
|
+
keepId: archivedContinuationId(automationId, threadId) ?? threadId
|
|
23420
|
+
};
|
|
23421
|
+
});
|
|
23422
|
+
if (keep) forgetOlderEphemeralRuns(keep.automationId, keep.keepId);
|
|
23423
|
+
}
|
|
23424
|
+
function archivedContinuationId(automationId, sourceId) {
|
|
23425
|
+
for (const thread of listThreads({ includeArchived: true })) {
|
|
23426
|
+
if (thread.id === sourceId || thread.status !== "archived") continue;
|
|
23427
|
+
if (thread.ephemeralAutomationId !== automationId) continue;
|
|
23428
|
+
if (thread.quotaContinuedFromId !== sourceId) continue;
|
|
23429
|
+
return thread.id;
|
|
23430
|
+
}
|
|
23431
|
+
return null;
|
|
23432
|
+
}
|
|
23433
|
+
function clearEphemeralAutomation(threadId) {
|
|
23434
|
+
const thread = readThread(threadId);
|
|
23435
|
+
if (!thread?.ephemeralAutomationId?.trim()) return;
|
|
23436
|
+
updateThread(threadId, { ephemeralAutomationId: void 0 });
|
|
23437
|
+
}
|
|
23438
|
+
function forgetOlderEphemeralRuns(automationId, keepId) {
|
|
23439
|
+
const id = automationId.trim();
|
|
23440
|
+
if (!id || !keepId) return [];
|
|
23441
|
+
const removed = [];
|
|
23442
|
+
for (const thread of listThreads({ includeArchived: true })) {
|
|
23443
|
+
if (thread.id === keepId) continue;
|
|
23444
|
+
if (thread.status !== "archived") continue;
|
|
23445
|
+
if (thread.ephemeralAutomationId !== id) continue;
|
|
23446
|
+
try {
|
|
23447
|
+
deleteThreadRecord(thread.id);
|
|
23448
|
+
removed.push(thread.id);
|
|
23449
|
+
} catch {
|
|
23450
|
+
}
|
|
23451
|
+
}
|
|
23452
|
+
return removed;
|
|
23453
|
+
}
|
|
23454
|
+
var init_ephemeral_automation = __esm({
|
|
23455
|
+
"src/orchestrator/ephemeral-automation.ts"() {
|
|
23456
|
+
"use strict";
|
|
23457
|
+
init_thread_store();
|
|
23458
|
+
}
|
|
23459
|
+
});
|
|
23460
|
+
|
|
23331
23461
|
// src/threads/title.ts
|
|
23332
23462
|
var title_exports = {};
|
|
23333
23463
|
__export(title_exports, {
|
|
@@ -24886,6 +25016,7 @@ var init_abletime_projects = __esm({
|
|
|
24886
25016
|
var abletime_exports = {};
|
|
24887
25017
|
__export(abletime_exports, {
|
|
24888
25018
|
ableTimeDependencyTarget: () => ableTimeDependencyTarget,
|
|
25019
|
+
ableTimeStateIsClosed: () => ableTimeStateIsClosed,
|
|
24889
25020
|
commentAbleTimeTask: () => commentAbleTimeTask,
|
|
24890
25021
|
createAbleTimeTask: () => createAbleTimeTask,
|
|
24891
25022
|
downloadAbleTimeAttachment: () => downloadAbleTimeAttachment,
|
|
@@ -25039,9 +25170,12 @@ function issueAttachmentForAbleTimeTask(task) {
|
|
|
25039
25170
|
].filter(Boolean).join("\n")
|
|
25040
25171
|
};
|
|
25041
25172
|
}
|
|
25173
|
+
function ableTimeStateIsClosed(state) {
|
|
25174
|
+
const value = (state ?? "").trim().toLowerCase();
|
|
25175
|
+
return Boolean(value && CLOSED_STATES.has(value));
|
|
25176
|
+
}
|
|
25042
25177
|
function isOpenTask(task) {
|
|
25043
|
-
|
|
25044
|
-
return !state || !CLOSED_STATES.has(state);
|
|
25178
|
+
return !ableTimeStateIsClosed(task.state);
|
|
25045
25179
|
}
|
|
25046
25180
|
async function getAbleTimeOrientation(opts) {
|
|
25047
25181
|
const raw = await callAbleTimeTool("orientation", {}, opts);
|
|
@@ -26292,17 +26426,23 @@ async function isolateQuotaFailover(run2) {
|
|
|
26292
26426
|
}
|
|
26293
26427
|
}
|
|
26294
26428
|
function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
|
|
26429
|
+
const ephemeralAutomationId = from.ephemeralAutomationId?.trim();
|
|
26430
|
+
const ephemeralTitle = ephemeralAutomationId ? from.title.trim() : "";
|
|
26295
26431
|
const handoff = buildQuotaHandoffAttachment(from, limitText, fallbackAgent);
|
|
26296
26432
|
const tab = createChatTab({
|
|
26297
26433
|
fromThreadId: from.id,
|
|
26298
26434
|
agent: fallbackAgent,
|
|
26299
26435
|
model: null,
|
|
26300
26436
|
attachments: [handoff],
|
|
26437
|
+
...ephemeralTitle ? { title: ephemeralTitle } : {},
|
|
26301
26438
|
...opts && "accountId" in opts ? { accountId: opts.accountId } : {}
|
|
26302
26439
|
});
|
|
26303
26440
|
const patch = {
|
|
26304
26441
|
quotaContinuedFromId: from.id,
|
|
26305
|
-
sourceRef: from.sourceRef
|
|
26442
|
+
sourceRef: from.sourceRef,
|
|
26443
|
+
// The original drain archives as idle. This sibling has to carry the one-off
|
|
26444
|
+
// so it archives when the continued turn finishes and History keeps it.
|
|
26445
|
+
...ephemeralAutomationId ? { ephemeralAutomationId } : {}
|
|
26306
26446
|
};
|
|
26307
26447
|
if (isOrchestratorThread(from)) {
|
|
26308
26448
|
patch.parentThreadId = from.id;
|
|
@@ -28329,6 +28469,41 @@ var init_expand = __esm({
|
|
|
28329
28469
|
}
|
|
28330
28470
|
});
|
|
28331
28471
|
|
|
28472
|
+
// src/composer/agent-has-replied.ts
|
|
28473
|
+
function joinSteerPrompt(base, addition) {
|
|
28474
|
+
const next = addition.trim();
|
|
28475
|
+
if (!next) return base;
|
|
28476
|
+
const head = base.replace(/\s+$/, "");
|
|
28477
|
+
if (!head) return next;
|
|
28478
|
+
return `${head}
|
|
28479
|
+
${next}`;
|
|
28480
|
+
}
|
|
28481
|
+
function trailingUnansweredUserText(messages) {
|
|
28482
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
28483
|
+
const message = messages[i];
|
|
28484
|
+
if (!message || message.origin === "continue" || message.role === "summary") continue;
|
|
28485
|
+
if (message.role === "agent") {
|
|
28486
|
+
const text7 = (message.text ?? "").trim();
|
|
28487
|
+
if (text7 || (message.parts?.length ?? 0) > 0) return null;
|
|
28488
|
+
continue;
|
|
28489
|
+
}
|
|
28490
|
+
if (message.role === "user") return message.text;
|
|
28491
|
+
}
|
|
28492
|
+
return null;
|
|
28493
|
+
}
|
|
28494
|
+
function livePartsShowAgentReply(parts) {
|
|
28495
|
+
for (const part of parts) {
|
|
28496
|
+
if (part.type === "tool") return true;
|
|
28497
|
+
if ((part.type === "text" || part.type === "thinking") && part.text.trim()) return true;
|
|
28498
|
+
}
|
|
28499
|
+
return false;
|
|
28500
|
+
}
|
|
28501
|
+
var init_agent_has_replied = __esm({
|
|
28502
|
+
"src/composer/agent-has-replied.ts"() {
|
|
28503
|
+
"use strict";
|
|
28504
|
+
}
|
|
28505
|
+
});
|
|
28506
|
+
|
|
28332
28507
|
// src/composer/consume-attachments.ts
|
|
28333
28508
|
function consumeComposerAttachments(thread) {
|
|
28334
28509
|
return {
|
|
@@ -28386,6 +28561,142 @@ var init_consume_attachments = __esm({
|
|
|
28386
28561
|
}
|
|
28387
28562
|
});
|
|
28388
28563
|
|
|
28564
|
+
// src/orchestrator/enqueue-thread-send.ts
|
|
28565
|
+
function resolveSendFollowUp(thread, requested) {
|
|
28566
|
+
if (requested === "steer" || requested === "queue") return requested;
|
|
28567
|
+
return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
|
|
28568
|
+
}
|
|
28569
|
+
function rewriteTrailingUserPrompt(threadId, from, to) {
|
|
28570
|
+
if (from === to) return;
|
|
28571
|
+
const thread = readThread(threadId);
|
|
28572
|
+
if (!thread) return;
|
|
28573
|
+
const messages = thread.messages.slice();
|
|
28574
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
28575
|
+
const message = messages[i];
|
|
28576
|
+
if (!message || message.origin === "continue" || message.role === "summary") continue;
|
|
28577
|
+
if (message.role === "user" && message.text === from) {
|
|
28578
|
+
messages[i] = { ...message, text: to };
|
|
28579
|
+
updateThread(threadId, { messages });
|
|
28580
|
+
}
|
|
28581
|
+
return;
|
|
28582
|
+
}
|
|
28583
|
+
}
|
|
28584
|
+
function reuseJoinedUserBubble(reused, threadId, last, promptText) {
|
|
28585
|
+
return reused.delete(threadId) && last?.role === "user" && last.origin !== "continue" && last.text === promptText;
|
|
28586
|
+
}
|
|
28587
|
+
function promptForJoinedSteer(input) {
|
|
28588
|
+
if (input.latestPrompt === input.promptText) return input.agentPrompt;
|
|
28589
|
+
rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
|
|
28590
|
+
const { agentPrompt: expandedLatest } = expandComposerPrompt(
|
|
28591
|
+
input.worktreePath,
|
|
28592
|
+
expandCanonicalGitRequest(input.latestPrompt),
|
|
28593
|
+
{ attachments: input.attachments }
|
|
28594
|
+
);
|
|
28595
|
+
return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
|
|
28596
|
+
|
|
28597
|
+
${expandedLatest}`;
|
|
28598
|
+
}
|
|
28599
|
+
function clearSendBookkeeping(host, threadId) {
|
|
28600
|
+
host.crashContinued.delete(threadId);
|
|
28601
|
+
host.jobContinueCount.delete(threadId);
|
|
28602
|
+
host.jobContinueNudged.delete(threadId);
|
|
28603
|
+
host.haltDrain.delete(threadId);
|
|
28604
|
+
}
|
|
28605
|
+
async function enqueueThreadSend(host, threadRef, prompt, opts) {
|
|
28606
|
+
const thread = host.requireThread(threadRef);
|
|
28607
|
+
if (thread.status === "archived") {
|
|
28608
|
+
throw new Error(`Thread is archived: ${thread.id}`);
|
|
28609
|
+
}
|
|
28610
|
+
let shouldSteer = false;
|
|
28611
|
+
const sent = await withThreadLock(thread.id, async () => {
|
|
28612
|
+
const current = host.requireThread(thread.id);
|
|
28613
|
+
if (current.status === "archived") {
|
|
28614
|
+
throw new Error(`Thread is archived: ${thread.id}`);
|
|
28615
|
+
}
|
|
28616
|
+
const followUp = resolveSendFollowUp(current, opts?.followUp);
|
|
28617
|
+
const explicit = opts?.attachments;
|
|
28618
|
+
const consumed = explicit !== void 0 ? { attachments: current.attachments, consumed: explicit } : consumeComposerAttachments(current);
|
|
28619
|
+
const inFlightEarly = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
|
|
28620
|
+
const agentHasRepliedEarly = livePartsShowAgentReply(readTurnLiveParts(current.id));
|
|
28621
|
+
const draft = host.openSteerPrompt.get(current.id);
|
|
28622
|
+
const queuedHead = !inFlightEarly && current.status === "queued" && current.queue.length > 0 ? current.queue[0] : null;
|
|
28623
|
+
const unanswered = followUp === "steer" && !agentHasRepliedEarly ? draft?.text ?? (inFlightEarly ? trailingUnansweredUserText(current.messages) : queuedHead) : null;
|
|
28624
|
+
if (unanswered != null && (draft ? !draft.spawned : queuedHead != null)) {
|
|
28625
|
+
clearSendBookkeeping(host, thread.id);
|
|
28626
|
+
const combined = joinSteerPrompt(unanswered, prompt);
|
|
28627
|
+
if (draft && !draft.spawned) {
|
|
28628
|
+
draft.text = combined;
|
|
28629
|
+
rewriteTrailingUserPrompt(current.id, unanswered, combined);
|
|
28630
|
+
} else {
|
|
28631
|
+
const queue = current.queue.slice();
|
|
28632
|
+
queue[0] = combined;
|
|
28633
|
+
const queueAttachments = alignQueueAttachments(queue.length, current.queueAttachments);
|
|
28634
|
+
if (consumed.consumed.length > 0) {
|
|
28635
|
+
queueAttachments[0] = [...queueAttachments[0] ?? [], ...consumed.consumed];
|
|
28636
|
+
}
|
|
28637
|
+
const patch2 = { queue, queueAttachments };
|
|
28638
|
+
if (explicit === void 0 && consumed.consumed.length > 0) {
|
|
28639
|
+
patch2.attachments = consumed.attachments;
|
|
28640
|
+
}
|
|
28641
|
+
updateThread(current.id, patch2);
|
|
28642
|
+
host.emit({ type: "queue_changed", threadId: current.id, queue });
|
|
28643
|
+
}
|
|
28644
|
+
if (thisProcessShouldDrainAgentQueues() && !inFlightEarly) {
|
|
28645
|
+
host.armDrain(current.id);
|
|
28646
|
+
}
|
|
28647
|
+
return host.requireThread(current.id);
|
|
28648
|
+
}
|
|
28649
|
+
const promptToQueue = unanswered != null ? joinSteerPrompt(unanswered, prompt) : prompt;
|
|
28650
|
+
if (unanswered != null) {
|
|
28651
|
+
if (draft) draft.text = promptToQueue;
|
|
28652
|
+
rewriteTrailingUserPrompt(current.id, unanswered, promptToQueue);
|
|
28653
|
+
host.reusedUserPrompt.add(current.id);
|
|
28654
|
+
}
|
|
28655
|
+
const queued = appendQueuedItem(
|
|
28656
|
+
current.queue,
|
|
28657
|
+
current.queueAttachments,
|
|
28658
|
+
promptToQueue,
|
|
28659
|
+
consumed.consumed
|
|
28660
|
+
);
|
|
28661
|
+
clearSendBookkeeping(host, thread.id);
|
|
28662
|
+
const inFlight = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
|
|
28663
|
+
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
28664
|
+
const patch = queued;
|
|
28665
|
+
if (explicit === void 0 && consumed.consumed.length > 0) {
|
|
28666
|
+
patch.attachments = consumed.attachments;
|
|
28667
|
+
}
|
|
28668
|
+
if (!inFlight) patch.status = "queued";
|
|
28669
|
+
const pid = current.agentPid;
|
|
28670
|
+
if (typeof pid === "number" && pid > 0 && !host.pidAlive(pid)) {
|
|
28671
|
+
patch.agentPid = null;
|
|
28672
|
+
}
|
|
28673
|
+
updateThread(thread.id, patch);
|
|
28674
|
+
host.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
|
|
28675
|
+
if (!inFlight) {
|
|
28676
|
+
host.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
28677
|
+
}
|
|
28678
|
+
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
28679
|
+
host.armDrain(thread.id);
|
|
28680
|
+
}
|
|
28681
|
+
return host.requireThread(thread.id);
|
|
28682
|
+
});
|
|
28683
|
+
return { thread: sent, shouldSteer };
|
|
28684
|
+
}
|
|
28685
|
+
var init_enqueue_thread_send = __esm({
|
|
28686
|
+
"src/orchestrator/enqueue-thread-send.ts"() {
|
|
28687
|
+
"use strict";
|
|
28688
|
+
init_agent_git_actions();
|
|
28689
|
+
init_agent_has_replied();
|
|
28690
|
+
init_expand();
|
|
28691
|
+
init_consume_attachments();
|
|
28692
|
+
init_desktop_host();
|
|
28693
|
+
init_thread_store();
|
|
28694
|
+
init_turn_live();
|
|
28695
|
+
init_app_settings();
|
|
28696
|
+
init_global_workspace();
|
|
28697
|
+
}
|
|
28698
|
+
});
|
|
28699
|
+
|
|
28389
28700
|
// src/skills/detached-job-path.ts
|
|
28390
28701
|
function compiledModuleDir() {
|
|
28391
28702
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
@@ -28548,7 +28859,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
28548
28859
|
lines.push(formatDevAccessHint(opts?.activeRuns));
|
|
28549
28860
|
lines.push("");
|
|
28550
28861
|
lines.push(
|
|
28551
|
-
"
|
|
28862
|
+
"Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `chatId=self` continues this chat; omit chatId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled."
|
|
28552
28863
|
);
|
|
28553
28864
|
lines.push(
|
|
28554
28865
|
"`set_workspace_tags` labels this checkout (omit ref; replace, add, or remove). Not another checkout."
|
|
@@ -28568,7 +28879,7 @@ function connectedOrchestratorTurnReminder(thread, find) {
|
|
|
28568
28879
|
return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
|
|
28569
28880
|
}
|
|
28570
28881
|
function formatWorktreeReminder() {
|
|
28571
|
-
return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push.
|
|
28882
|
+
return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push. Automations: create_schedule (at / every / cron; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
|
|
28572
28883
|
}
|
|
28573
28884
|
function formatClaudeSubagentReminder() {
|
|
28574
28885
|
return 'Claude subagents: if Task/Agent workers will edit files, write a short plan in this chat and continue in the same turn. Do not ask the user whether to isolate, and do not set worktree.bgIsolation to none. One writer may edit this workspace. Every other writer is an Agent with isolation "worktree" and a disjoint file list (read-only explore agents may overlap). While those agents run, leave their files alone. Merge each returned branch into this workspace, then remove the temporary worktree. You stay in this cwd. If Claude says another write-capable agent is in this directory, or that writes to the shared checkout are blocked, re-spawn that agent with isolation "worktree" or make the edit yourself. That note is another worker in this chat, or a worker Claude still has marked running. Do not mention it to the user.';
|
|
@@ -29756,10 +30067,6 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
29756
30067
|
}
|
|
29757
30068
|
return true;
|
|
29758
30069
|
}
|
|
29759
|
-
function resolveSendFollowUp(thread, requested) {
|
|
29760
|
-
if (requested === "steer" || requested === "queue") return requested;
|
|
29761
|
-
return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
|
|
29762
|
-
}
|
|
29763
30070
|
function resolveOrchChildFollowUp(requested) {
|
|
29764
30071
|
if (requested === "steer" || requested === "queue") return requested;
|
|
29765
30072
|
return followUpBehavior();
|
|
@@ -29800,10 +30107,11 @@ async function startOrchestration(opts) {
|
|
|
29800
30107
|
planMode: opts.planMode,
|
|
29801
30108
|
attachments: opts.attachments
|
|
29802
30109
|
});
|
|
30110
|
+
const ready2 = markEphemeralAutomation(thread2.id, opts);
|
|
29803
30111
|
if (goal) {
|
|
29804
|
-
return orch.send(
|
|
30112
|
+
return orch.send(ready2.id, goal);
|
|
29805
30113
|
}
|
|
29806
|
-
return
|
|
30114
|
+
return ready2;
|
|
29807
30115
|
}
|
|
29808
30116
|
const { titleFromPrompt: titleFromPrompt2 } = await Promise.resolve().then(() => (init_title(), title_exports));
|
|
29809
30117
|
const title = titleFromPrompt2(goal) || "Orchestration";
|
|
@@ -29838,10 +30146,11 @@ async function startOrchestration(opts) {
|
|
|
29838
30146
|
sourceType: "orchestration",
|
|
29839
30147
|
sourceRef: goal
|
|
29840
30148
|
});
|
|
30149
|
+
const ready = markEphemeralAutomation(updated.id, opts);
|
|
29841
30150
|
if (goal) {
|
|
29842
|
-
return orch.send(
|
|
30151
|
+
return orch.send(ready.id, goal);
|
|
29843
30152
|
}
|
|
29844
|
-
return
|
|
30153
|
+
return ready;
|
|
29845
30154
|
}
|
|
29846
30155
|
var import_node_events, import_node_crypto19, import_node_fs67, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton2;
|
|
29847
30156
|
var init_orchestrator = __esm({
|
|
@@ -29882,6 +30191,7 @@ var init_orchestrator = __esm({
|
|
|
29882
30191
|
init_child_halt();
|
|
29883
30192
|
init_stop_reason();
|
|
29884
30193
|
init_steer_request();
|
|
30194
|
+
init_ephemeral_automation();
|
|
29885
30195
|
init_wait_for_job();
|
|
29886
30196
|
init_agent_purpose_title();
|
|
29887
30197
|
init_create();
|
|
@@ -29909,6 +30219,7 @@ var init_orchestrator = __esm({
|
|
|
29909
30219
|
init_read_worktree_tail();
|
|
29910
30220
|
init_discover();
|
|
29911
30221
|
init_expand();
|
|
30222
|
+
init_enqueue_thread_send();
|
|
29912
30223
|
init_consume_attachments();
|
|
29913
30224
|
init_stage_files();
|
|
29914
30225
|
init_context_compact();
|
|
@@ -29926,6 +30237,7 @@ var init_orchestrator = __esm({
|
|
|
29926
30237
|
init_caffeinate_hold();
|
|
29927
30238
|
init_schedule_runner();
|
|
29928
30239
|
init_coordinator_prompt();
|
|
30240
|
+
init_enqueue_thread_send();
|
|
29929
30241
|
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
29930
30242
|
RUN_SCRIPT_DESKTOP_ADOPT_MS = 2e4;
|
|
29931
30243
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
@@ -29937,6 +30249,13 @@ var init_orchestrator = __esm({
|
|
|
29937
30249
|
draining = /* @__PURE__ */ new Set();
|
|
29938
30250
|
/** Threads past setStatus(running) but not yet in activeTurns (spawn in flight). */
|
|
29939
30251
|
startingTurns = /* @__PURE__ */ new Set();
|
|
30252
|
+
/**
|
|
30253
|
+
* Prompt for the turn that has not been answered yet. Steer follow-ups before
|
|
30254
|
+
* any agent output are joined onto this text instead of starting a second bubble.
|
|
30255
|
+
*/
|
|
30256
|
+
openSteerPrompt = /* @__PURE__ */ new Map();
|
|
30257
|
+
/** Next runTurn should keep the user bubble already rewritten to this prompt. */
|
|
30258
|
+
reusedUserPrompt = /* @__PURE__ */ new Set();
|
|
29940
30259
|
/** Last sync thread-file read for false-stop heal (throttled per thread). */
|
|
29941
30260
|
lastReconcileHealAt = /* @__PURE__ */ new Map();
|
|
29942
30261
|
/** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
|
|
@@ -30547,54 +30866,29 @@ var init_orchestrator = __esm({
|
|
|
30547
30866
|
return thread;
|
|
30548
30867
|
}
|
|
30549
30868
|
async send(threadRef, prompt, opts) {
|
|
30550
|
-
const
|
|
30551
|
-
|
|
30552
|
-
|
|
30553
|
-
|
|
30554
|
-
|
|
30555
|
-
|
|
30556
|
-
|
|
30557
|
-
|
|
30558
|
-
|
|
30559
|
-
|
|
30560
|
-
|
|
30561
|
-
|
|
30562
|
-
|
|
30563
|
-
|
|
30564
|
-
|
|
30565
|
-
|
|
30566
|
-
|
|
30567
|
-
|
|
30568
|
-
|
|
30569
|
-
|
|
30570
|
-
this.
|
|
30571
|
-
this.jobContinueNudged.delete(thread.id);
|
|
30572
|
-
this.haltDrain.delete(thread.id);
|
|
30573
|
-
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
30574
|
-
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
30575
|
-
const patch = queued;
|
|
30576
|
-
if (explicit === void 0 && consumed.consumed.length > 0) {
|
|
30577
|
-
patch.attachments = consumed.attachments;
|
|
30578
|
-
}
|
|
30579
|
-
if (!inFlight) patch.status = "queued";
|
|
30580
|
-
const pid = current.agentPid;
|
|
30581
|
-
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
30582
|
-
patch.agentPid = null;
|
|
30583
|
-
}
|
|
30584
|
-
updateThread(thread.id, patch);
|
|
30585
|
-
this.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
|
|
30586
|
-
if (!inFlight) {
|
|
30587
|
-
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
30588
|
-
}
|
|
30589
|
-
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
30590
|
-
this.armDrain(thread.id);
|
|
30591
|
-
}
|
|
30592
|
-
return this.requireThread(thread.id);
|
|
30593
|
-
});
|
|
30594
|
-
if (shouldSteer && sent.queue.length > 0) {
|
|
30595
|
-
return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
|
|
30869
|
+
const sent = await enqueueThreadSend(
|
|
30870
|
+
{
|
|
30871
|
+
activeTurns: this.activeTurns,
|
|
30872
|
+
startingTurns: this.startingTurns,
|
|
30873
|
+
openSteerPrompt: this.openSteerPrompt,
|
|
30874
|
+
reusedUserPrompt: this.reusedUserPrompt,
|
|
30875
|
+
crashContinued: this.crashContinued,
|
|
30876
|
+
jobContinueCount: this.jobContinueCount,
|
|
30877
|
+
jobContinueNudged: this.jobContinueNudged,
|
|
30878
|
+
haltDrain: this.haltDrain,
|
|
30879
|
+
emit: (event) => this.emit(event),
|
|
30880
|
+
armDrain: (id) => this.armDrain(id),
|
|
30881
|
+
requireThread: (ref) => this.requireThread(ref),
|
|
30882
|
+
pidAlive: (pid) => isPidAlive(pid)
|
|
30883
|
+
},
|
|
30884
|
+
threadRef,
|
|
30885
|
+
prompt,
|
|
30886
|
+
opts
|
|
30887
|
+
);
|
|
30888
|
+
if (sent.shouldSteer && sent.thread.queue.length > 0) {
|
|
30889
|
+
return this.sendQueuedMessageNow(sent.thread.id, sent.thread.queue.length - 1);
|
|
30596
30890
|
}
|
|
30597
|
-
return sent;
|
|
30891
|
+
return sent.thread;
|
|
30598
30892
|
}
|
|
30599
30893
|
async fanOut(threadRefs, prompt, opts) {
|
|
30600
30894
|
const results = [];
|
|
@@ -30735,6 +31029,7 @@ var init_orchestrator = __esm({
|
|
|
30735
31029
|
} finally {
|
|
30736
31030
|
this.draining.delete(threadId);
|
|
30737
31031
|
}
|
|
31032
|
+
await archiveEphemeralAutomationIfReady(threadId, (id) => this.archive(id));
|
|
30738
31033
|
}
|
|
30739
31034
|
async runTurn(threadId, prompt) {
|
|
30740
31035
|
const existing = readThread(threadId);
|
|
@@ -30751,6 +31046,10 @@ var init_orchestrator = __esm({
|
|
|
30751
31046
|
this.emit({ type: "status_changed", threadId, status: "running" });
|
|
30752
31047
|
this.emit({ type: "turn_started", threadId, prompt });
|
|
30753
31048
|
try {
|
|
31049
|
+
this.openSteerPrompt.set(threadId, {
|
|
31050
|
+
text: typeof prompt === "string" ? prompt : "",
|
|
31051
|
+
spawned: false
|
|
31052
|
+
});
|
|
30754
31053
|
try {
|
|
30755
31054
|
const baseline = await captureTurnBaseline(thread.worktreePath);
|
|
30756
31055
|
if (baseline) this.turnBaselines.set(threadId, baseline);
|
|
@@ -30776,18 +31075,21 @@ var init_orchestrator = __esm({
|
|
|
30776
31075
|
this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
|
|
30777
31076
|
thread = this.requireThread(threadId);
|
|
30778
31077
|
}
|
|
30779
|
-
const promptText = typeof prompt === "string" ? prompt : "";
|
|
31078
|
+
const promptText = this.openSteerPrompt.get(threadId)?.text ?? (typeof prompt === "string" ? prompt : "");
|
|
30780
31079
|
const autoContinue = isJobContinuePrompt(promptText) || promptText.startsWith("The previous agent process ended before it finished.");
|
|
30781
31080
|
const parked = takePendingTurnAttachments(thread);
|
|
30782
31081
|
const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
|
|
30783
31082
|
if (!autoContinue) clearAgentBlock(threadId);
|
|
30784
|
-
|
|
30785
|
-
|
|
30786
|
-
|
|
30787
|
-
|
|
30788
|
-
|
|
30789
|
-
|
|
30790
|
-
|
|
31083
|
+
const lastShown = this.requireThread(threadId).messages.at(-1);
|
|
31084
|
+
if (!reuseJoinedUserBubble(this.reusedUserPrompt, threadId, lastShown, promptText)) {
|
|
31085
|
+
appendMessage(threadId, {
|
|
31086
|
+
role: "user",
|
|
31087
|
+
text: promptText,
|
|
31088
|
+
...sentAttachments ? { attachments: sentAttachments } : {},
|
|
31089
|
+
...autoContinue ? { origin: "continue" } : {},
|
|
31090
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
31091
|
+
});
|
|
31092
|
+
}
|
|
30791
31093
|
if (!autoContinue) {
|
|
30792
31094
|
const live = this.requireThread(threadId);
|
|
30793
31095
|
const stamp = agentPurposeStamp({
|
|
@@ -30986,11 +31288,22 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
30986
31288
|
].filter(Boolean).join("\n\n---\n\n");
|
|
30987
31289
|
const stderrTail = [];
|
|
30988
31290
|
traceTurn("runTurn.beforeSpawn", { threadId, agent: fresh.agent });
|
|
31291
|
+
const steerDraft = this.openSteerPrompt.get(threadId);
|
|
31292
|
+
if (steerDraft) steerDraft.spawned = true;
|
|
31293
|
+
const promptForAgent = promptForJoinedSteer({
|
|
31294
|
+
threadId,
|
|
31295
|
+
promptText,
|
|
31296
|
+
latestPrompt: steerDraft?.text ?? promptText,
|
|
31297
|
+
agentPrompt,
|
|
31298
|
+
expandedPrompt,
|
|
31299
|
+
worktreePath: fresh.worktreePath,
|
|
31300
|
+
attachments: autoContinue ? [] : sentAttachments ?? []
|
|
31301
|
+
});
|
|
30989
31302
|
const handle = await spawnAgentTurn(
|
|
30990
31303
|
fresh,
|
|
30991
31304
|
{
|
|
30992
31305
|
cachedPrefix,
|
|
30993
|
-
prompt:
|
|
31306
|
+
prompt: promptForAgent,
|
|
30994
31307
|
systemPrompt: turnReminders,
|
|
30995
31308
|
isolateCodexPlugins: fresh.isolateCodexPlugins === true
|
|
30996
31309
|
},
|
|
@@ -31118,7 +31431,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
31118
31431
|
retryThread,
|
|
31119
31432
|
{
|
|
31120
31433
|
cachedPrefix: retryPrefix,
|
|
31121
|
-
prompt:
|
|
31434
|
+
prompt: promptForAgent,
|
|
31122
31435
|
systemPrompt: turnReminders,
|
|
31123
31436
|
isolateCodexPlugins: isolateCodexPluginRetry || retryThread.isolateCodexPlugins === true
|
|
31124
31437
|
},
|
|
@@ -31278,6 +31591,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
31278
31591
|
} finally {
|
|
31279
31592
|
this.startingTurns.delete(threadId);
|
|
31280
31593
|
this.activeTurns.delete(threadId);
|
|
31594
|
+
this.openSteerPrompt.delete(threadId);
|
|
31281
31595
|
this.processes.delete(`${threadId}:agent`);
|
|
31282
31596
|
this.stoppedTurns.delete(threadId);
|
|
31283
31597
|
this.runningCount = Math.max(0, this.runningCount - 1);
|
|
@@ -31954,7 +32268,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
31954
32268
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
31955
32269
|
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
31956
32270
|
const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
31957
|
-
const
|
|
32271
|
+
const taskState2 = deriveTaskState({
|
|
31958
32272
|
status: thread.status,
|
|
31959
32273
|
stillRunning,
|
|
31960
32274
|
lastAgentParts: lastAgent?.parts
|
|
@@ -31963,7 +32277,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
31963
32277
|
return {
|
|
31964
32278
|
text: text7,
|
|
31965
32279
|
status: thread.status,
|
|
31966
|
-
taskState,
|
|
32280
|
+
taskState: taskState2,
|
|
31967
32281
|
sessionId: thread.sessionId,
|
|
31968
32282
|
lastError,
|
|
31969
32283
|
stillRunning,
|
|
@@ -32549,6 +32863,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
32549
32863
|
if (thread.status !== "archived") {
|
|
32550
32864
|
throw new Error("Thread is not archived");
|
|
32551
32865
|
}
|
|
32866
|
+
clearEphemeralAutomation(thread.id);
|
|
32552
32867
|
if (isGlobalThread(thread)) {
|
|
32553
32868
|
const { globalAgentCwd: globalAgentCwd2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
32554
32869
|
updateThread(thread.id, { worktreePath: globalAgentCwd2() });
|
|
@@ -32640,17 +32955,52 @@ async function defaultDeps() {
|
|
|
32640
32955
|
const orch = getOrchestrator2();
|
|
32641
32956
|
return {
|
|
32642
32957
|
findThread: (id) => findThreadByRef(id),
|
|
32643
|
-
send: (id, prompt) =>
|
|
32958
|
+
send: async (id, prompt, opts) => {
|
|
32959
|
+
if (opts?.options && Object.keys(opts.options).length > 0) {
|
|
32960
|
+
try {
|
|
32961
|
+
orch.setThreadOptions(id, opts.options);
|
|
32962
|
+
} catch {
|
|
32963
|
+
const rest = scheduleOptionsAfterRefusedAgentSwitch(opts.options);
|
|
32964
|
+
if (Object.keys(rest).length > 0) {
|
|
32965
|
+
try {
|
|
32966
|
+
orch.setThreadOptions(id, rest);
|
|
32967
|
+
} catch {
|
|
32968
|
+
}
|
|
32969
|
+
}
|
|
32970
|
+
}
|
|
32971
|
+
}
|
|
32972
|
+
const thread = findThreadByRef(id);
|
|
32973
|
+
const attachments = thread ? persistPendingFileAttachments(thread.worktreePath, opts?.attachments ?? []) : opts?.attachments ?? [];
|
|
32974
|
+
return orch.send(id, prompt, { attachments });
|
|
32975
|
+
},
|
|
32644
32976
|
startOrchestration: (opts) => startOrchestration2(opts)
|
|
32645
32977
|
};
|
|
32646
32978
|
}
|
|
32979
|
+
function scheduleOptionsAfterRefusedAgentSwitch(options) {
|
|
32980
|
+
const { agent: _agent, model: _model, ...rest } = options;
|
|
32981
|
+
return rest;
|
|
32982
|
+
}
|
|
32983
|
+
function scheduleSendOptions(schedule) {
|
|
32984
|
+
const patch = {};
|
|
32985
|
+
if (schedule.agent) {
|
|
32986
|
+
patch.agent = schedule.agent;
|
|
32987
|
+
patch.model = schedule.model;
|
|
32988
|
+
} else if (schedule.model) {
|
|
32989
|
+
patch.model = schedule.model;
|
|
32990
|
+
}
|
|
32991
|
+
if (schedule.effort) patch.effort = schedule.effort;
|
|
32992
|
+
if (schedule.fast != null) patch.fast = schedule.fast;
|
|
32993
|
+
if (schedule.planMode != null) patch.planMode = schedule.planMode;
|
|
32994
|
+
if (schedule.autonomy) patch.autonomy = schedule.autonomy;
|
|
32995
|
+
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
32996
|
+
}
|
|
32647
32997
|
function pickAgent(schedule) {
|
|
32648
32998
|
if (schedule.agent) return schedule.agent;
|
|
32649
32999
|
return coerceOrchestratorAgent(resolveOrchestratorDefaults().agent);
|
|
32650
33000
|
}
|
|
32651
33001
|
async function fireSchedule(id) {
|
|
32652
33002
|
const schedule = getSchedule(id);
|
|
32653
|
-
if (!schedule) throw new Error(`
|
|
33003
|
+
if (!schedule) throw new Error(`Automation not found: ${id}`);
|
|
32654
33004
|
if (firing.has(schedule.id)) return schedule;
|
|
32655
33005
|
firing.add(schedule.id);
|
|
32656
33006
|
try {
|
|
@@ -32658,18 +33008,28 @@ async function fireSchedule(id) {
|
|
|
32658
33008
|
const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
|
|
32659
33009
|
const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
|
|
32660
33010
|
if (target && target.status !== "archived") {
|
|
32661
|
-
const sent = await deps.send(target.id, prompt
|
|
33011
|
+
const sent = await deps.send(target.id, prompt, {
|
|
33012
|
+
attachments: schedule.attachments,
|
|
33013
|
+
options: scheduleSendOptions(schedule)
|
|
33014
|
+
});
|
|
32662
33015
|
return recordScheduleRun(schedule.id, {
|
|
32663
33016
|
lastThreadId: sent.id,
|
|
32664
33017
|
lastError: null
|
|
32665
33018
|
});
|
|
32666
33019
|
}
|
|
33020
|
+
const pinReplacement = Boolean(schedule.threadId) && schedule.when.kind !== "once";
|
|
32667
33021
|
const created = await deps.startOrchestration({
|
|
32668
33022
|
goal: prompt,
|
|
32669
33023
|
agent: pickAgent(schedule),
|
|
32670
|
-
model: schedule.model
|
|
33024
|
+
model: schedule.model,
|
|
33025
|
+
...schedule.effort ? { effort: schedule.effort } : {},
|
|
33026
|
+
...schedule.fast != null ? { fast: schedule.fast } : {},
|
|
33027
|
+
...schedule.planMode != null ? { planMode: schedule.planMode } : {},
|
|
33028
|
+
...schedule.autonomy ? { autonomy: schedule.autonomy } : {},
|
|
33029
|
+
attachments: schedule.attachments,
|
|
33030
|
+
...pinReplacement ? {} : { ephemeralAutomationId: schedule.id, ephemeralTitle: schedule.name }
|
|
32671
33031
|
});
|
|
32672
|
-
if (
|
|
33032
|
+
if (pinReplacement) {
|
|
32673
33033
|
updateSchedule(schedule.id, { threadId: created.id });
|
|
32674
33034
|
}
|
|
32675
33035
|
return recordScheduleRun(schedule.id, {
|
|
@@ -32739,6 +33099,7 @@ var init_schedule_runner = __esm({
|
|
|
32739
33099
|
init_desktop_host();
|
|
32740
33100
|
init_app_settings();
|
|
32741
33101
|
init_schedules();
|
|
33102
|
+
init_stage_files();
|
|
32742
33103
|
init_thread_store();
|
|
32743
33104
|
SET_TIMEOUT_MAX = 2147483647;
|
|
32744
33105
|
fireHooks = null;
|
|
@@ -32907,6 +33268,7 @@ __export(index_exports, {
|
|
|
32907
33268
|
ableTimeOAuthLocalBounceUrl: () => ableTimeOAuthLocalBounceUrl,
|
|
32908
33269
|
ableTimeOAuthRedirectUri: () => ableTimeOAuthRedirectUri,
|
|
32909
33270
|
ableTimeOAuthResource: () => ableTimeOAuthResource,
|
|
33271
|
+
ableTimeStateIsClosed: () => ableTimeStateIsClosed,
|
|
32910
33272
|
ableTimeUsesRest: () => ableTimeUsesRest,
|
|
32911
33273
|
abletimeMcpRequest: () => abletimeMcpRequest,
|
|
32912
33274
|
abletimeMcpUrl: () => abletimeMcpUrl,
|
|
@@ -33389,6 +33751,7 @@ __export(index_exports, {
|
|
|
33389
33751
|
issueMatchesAssignee: () => issueMatchesAssignee,
|
|
33390
33752
|
issueSourceLabel: () => issueSourceLabel,
|
|
33391
33753
|
issueTicketFromThread: () => issueTicketFromThread,
|
|
33754
|
+
joinSteerPrompt: () => joinSteerPrompt,
|
|
33392
33755
|
killDetachedRunTree: () => killDetachedRunTree,
|
|
33393
33756
|
killListenersOnPorts: () => killListenersOnPorts,
|
|
33394
33757
|
killStaleWorktreeListeners: () => killStaleWorktreeListeners,
|
|
@@ -33447,6 +33810,7 @@ __export(index_exports, {
|
|
|
33447
33810
|
listWorktrees: () => listWorktrees,
|
|
33448
33811
|
listenerCwd: () => listenerCwd,
|
|
33449
33812
|
liveActivitySummary: () => liveActivitySummary,
|
|
33813
|
+
livePartsShowAgentReply: () => livePartsShowAgentReply,
|
|
33450
33814
|
loadAppSettings: () => loadAppSettings,
|
|
33451
33815
|
loadBrightsyConfig: () => loadBrightsyConfig,
|
|
33452
33816
|
loadConductorSettings: () => loadConductorSettings,
|
|
@@ -33784,6 +34148,7 @@ __export(index_exports, {
|
|
|
33784
34148
|
toolDetail: () => toolDetail,
|
|
33785
34149
|
toolFilePath: () => toolFilePath,
|
|
33786
34150
|
totalTokens: () => totalTokens,
|
|
34151
|
+
trailingUnansweredUserText: () => trailingUnansweredUserText,
|
|
33787
34152
|
trustSystemCertificates: () => trustSystemCertificates,
|
|
33788
34153
|
tryReservePort: () => tryReservePort,
|
|
33789
34154
|
tryReservePorts: () => tryReservePorts,
|
|
@@ -41754,6 +42119,7 @@ init_discover();
|
|
|
41754
42119
|
init_detached_job_path();
|
|
41755
42120
|
init_long_running();
|
|
41756
42121
|
init_expand();
|
|
42122
|
+
init_agent_has_replied();
|
|
41757
42123
|
|
|
41758
42124
|
// src/composer/diff-comment.ts
|
|
41759
42125
|
function lineRangeLabel(lines) {
|
|
@@ -43460,7 +43826,7 @@ function parseWhen(args) {
|
|
|
43460
43826
|
function registerScheduleTools(server) {
|
|
43461
43827
|
server.tool(
|
|
43462
43828
|
"list_schedules",
|
|
43463
|
-
"List local Sideboard
|
|
43829
|
+
"List local Sideboard automations that trigger a chat when due. Jobs fire only while Sideboard.app is running on this Mac (sleep skips until wake). Shown in the sidebar after Board.",
|
|
43464
43830
|
{},
|
|
43465
43831
|
async () => {
|
|
43466
43832
|
try {
|
|
@@ -43472,9 +43838,9 @@ function registerScheduleTools(server) {
|
|
|
43472
43838
|
);
|
|
43473
43839
|
server.tool(
|
|
43474
43840
|
"create_schedule",
|
|
43475
|
-
"Create a local
|
|
43841
|
+
"Create a local automation that, when due, sends a prompt to an existing chat (chatId) or starts a new Global orchestration chat (omit chatId). Pass chatId=self to continue this chat. If that chat is missing or archived when the job fires, Sideboard starts a new Global chat (recurring jobs then continue that chat). Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without chatId open a new Global chat each run and archive it when that run finishes. History keeps the latest run for that automation. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled so the Mac stays awake until due. Sideboard.app must be running for the job to fire.",
|
|
43476
43842
|
{
|
|
43477
|
-
prompt: import_zod10.z.string().describe("User message / goal queued when the
|
|
43843
|
+
prompt: import_zod10.z.string().describe("User message / goal queued when the automation fires"),
|
|
43478
43844
|
name: import_zod10.z.string().optional(),
|
|
43479
43845
|
at: import_zod10.z.string().optional().describe("ISO datetime for a one-shot"),
|
|
43480
43846
|
every: import_zod10.z.string().optional().describe("Interval such as 15m, 1h, 6h, 1d"),
|
|
@@ -43510,7 +43876,7 @@ function registerScheduleTools(server) {
|
|
|
43510
43876
|
});
|
|
43511
43877
|
return text6({
|
|
43512
43878
|
schedule,
|
|
43513
|
-
hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run. Caffeinate while
|
|
43879
|
+
hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run and archive it when that run finishes (History keeps the latest). Caffeinate while automations are enabled is now on so the Mac can stay awake until this job is due." : "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run and archive it when that run finishes (History keeps the latest)."
|
|
43514
43880
|
});
|
|
43515
43881
|
} catch (err) {
|
|
43516
43882
|
return fail4(err);
|
|
@@ -43519,7 +43885,7 @@ function registerScheduleTools(server) {
|
|
|
43519
43885
|
);
|
|
43520
43886
|
server.tool(
|
|
43521
43887
|
"update_schedule",
|
|
43522
|
-
"Update a local
|
|
43888
|
+
"Update a local automation (prompt, cadence, target chat, enabled). Pass id from list_schedules.",
|
|
43523
43889
|
{
|
|
43524
43890
|
id: import_zod10.z.string(),
|
|
43525
43891
|
prompt: import_zod10.z.string().optional(),
|
|
@@ -43574,7 +43940,7 @@ function registerScheduleTools(server) {
|
|
|
43574
43940
|
);
|
|
43575
43941
|
server.tool(
|
|
43576
43942
|
"delete_schedule",
|
|
43577
|
-
"Delete a local
|
|
43943
|
+
"Delete a local automation. Pass id from list_schedules.",
|
|
43578
43944
|
{ id: import_zod10.z.string() },
|
|
43579
43945
|
async ({ id }) => {
|
|
43580
43946
|
try {
|
|
@@ -43587,12 +43953,12 @@ function registerScheduleTools(server) {
|
|
|
43587
43953
|
);
|
|
43588
43954
|
server.tool(
|
|
43589
43955
|
"run_schedule",
|
|
43590
|
-
"Fire
|
|
43956
|
+
"Fire an automation now (does not wait for nextRunAt). Queues the prompt on the target chat or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
|
|
43591
43957
|
{ id: import_zod10.z.string() },
|
|
43592
43958
|
async ({ id }) => {
|
|
43593
43959
|
try {
|
|
43594
43960
|
if (!getSchedule(id)) {
|
|
43595
|
-
return fail4(new Error(`
|
|
43961
|
+
return fail4(new Error(`Automation not found: ${id}`));
|
|
43596
43962
|
}
|
|
43597
43963
|
const schedule = await fireSchedule(id);
|
|
43598
43964
|
return text6({ schedule });
|
|
@@ -45568,6 +45934,7 @@ init_profile();
|
|
|
45568
45934
|
init_home_board();
|
|
45569
45935
|
|
|
45570
45936
|
// src/integrations/abletime-blocked.ts
|
|
45937
|
+
init_abletime();
|
|
45571
45938
|
init_abletime_mcp();
|
|
45572
45939
|
init_abletime_rest();
|
|
45573
45940
|
function asRecord18(value) {
|
|
@@ -45592,6 +45959,9 @@ function firstRecord2(record, keys) {
|
|
|
45592
45959
|
}
|
|
45593
45960
|
return null;
|
|
45594
45961
|
}
|
|
45962
|
+
function taskState(record) {
|
|
45963
|
+
return firstString5(record, ["state", "board_state", "boardState", "status", "taskState"]);
|
|
45964
|
+
}
|
|
45595
45965
|
function identifierFromUnknown(value) {
|
|
45596
45966
|
if (typeof value === "string" || typeof value === "number") {
|
|
45597
45967
|
const id2 = String(value).trim();
|
|
@@ -45603,6 +45973,7 @@ function identifierFromUnknown(value) {
|
|
|
45603
45973
|
for (const key of ["nodes", "data", "tasks", "items"]) {
|
|
45604
45974
|
if (Array.isArray(rec[key])) return identifierFromUnknown(rec[key]);
|
|
45605
45975
|
}
|
|
45976
|
+
if (ableTimeStateIsClosed(taskState(rec))) return [];
|
|
45606
45977
|
const id = firstString5(rec, ["identifier", "reference", "ref", "key", "code", "number", "id"]);
|
|
45607
45978
|
return id ? [id] : [];
|
|
45608
45979
|
}
|
|
@@ -45637,6 +46008,8 @@ async function getAbleTimeIssueBlockedBy(id, opts) {
|
|
|
45637
46008
|
continue;
|
|
45638
46009
|
}
|
|
45639
46010
|
const parent = await callAbleTimeTool("get_task", { id: blockerId, task_id: blockerId }, opts);
|
|
46011
|
+
const parentRecord = firstRecord2(asRecord18(parent), ["task", "data"]) ?? asRecord18(parent);
|
|
46012
|
+
if (ableTimeStateIsClosed(taskState(parentRecord))) continue;
|
|
45640
46013
|
const ref = taskReference(parent);
|
|
45641
46014
|
if (!ref || looksLikeAbleTimeUlid(ref)) {
|
|
45642
46015
|
throw new Error(`AbleTime blocker has no reference: ${blockerId}`);
|
|
@@ -45661,6 +46034,8 @@ function githubBlockedByIdentifiers(payload) {
|
|
|
45661
46034
|
const rec = node && typeof node === "object" && !Array.isArray(node) ? node : null;
|
|
45662
46035
|
const number = Number(rec?.number ?? node);
|
|
45663
46036
|
if (!Number.isFinite(number) || number <= 0) continue;
|
|
46037
|
+
const state = String(rec?.state ?? "").trim().toUpperCase();
|
|
46038
|
+
if (state === "CLOSED") continue;
|
|
45664
46039
|
const id = `#${number}`;
|
|
45665
46040
|
const key = id.toLowerCase();
|
|
45666
46041
|
if (seen.has(key)) continue;
|
|
@@ -45673,7 +46048,7 @@ var GITHUB_BLOCKED_BY_QUERY = `
|
|
|
45673
46048
|
query($owner: String!, $name: String!, $number: Int!) {
|
|
45674
46049
|
repository(owner: $owner, name: $name) {
|
|
45675
46050
|
issue(number: $number) {
|
|
45676
|
-
blockedBy(first: 25) { nodes { number } }
|
|
46051
|
+
blockedBy(first: 25) { nodes { number state } }
|
|
45677
46052
|
}
|
|
45678
46053
|
}
|
|
45679
46054
|
}
|
|
@@ -45721,15 +46096,21 @@ async function getGitHubIssueBlockedBy(id, opts) {
|
|
|
45721
46096
|
}
|
|
45722
46097
|
|
|
45723
46098
|
// src/integrations/linear-blocked.ts
|
|
46099
|
+
var RESOLVED_LINEAR_STATE = /* @__PURE__ */ new Set(["completed", "canceled", "cancelled", "duplicate"]);
|
|
46100
|
+
function linearBlockerStillBlocks(issue) {
|
|
46101
|
+
const type = (issue?.state?.type ?? "").trim().toLowerCase();
|
|
46102
|
+
if (!type) return true;
|
|
46103
|
+
return !RESOLVED_LINEAR_STATE.has(type);
|
|
46104
|
+
}
|
|
45724
46105
|
var ISSUE_BLOCKED_BY_QUERY = `
|
|
45725
46106
|
query SideboardIssueBlockedBy($id: String!) {
|
|
45726
46107
|
issue(id: $id) {
|
|
45727
46108
|
identifier
|
|
45728
46109
|
relations(first: 25) {
|
|
45729
|
-
nodes { id type relatedIssue { id identifier } }
|
|
46110
|
+
nodes { id type relatedIssue { id identifier state { type } } }
|
|
45730
46111
|
}
|
|
45731
46112
|
inverseRelations(first: 25) {
|
|
45732
|
-
nodes { id type issue { id identifier } }
|
|
46113
|
+
nodes { id type issue { id identifier state { type } } }
|
|
45733
46114
|
}
|
|
45734
46115
|
}
|
|
45735
46116
|
}
|
|
@@ -45740,6 +46121,7 @@ function linearBlockedByIdentifiers(relations) {
|
|
|
45740
46121
|
for (const rel of relations) {
|
|
45741
46122
|
const type = (rel.type ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
|
|
45742
46123
|
if (type !== "blockedby" && type !== "blocked") continue;
|
|
46124
|
+
if (!linearBlockerStillBlocks(rel.issue)) continue;
|
|
45743
46125
|
const id = (rel.issue?.identifier || rel.issue?.id || "").trim();
|
|
45744
46126
|
const key = id.toLowerCase();
|
|
45745
46127
|
if (!id || seen.has(key)) continue;
|
|
@@ -47931,6 +48313,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
47931
48313
|
ableTimeOAuthLocalBounceUrl,
|
|
47932
48314
|
ableTimeOAuthRedirectUri,
|
|
47933
48315
|
ableTimeOAuthResource,
|
|
48316
|
+
ableTimeStateIsClosed,
|
|
47934
48317
|
ableTimeUsesRest,
|
|
47935
48318
|
abletimeMcpRequest,
|
|
47936
48319
|
abletimeMcpUrl,
|
|
@@ -48413,6 +48796,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48413
48796
|
issueMatchesAssignee,
|
|
48414
48797
|
issueSourceLabel,
|
|
48415
48798
|
issueTicketFromThread,
|
|
48799
|
+
joinSteerPrompt,
|
|
48416
48800
|
killDetachedRunTree,
|
|
48417
48801
|
killListenersOnPorts,
|
|
48418
48802
|
killStaleWorktreeListeners,
|
|
@@ -48471,6 +48855,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48471
48855
|
listWorktrees,
|
|
48472
48856
|
listenerCwd,
|
|
48473
48857
|
liveActivitySummary,
|
|
48858
|
+
livePartsShowAgentReply,
|
|
48474
48859
|
loadAppSettings,
|
|
48475
48860
|
loadBrightsyConfig,
|
|
48476
48861
|
loadConductorSettings,
|
|
@@ -48808,6 +49193,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
48808
49193
|
toolDetail,
|
|
48809
49194
|
toolFilePath,
|
|
48810
49195
|
totalTokens,
|
|
49196
|
+
trailingUnansweredUserText,
|
|
48811
49197
|
trustSystemCertificates,
|
|
48812
49198
|
tryReservePort,
|
|
48813
49199
|
tryReservePorts,
|