@sideboard-ai/core 0.1.289 → 0.1.290
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/{chunk-EBGJXOXT.js → chunk-4VXWLY3L.js} +3 -2
- package/dist/{chunk-C546EOEF.js → chunk-QOUTSISS.js} +3 -2
- package/dist/index.cjs +546 -96
- package/dist/index.js +512 -73
- package/dist/mcp/run-stdio.cjs +2 -1
- package/dist/mcp/run-stdio.js +1 -1
- package/dist/{orchestrator-MKF3YBNK.js → orchestrator-EQSK2RMI.js} +1 -1
- package/dist/{orchestrator-IG4VU7MT.js → orchestrator-GSOW3RPA.js} +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26376,12 +26376,13 @@ function formatArtifactDirective() {
|
|
|
26376
26376
|
"Sideboard side column (desktop UI) \u2014 Sideboard MCP tools present_artifact, present_schema, present_files, ask_user (see their descriptions). claude.ai\u2019s \u201CArtifact\u201D tool does not exist here; never say artifacts, the CMS UI, or the Files column are unavailable.",
|
|
26377
26377
|
"- Standalone documents: a fenced block tagged `html` (preferred), `svg`, or `markdown` containing the FULL document opens the side column by itself. Use that or present_artifact \u2014 never both for the same body.",
|
|
26378
26378
|
"- present_artifact type=log appends: same artifact_id, content = new lines only (plus status/phase). Do not resend the full log or wrap it in HTML.",
|
|
26379
|
+
"- Chat links open the side column and files: `[label](sideboard://artifact/<artifact_id or title>)` opens that pane; `[label](sideboard://file/<path>#L12-L40)` opens the file (line range optional). A repo-relative markdown link opens the file too.",
|
|
26379
26380
|
"- Data: a markdown table is enough to read. Call present_schema only when the user needs to filter/edit/publish/persist rows \u2014 including when they ask for an editable table after you already showed markdown. Never re-present rows you already wrote just to display them.",
|
|
26380
26381
|
"- ask_user only when work is blocked on a few concrete options (approach fork, which API, auth vs cookies): first a short chat message explaining the decision and each option, then the call (description on every option), then stop and wait. Not for greetings, check-ins, an invented menu of next tasks, or after a review \u2014 reply in chat. If one option is the obvious default, proceed. ask_user already notifies the parent orchestrator. Call notify_orchestrator only when blocked without a picker."
|
|
26381
26382
|
].join("\n");
|
|
26382
26383
|
}
|
|
26383
26384
|
function formatUiReminder() {
|
|
26384
|
-
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. ask_user wakes the parent orchestrator; notify_orchestrator if blocked without a picker. Do not say artifacts/CMS UI are unavailable. Dev / preview: run_dev_script (same as the Dev button; pass name \u2014 several scripts can run at once) returns {url, port, preview} (SIDEBOARD_PORT \u2014 never guess :3000). preview=url \u2192 open url; preview=window \u2192 Electron window is the app, url is renderer/HMR only. list_run_scripts active[].url if already running; get_run_log for that script\u2019s Run-tab terminal; stop_dev_script to stop one.";
|
|
26385
|
+
return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). Chat links: `[name](sideboard://artifact/<id-or-title>)` opens that pane; `[name](sideboard://file/path#L12-L40)` opens a file. ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. ask_user wakes the parent orchestrator; notify_orchestrator if blocked without a picker. Do not say artifacts/CMS UI are unavailable. Dev / preview: run_dev_script (same as the Dev button; pass name \u2014 several scripts can run at once) returns {url, port, preview} (SIDEBOARD_PORT \u2014 never guess :3000). preview=url \u2192 open url; preview=window \u2192 Electron window is the app, url is renderer/HMR only. list_run_scripts active[].url if already running; get_run_log for that script\u2019s Run-tab terminal; stop_dev_script to stop one.";
|
|
26385
26386
|
}
|
|
26386
26387
|
var import_node_fs63, import_node_path60, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
|
|
26387
26388
|
var init_instructions = __esm({
|
|
@@ -40026,10 +40027,16 @@ init_stage_files();
|
|
|
40026
40027
|
init_orchestrator();
|
|
40027
40028
|
init_app_settings();
|
|
40028
40029
|
init_implied_first_prompt();
|
|
40030
|
+
init_message_parts();
|
|
40031
|
+
init_turn_live();
|
|
40029
40032
|
|
|
40030
40033
|
// src/remote/phone-media.ts
|
|
40034
|
+
var import_node_fs71 = require("fs");
|
|
40035
|
+
var import_node_path69 = require("path");
|
|
40031
40036
|
init_diff();
|
|
40032
40037
|
var PHONE_IMAGE_MAX_BYTES = 15e5;
|
|
40038
|
+
var PHONE_TEXT_MAX_BYTES = 18e4;
|
|
40039
|
+
var PHONE_DIR_MAX = 200;
|
|
40033
40040
|
var IMAGE_MIME = {
|
|
40034
40041
|
png: "image/png",
|
|
40035
40042
|
jpg: "image/jpeg",
|
|
@@ -40076,21 +40083,74 @@ function phoneImageDataUrl(worktreePath, raw) {
|
|
|
40076
40083
|
return null;
|
|
40077
40084
|
}
|
|
40078
40085
|
}
|
|
40079
|
-
|
|
40080
|
-
|
|
40081
|
-
|
|
40082
|
-
|
|
40083
|
-
|
|
40084
|
-
|
|
40085
|
-
|
|
40086
|
-
|
|
40087
|
-
|
|
40088
|
-
|
|
40089
|
-
|
|
40090
|
-
|
|
40091
|
-
|
|
40092
|
-
|
|
40093
|
-
|
|
40086
|
+
function phoneDirectoryListing(worktreePath, relative) {
|
|
40087
|
+
try {
|
|
40088
|
+
const entries = (0, import_node_fs71.readdirSync)((0, import_node_path69.join)(worktreePath, relative), { withFileTypes: true });
|
|
40089
|
+
const dirs = new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
40090
|
+
const names = entries.map((entry) => entry.name).filter((name) => name && !name.includes("/") && !name.includes("\0")).sort((a, b) => a.localeCompare(b));
|
|
40091
|
+
const shown = names.slice(0, PHONE_DIR_MAX);
|
|
40092
|
+
const lines = shown.map((name) => dirs.has(name) ? `${name}/` : name);
|
|
40093
|
+
const truncated = names.length > shown.length;
|
|
40094
|
+
if (truncated) lines.push(`\u2026 ${names.length - shown.length} more`);
|
|
40095
|
+
return { content: lines.join("\n"), truncated };
|
|
40096
|
+
} catch {
|
|
40097
|
+
return null;
|
|
40098
|
+
}
|
|
40099
|
+
}
|
|
40100
|
+
function phoneFilePreview(worktreePath, relative, kind) {
|
|
40101
|
+
if (kind === "dir") {
|
|
40102
|
+
const listing = phoneDirectoryListing(worktreePath, relative);
|
|
40103
|
+
if (!listing) return null;
|
|
40104
|
+
return {
|
|
40105
|
+
content: listing.content,
|
|
40106
|
+
encoding: "utf8",
|
|
40107
|
+
binary: false,
|
|
40108
|
+
directory: true,
|
|
40109
|
+
truncated: listing.truncated
|
|
40110
|
+
};
|
|
40111
|
+
}
|
|
40112
|
+
if (relative.toLowerCase().endsWith(".svg")) {
|
|
40113
|
+
try {
|
|
40114
|
+
const buf = (0, import_node_fs71.readFileSync)((0, import_node_path69.join)(worktreePath, relative));
|
|
40115
|
+
const truncated = buf.length > PHONE_TEXT_MAX_BYTES;
|
|
40116
|
+
return {
|
|
40117
|
+
content: buf.subarray(0, PHONE_TEXT_MAX_BYTES).toString("utf8"),
|
|
40118
|
+
encoding: "utf8",
|
|
40119
|
+
binary: false,
|
|
40120
|
+
directory: false,
|
|
40121
|
+
truncated,
|
|
40122
|
+
mime: "image/svg+xml"
|
|
40123
|
+
};
|
|
40124
|
+
} catch {
|
|
40125
|
+
return null;
|
|
40126
|
+
}
|
|
40127
|
+
}
|
|
40128
|
+
const mime = phoneImageMime(relative);
|
|
40129
|
+
if (mime) {
|
|
40130
|
+
const dataUrl = phoneImageDataUrl(worktreePath, relative);
|
|
40131
|
+
if (!dataUrl) return null;
|
|
40132
|
+
return {
|
|
40133
|
+
content: dataUrl,
|
|
40134
|
+
encoding: "base64",
|
|
40135
|
+
binary: true,
|
|
40136
|
+
directory: false,
|
|
40137
|
+
truncated: false,
|
|
40138
|
+
mime
|
|
40139
|
+
};
|
|
40140
|
+
}
|
|
40141
|
+
try {
|
|
40142
|
+
const file = readWorktreeFile(worktreePath, relative, { maxBytes: PHONE_TEXT_MAX_BYTES });
|
|
40143
|
+
return {
|
|
40144
|
+
content: file.content,
|
|
40145
|
+
encoding: file.encoding,
|
|
40146
|
+
binary: file.binary,
|
|
40147
|
+
directory: false,
|
|
40148
|
+
truncated: file.truncated
|
|
40149
|
+
};
|
|
40150
|
+
} catch {
|
|
40151
|
+
return null;
|
|
40152
|
+
}
|
|
40153
|
+
}
|
|
40094
40154
|
|
|
40095
40155
|
// src/remote/phone-artifact.ts
|
|
40096
40156
|
var FENCE_RE = /```([a-zA-Z0-9_+-]*)[^\n]*\n([\s\S]*?)(?:```|$)/g;
|
|
@@ -40227,6 +40287,281 @@ function parseOpenArtifact(value, chatId) {
|
|
|
40227
40287
|
const hint = oneLine(str6(record.hint), 200);
|
|
40228
40288
|
return { op: "open-artifact", chatId, title, ...hint ? { hint } : {} };
|
|
40229
40289
|
}
|
|
40290
|
+
var PHONE_ARTIFACT_MAX_CHARS = 18e4;
|
|
40291
|
+
function phoneArtifactDocuments(sources) {
|
|
40292
|
+
const docs = [];
|
|
40293
|
+
for (const source of sources) {
|
|
40294
|
+
const hints = /* @__PURE__ */ new Set();
|
|
40295
|
+
for (const match of source.text.matchAll(new RegExp(FENCE_RE.source, "g"))) {
|
|
40296
|
+
const language = match[1] ?? "";
|
|
40297
|
+
const content = match[2] ?? "";
|
|
40298
|
+
const kind = kindFor(language, content);
|
|
40299
|
+
if (!kind) continue;
|
|
40300
|
+
const hint = artifactHint(content);
|
|
40301
|
+
if (hint) hints.add(hint);
|
|
40302
|
+
docs.push({ title: titleFor(kind, content), content, kind });
|
|
40303
|
+
}
|
|
40304
|
+
for (const part of source.parts ?? []) {
|
|
40305
|
+
if (part.type !== "tool" || part.parentId || !isArtifactTool(part.name)) continue;
|
|
40306
|
+
const input = asRecord14(part.input);
|
|
40307
|
+
const content = toolContent(input);
|
|
40308
|
+
const hint = artifactHint(content);
|
|
40309
|
+
if (hint && hints.has(hint)) continue;
|
|
40310
|
+
const typed = kindFor(str6(input?.type), content) ?? kindFor("", content);
|
|
40311
|
+
const title = oneLine(str6(input?.title), 80) || (typed ? titleFor(typed, content) : "Artifact");
|
|
40312
|
+
if (!str6(input?.title) && content.trim().length < MIN_FENCE_CHARS) continue;
|
|
40313
|
+
if (hint) hints.add(hint);
|
|
40314
|
+
docs.push({ title, content, kind: typed ?? "text" });
|
|
40315
|
+
}
|
|
40316
|
+
}
|
|
40317
|
+
return docs;
|
|
40318
|
+
}
|
|
40319
|
+
function phoneArtifactReply(docs, request) {
|
|
40320
|
+
const match = pickArtifactMatch(docs, request);
|
|
40321
|
+
if (!match) return null;
|
|
40322
|
+
const truncated = match.content.length > PHONE_ARTIFACT_MAX_CHARS;
|
|
40323
|
+
return {
|
|
40324
|
+
title: match.title,
|
|
40325
|
+
kind: match.kind,
|
|
40326
|
+
content: truncated ? match.content.slice(0, PHONE_ARTIFACT_MAX_CHARS) : match.content,
|
|
40327
|
+
truncated
|
|
40328
|
+
};
|
|
40329
|
+
}
|
|
40330
|
+
function newest(items) {
|
|
40331
|
+
return items.length ? items[items.length - 1] ?? null : null;
|
|
40332
|
+
}
|
|
40333
|
+
function pickArtifactMatch(items, request) {
|
|
40334
|
+
const hint = request.hint?.trim();
|
|
40335
|
+
const title = request.title.trim();
|
|
40336
|
+
if (hint) {
|
|
40337
|
+
const exact = items.filter((item) => item.content && artifactHint(item.content) === hint);
|
|
40338
|
+
const exactTitled = title ? exact.filter((item) => item.title === title) : [];
|
|
40339
|
+
const exactMatch = newest(exactTitled.length ? exactTitled : exact);
|
|
40340
|
+
if (exactMatch) return exactMatch;
|
|
40341
|
+
if (title) {
|
|
40342
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
40343
|
+
const item = items[i];
|
|
40344
|
+
if (!item?.content || item.title !== title) continue;
|
|
40345
|
+
if (normalizedBody(item.content).startsWith(hint)) return item;
|
|
40346
|
+
}
|
|
40347
|
+
}
|
|
40348
|
+
}
|
|
40349
|
+
if (!title) return null;
|
|
40350
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
40351
|
+
if (items[i]?.title === title) return items[i] ?? null;
|
|
40352
|
+
}
|
|
40353
|
+
return null;
|
|
40354
|
+
}
|
|
40355
|
+
|
|
40356
|
+
// src/remote/phone-workspace-ops.ts
|
|
40357
|
+
init_orchestrator();
|
|
40358
|
+
|
|
40359
|
+
// src/remote/phone-chats.ts
|
|
40360
|
+
var import_node_crypto26 = require("crypto");
|
|
40361
|
+
init_list_models();
|
|
40362
|
+
init_home_board();
|
|
40363
|
+
init_stage_files();
|
|
40364
|
+
init_worktree_labels();
|
|
40365
|
+
init_thinking_effort();
|
|
40366
|
+
init_app_settings();
|
|
40367
|
+
init_global_workspace();
|
|
40368
|
+
init_thread_store();
|
|
40369
|
+
init_workspaces();
|
|
40370
|
+
init_chat_tabs();
|
|
40371
|
+
init_create();
|
|
40372
|
+
init_orchestrator();
|
|
40373
|
+
|
|
40374
|
+
// src/remote/phone-header.ts
|
|
40375
|
+
init_orchestrator();
|
|
40376
|
+
init_global_workspace();
|
|
40377
|
+
var PHONE_HEADER_GIT_ACTIONS = [
|
|
40378
|
+
"commit-push",
|
|
40379
|
+
"create-draft",
|
|
40380
|
+
"resolve-conflicts",
|
|
40381
|
+
"ready-for-review",
|
|
40382
|
+
"merge"
|
|
40383
|
+
];
|
|
40384
|
+
var HIDDEN = {
|
|
40385
|
+
visible: false,
|
|
40386
|
+
branch: "",
|
|
40387
|
+
additions: 0,
|
|
40388
|
+
deletions: 0,
|
|
40389
|
+
unpushed: 0,
|
|
40390
|
+
dirty: false,
|
|
40391
|
+
ready: false,
|
|
40392
|
+
title: ""
|
|
40393
|
+
};
|
|
40394
|
+
function phoneHeaderFrom(thread, diff) {
|
|
40395
|
+
if (isGlobalThread(thread)) return HIDDEN;
|
|
40396
|
+
const branch = thread.branchName.trim().replace(/^thread\//, "");
|
|
40397
|
+
if (!branch) return HIDDEN;
|
|
40398
|
+
const ready = diff != null;
|
|
40399
|
+
const uncommitted = diff?.scopeStats?.uncommitted;
|
|
40400
|
+
const additions = ready ? Math.max(0, Math.trunc(uncommitted?.additions ?? 0)) : 0;
|
|
40401
|
+
const deletions = ready ? Math.max(0, Math.trunc(uncommitted?.deletions ?? 0)) : 0;
|
|
40402
|
+
const unpushed = ready ? Math.max(0, Math.trunc(diff?.unpushed ?? 0)) : 0;
|
|
40403
|
+
const dirty = ready && (Boolean(diff?.dirty) || additions > 0 || deletions > 0);
|
|
40404
|
+
const pr = prSnapshot(thread);
|
|
40405
|
+
const action = ready ? headerAction(pr, { dirty: Boolean(diff?.dirty), unpushed }) : null;
|
|
40406
|
+
const lines = [branch];
|
|
40407
|
+
if (!ready) lines.push("Loading git status\u2026");
|
|
40408
|
+
else if (dirty) lines.push(`Uncommitted +${additions} \u2212${deletions}`);
|
|
40409
|
+
else lines.push("Working tree clean");
|
|
40410
|
+
if (unpushed > 0) lines.push(`${unpushed} unpushed commit${unpushed === 1 ? "" : "s"}`);
|
|
40411
|
+
return {
|
|
40412
|
+
visible: true,
|
|
40413
|
+
branch,
|
|
40414
|
+
additions,
|
|
40415
|
+
deletions,
|
|
40416
|
+
unpushed,
|
|
40417
|
+
dirty,
|
|
40418
|
+
ready,
|
|
40419
|
+
title: lines.join("\n"),
|
|
40420
|
+
...pr.url ? { prUrl: pr.url } : {},
|
|
40421
|
+
...pr.number ? { prNumber: pr.number } : {},
|
|
40422
|
+
...pr.status ? { prStatus: pr.status } : {},
|
|
40423
|
+
...action ? { action: action.id, actionLabel: action.label } : {}
|
|
40424
|
+
};
|
|
40425
|
+
}
|
|
40426
|
+
function phonePrPill(thread) {
|
|
40427
|
+
const pr = prSnapshot(thread);
|
|
40428
|
+
if (!pr.url) return null;
|
|
40429
|
+
return { url: pr.url, number: pr.number, status: pr.status };
|
|
40430
|
+
}
|
|
40431
|
+
async function readPhoneHeader(thread) {
|
|
40432
|
+
const pending = phoneHeaderFrom(thread, null);
|
|
40433
|
+
if (!pending.visible) return pending;
|
|
40434
|
+
try {
|
|
40435
|
+
const diff = await getOrchestrator().diff(thread.id, { includePatches: false });
|
|
40436
|
+
return phoneHeaderFrom(thread, diff);
|
|
40437
|
+
} catch {
|
|
40438
|
+
return pending;
|
|
40439
|
+
}
|
|
40440
|
+
}
|
|
40441
|
+
function prSnapshot(thread) {
|
|
40442
|
+
const url = thread.prUrl?.trim() || "";
|
|
40443
|
+
const number = url.match(/\/pull\/(\d+)/)?.[1] ?? "";
|
|
40444
|
+
const state = (thread.prState ?? "").toUpperCase();
|
|
40445
|
+
const merged = state === "MERGED";
|
|
40446
|
+
const closed = state === "CLOSED";
|
|
40447
|
+
const open = Boolean(url) && !merged && !closed;
|
|
40448
|
+
const draft = open && Boolean(thread.prIsDraft);
|
|
40449
|
+
const inMergeQueue = open && Boolean(thread.prIsInMergeQueue);
|
|
40450
|
+
const mergeable = (thread.prMergeable ?? "").toUpperCase();
|
|
40451
|
+
const mergeState = (thread.prMergeStateStatus ?? "").toUpperCase();
|
|
40452
|
+
const mergeConflicts = open && !inMergeQueue && (mergeable === "CONFLICTING" || mergeState === "DIRTY");
|
|
40453
|
+
const branchBehind = open && !inMergeQueue && !mergeConflicts && mergeState === "BEHIND";
|
|
40454
|
+
const checksFailed = Boolean(thread.prChecksFailed);
|
|
40455
|
+
const review = (open && !draft ? thread.prReviewDecision : "") ?? "";
|
|
40456
|
+
return {
|
|
40457
|
+
url,
|
|
40458
|
+
number,
|
|
40459
|
+
status: pillStatus({ url, merged, closed, draft, inMergeQueue, mergeConflicts, branchBehind, checksFailed, review }),
|
|
40460
|
+
merged,
|
|
40461
|
+
closed,
|
|
40462
|
+
open,
|
|
40463
|
+
draft,
|
|
40464
|
+
cowboy: Boolean(thread.cowboy),
|
|
40465
|
+
inMergeQueue,
|
|
40466
|
+
mergeConflicts,
|
|
40467
|
+
branchBehind,
|
|
40468
|
+
checksFailed,
|
|
40469
|
+
review: review.toUpperCase()
|
|
40470
|
+
};
|
|
40471
|
+
}
|
|
40472
|
+
function pillStatus(pr) {
|
|
40473
|
+
if (!pr.url) return "";
|
|
40474
|
+
if (pr.merged) return "Merged";
|
|
40475
|
+
if (pr.closed) return "Closed";
|
|
40476
|
+
if (pr.inMergeQueue) return "Queued";
|
|
40477
|
+
if (pr.mergeConflicts) return "Merge conflicts";
|
|
40478
|
+
if (pr.branchBehind) return "Behind base";
|
|
40479
|
+
if (pr.draft) return "Draft";
|
|
40480
|
+
if (pr.checksFailed) return "Checks failing";
|
|
40481
|
+
if (pr.review === "CHANGES_REQUESTED") return "Changes requested";
|
|
40482
|
+
if (pr.review !== "APPROVED") return "Needs approval";
|
|
40483
|
+
return "Approved";
|
|
40484
|
+
}
|
|
40485
|
+
function headerAction(pr, diff) {
|
|
40486
|
+
const hasLocalChanges = diff.dirty || diff.unpushed > 0;
|
|
40487
|
+
const originInSync = !hasLocalChanges;
|
|
40488
|
+
if (pr.merged) return null;
|
|
40489
|
+
if (pr.closed) return { id: "open-pr", label: "Closed" };
|
|
40490
|
+
if (pr.cowboy) {
|
|
40491
|
+
return hasLocalChanges ? { id: "commit-push", label: "Commit & push" } : { id: "commit-push", label: "Push" };
|
|
40492
|
+
}
|
|
40493
|
+
if (!pr.url) return { id: "create-draft", label: "Create PR" };
|
|
40494
|
+
if (pr.inMergeQueue) return { id: "open-pr", label: "Queued" };
|
|
40495
|
+
if (pr.mergeConflicts) return { id: "resolve-conflicts", label: "Resolve" };
|
|
40496
|
+
if (pr.branchBehind) return { id: "resolve-conflicts", label: "Update" };
|
|
40497
|
+
if (hasLocalChanges) return { id: "commit-push", label: "Commit & push" };
|
|
40498
|
+
if (pr.draft) {
|
|
40499
|
+
return originInSync ? { id: "ready-for-review", label: "Ready for review" } : { id: "commit-push", label: "Commit & push" };
|
|
40500
|
+
}
|
|
40501
|
+
if (pr.checksFailed) return { id: "open-checks", label: "Checks failing" };
|
|
40502
|
+
if (pr.review === "CHANGES_REQUESTED") return { id: "open-pr", label: "Changes requested" };
|
|
40503
|
+
if (pr.review !== "APPROVED") return { id: "open-pr", label: "Needs approval" };
|
|
40504
|
+
return { id: "merge", label: "Merge" };
|
|
40505
|
+
}
|
|
40506
|
+
|
|
40507
|
+
// src/remote/phone-panes.ts
|
|
40508
|
+
init_orchestrator();
|
|
40509
|
+
var MAX_ROWS = 200;
|
|
40510
|
+
function parsePhonePane(value, chatId) {
|
|
40511
|
+
const pane = value && typeof value === "object" ? value.pane : void 0;
|
|
40512
|
+
if (pane !== "files" && pane !== "changes" && pane !== "checks") return "invalid";
|
|
40513
|
+
const scopeRaw = value.scope;
|
|
40514
|
+
const scope = scopeRaw === "uncommitted" || scopeRaw === "commits" ? scopeRaw : void 0;
|
|
40515
|
+
return { op: "pane", chatId, pane, ...scope && pane === "changes" ? { scope } : {} };
|
|
40516
|
+
}
|
|
40517
|
+
async function readPhonePane(thread, pane, scope) {
|
|
40518
|
+
try {
|
|
40519
|
+
if (pane === "files") return await readFiles(thread.id);
|
|
40520
|
+
if (pane === "changes") return await readChanges(thread.id, scope ?? "commits");
|
|
40521
|
+
return await readChecks(thread.id);
|
|
40522
|
+
} catch (err) {
|
|
40523
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40524
|
+
return { rows: [], note: message };
|
|
40525
|
+
}
|
|
40526
|
+
}
|
|
40527
|
+
async function readFiles(threadId) {
|
|
40528
|
+
const paths = await getOrchestrator().listFiles(threadId);
|
|
40529
|
+
const shown = paths.slice(0, MAX_ROWS);
|
|
40530
|
+
return {
|
|
40531
|
+
rows: shown.map((path2) => ({ label: path2, path: path2 })),
|
|
40532
|
+
...paths.length > shown.length ? { note: `${paths.length - shown.length} more files on the Mac` } : {}
|
|
40533
|
+
};
|
|
40534
|
+
}
|
|
40535
|
+
async function readChanges(threadId, scope) {
|
|
40536
|
+
const diff = await getOrchestrator().diff(threadId, { includePatches: false, scope });
|
|
40537
|
+
const shown = diff.files.slice(0, MAX_ROWS);
|
|
40538
|
+
return {
|
|
40539
|
+
rows: shown.map((file) => ({
|
|
40540
|
+
label: file.path,
|
|
40541
|
+
path: file.path,
|
|
40542
|
+
detail: changeDetail(file.additions, file.deletions)
|
|
40543
|
+
})),
|
|
40544
|
+
...diff.files.length > shown.length ? { note: `${diff.files.length - shown.length} more changed files` } : {}
|
|
40545
|
+
};
|
|
40546
|
+
}
|
|
40547
|
+
function changeDetail(additions, deletions) {
|
|
40548
|
+
const add = additions ?? 0;
|
|
40549
|
+
const del = deletions ?? 0;
|
|
40550
|
+
if (add === 0 && del === 0) return void 0;
|
|
40551
|
+
return `+${add} \u2212${del}`;
|
|
40552
|
+
}
|
|
40553
|
+
async function readChecks(threadId) {
|
|
40554
|
+
const checks = await getOrchestrator().getPrChecks(threadId);
|
|
40555
|
+
if (!checks) return { rows: [], note: "No pull request on this branch." };
|
|
40556
|
+
const shown = checks.slice(0, MAX_ROWS);
|
|
40557
|
+
return {
|
|
40558
|
+
rows: shown.map((check) => ({
|
|
40559
|
+
label: check.name,
|
|
40560
|
+
detail: check.bucket || check.state,
|
|
40561
|
+
...check.link ? { href: check.link } : {}
|
|
40562
|
+
}))
|
|
40563
|
+
};
|
|
40564
|
+
}
|
|
40230
40565
|
|
|
40231
40566
|
// src/remote/phone-defaults.ts
|
|
40232
40567
|
init_app_settings();
|
|
@@ -40332,10 +40667,63 @@ function listPhoneMessages(thread) {
|
|
|
40332
40667
|
return live.slice(-TRANSCRIPT_LIMIT);
|
|
40333
40668
|
}
|
|
40334
40669
|
|
|
40335
|
-
// src/remote/phone-
|
|
40336
|
-
|
|
40670
|
+
// src/remote/phone-history.ts
|
|
40671
|
+
init_global_workspace();
|
|
40672
|
+
init_thread_store();
|
|
40337
40673
|
var PREVIEW_LIMIT = 90;
|
|
40338
40674
|
var HISTORY_PAGE_SIZE = 40;
|
|
40675
|
+
function previewOf(thread) {
|
|
40676
|
+
const messages = listPhoneMessages(thread);
|
|
40677
|
+
const last = messages[messages.length - 1];
|
|
40678
|
+
if (!last) return "";
|
|
40679
|
+
return clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT);
|
|
40680
|
+
}
|
|
40681
|
+
function repoName(repoPath) {
|
|
40682
|
+
const parts = repoPath.replace(/\/$/, "").split("/");
|
|
40683
|
+
return parts[parts.length - 1] || repoPath;
|
|
40684
|
+
}
|
|
40685
|
+
function isProjectPath(path2) {
|
|
40686
|
+
if (!path2 || path2 === "/" || path2 === ".") return false;
|
|
40687
|
+
return !isGlobalThread({ repoPath: path2 });
|
|
40688
|
+
}
|
|
40689
|
+
function historyStamp(thread) {
|
|
40690
|
+
return thread.archivedAt || thread.updatedAt;
|
|
40691
|
+
}
|
|
40692
|
+
function historyCursor(chat) {
|
|
40693
|
+
return `${chat.updatedAt} ${chat.id}`;
|
|
40694
|
+
}
|
|
40695
|
+
function listPhoneHistory(opts) {
|
|
40696
|
+
const query = opts?.query?.trim().toLowerCase() ?? "";
|
|
40697
|
+
const after = opts?.after?.trim() ?? "";
|
|
40698
|
+
const all = listThreads({ includeArchived: true }).filter((thread) => thread.status === "archived").filter((thread) => isGlobalThread(thread) || isProjectPath(thread.repoPath)).sort((a, b) => historyStamp(a) < historyStamp(b) ? 1 : historyStamp(a) > historyStamp(b) ? -1 : 0).map((thread) => ({
|
|
40699
|
+
id: thread.id,
|
|
40700
|
+
title: thread.title?.trim() || "Untitled",
|
|
40701
|
+
preview: previewOf(thread),
|
|
40702
|
+
updatedAt: historyStamp(thread),
|
|
40703
|
+
where: isGlobalThread(thread) ? "Orchestration" : repoName(thread.repoPath),
|
|
40704
|
+
agent: thread.agent
|
|
40705
|
+
})).filter((chat) => {
|
|
40706
|
+
if (!query) return true;
|
|
40707
|
+
return `${chat.title} ${chat.where} ${chat.agent} ${chat.preview}`.toLowerCase().includes(query);
|
|
40708
|
+
});
|
|
40709
|
+
let start = 0;
|
|
40710
|
+
if (after) {
|
|
40711
|
+
const index = all.findIndex((chat) => historyCursor(chat) === after);
|
|
40712
|
+
start = index >= 0 ? index + 1 : all.length;
|
|
40713
|
+
}
|
|
40714
|
+
const chats = all.slice(start, start + HISTORY_PAGE_SIZE);
|
|
40715
|
+
const last = chats.at(-1);
|
|
40716
|
+
const more = start + chats.length < all.length;
|
|
40717
|
+
return {
|
|
40718
|
+
chats,
|
|
40719
|
+
total: all.length,
|
|
40720
|
+
...more && last ? { next: historyCursor(last) } : {}
|
|
40721
|
+
};
|
|
40722
|
+
}
|
|
40723
|
+
|
|
40724
|
+
// src/remote/phone-chats.ts
|
|
40725
|
+
var PHONE_CONTROL_PREFIX = "\0sb.phone\n";
|
|
40726
|
+
var PREVIEW_LIMIT2 = 90;
|
|
40339
40727
|
var AGENT_KINDS = /* @__PURE__ */ new Set(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
40340
40728
|
var MAX_PHONE_FILES = 8;
|
|
40341
40729
|
var MAX_PHONE_FILE_CHARS = Math.ceil(8 * 1024 * 1024 * 4 / 3);
|
|
@@ -40365,7 +40753,7 @@ function parsePhoneControl(value) {
|
|
|
40365
40753
|
}
|
|
40366
40754
|
if (op === "sources") {
|
|
40367
40755
|
const repoPath = textField(value, "repoPath");
|
|
40368
|
-
if (!repoPath || !
|
|
40756
|
+
if (!repoPath || !isProjectPath2(repoPath)) return "invalid";
|
|
40369
40757
|
const query = textField(value, "query");
|
|
40370
40758
|
return { op: "sources", repoPath, ...query ? { query } : {} };
|
|
40371
40759
|
}
|
|
@@ -40383,7 +40771,15 @@ function parsePhoneControl(value) {
|
|
|
40383
40771
|
if (op === "create") return parsePhoneCreate(value);
|
|
40384
40772
|
const chatId = typeof value.chatId === "string" ? value.chatId.trim() : "";
|
|
40385
40773
|
if (!chatId) return "invalid";
|
|
40386
|
-
if (op === "open" || op === "archive" || op === "restore" || op === "stop"
|
|
40774
|
+
if (op === "open" || op === "archive" || op === "restore" || op === "stop" || op === "review" || op === "header") {
|
|
40775
|
+
return { op, chatId };
|
|
40776
|
+
}
|
|
40777
|
+
if (op === "git") {
|
|
40778
|
+
const action = textField(value, "action");
|
|
40779
|
+
if (!PHONE_HEADER_GIT_ACTIONS.includes(action)) return "invalid";
|
|
40780
|
+
return { op: "git", chatId, action };
|
|
40781
|
+
}
|
|
40782
|
+
if (op === "pane") return parsePhonePane(value, chatId);
|
|
40387
40783
|
if (op === "open-artifact") return parseOpenArtifact(value, chatId);
|
|
40388
40784
|
if (op === "open-file" || op === "media") {
|
|
40389
40785
|
const path2 = textField(value, "path");
|
|
@@ -40523,7 +40919,7 @@ function parsePhoneCreate(value) {
|
|
|
40523
40919
|
}
|
|
40524
40920
|
if (where === "project") {
|
|
40525
40921
|
const repoPath = textField(value, "repoPath");
|
|
40526
|
-
if (!repoPath || !
|
|
40922
|
+
if (!repoPath || !isProjectPath2(repoPath)) return "invalid";
|
|
40527
40923
|
const sourceRaw = textField(value, "sourceType");
|
|
40528
40924
|
let sourceType;
|
|
40529
40925
|
if (sourceRaw === "branch" || sourceRaw === "pr" || sourceRaw === "ticket") sourceType = sourceRaw;
|
|
@@ -40546,26 +40942,30 @@ function parsePhoneCreate(value) {
|
|
|
40546
40942
|
return "invalid";
|
|
40547
40943
|
}
|
|
40548
40944
|
function summarize(thread) {
|
|
40945
|
+
const pr = phonePrPill(thread);
|
|
40549
40946
|
return {
|
|
40550
40947
|
id: thread.id,
|
|
40551
40948
|
title: thread.title?.trim() || "Untitled",
|
|
40552
40949
|
status: thread.status,
|
|
40553
|
-
preview:
|
|
40950
|
+
preview: previewOf2(thread),
|
|
40554
40951
|
updatedAt: thread.updatedAt,
|
|
40555
|
-
agent: thread.agent
|
|
40952
|
+
agent: thread.agent,
|
|
40953
|
+
...pr?.url ? { prUrl: pr.url } : {},
|
|
40954
|
+
...pr?.number ? { prNumber: pr.number } : {},
|
|
40955
|
+
...pr?.status ? { prStatus: pr.status } : {}
|
|
40556
40956
|
};
|
|
40557
40957
|
}
|
|
40558
|
-
function
|
|
40958
|
+
function previewOf2(thread) {
|
|
40559
40959
|
const messages = listPhoneMessages(thread);
|
|
40560
40960
|
const last = messages[messages.length - 1];
|
|
40561
40961
|
if (!last) return "";
|
|
40562
|
-
return clip(last.text.replace(/\s+/g, " ").trim(),
|
|
40962
|
+
return clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT2);
|
|
40563
40963
|
}
|
|
40564
|
-
function
|
|
40964
|
+
function repoName2(repoPath) {
|
|
40565
40965
|
const parts = repoPath.replace(/\/$/, "").split("/");
|
|
40566
40966
|
return parts[parts.length - 1] || repoPath;
|
|
40567
40967
|
}
|
|
40568
|
-
function
|
|
40968
|
+
function isProjectPath2(path2) {
|
|
40569
40969
|
if (!path2 || path2 === "/" || path2 === ".") return false;
|
|
40570
40970
|
return !isGlobalThread({ repoPath: path2 });
|
|
40571
40971
|
}
|
|
@@ -40577,17 +40977,17 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
|
|
|
40577
40977
|
const threads = listThreads();
|
|
40578
40978
|
const byRepo = /* @__PURE__ */ new Map();
|
|
40579
40979
|
for (const thread of threads) {
|
|
40580
|
-
if (!
|
|
40980
|
+
if (!isProjectPath2(thread.repoPath) || isRemovedWorkspace(thread.repoPath)) continue;
|
|
40581
40981
|
const list = byRepo.get(thread.repoPath) ?? [];
|
|
40582
40982
|
list.push(thread);
|
|
40583
40983
|
byRepo.set(thread.repoPath, list);
|
|
40584
40984
|
}
|
|
40585
40985
|
for (const workspace of listWorkspaces()) {
|
|
40586
|
-
if (!
|
|
40986
|
+
if (!isProjectPath2(workspace.path) || byRepo.has(workspace.path)) continue;
|
|
40587
40987
|
byRepo.set(workspace.path, []);
|
|
40588
40988
|
}
|
|
40589
|
-
const projects = [...byRepo.entries()].sort(([a], [b]) =>
|
|
40590
|
-
name:
|
|
40989
|
+
const projects = [...byRepo.entries()].sort(([a], [b]) => repoName2(a).localeCompare(repoName2(b))).map(([path2, repoThreads]) => ({
|
|
40990
|
+
name: repoName2(path2),
|
|
40591
40991
|
path: path2,
|
|
40592
40992
|
worktrees: groupHomeBoardWorktrees(repoThreads).map((group) => {
|
|
40593
40993
|
const tags = workspaceTagsFromGroup(group);
|
|
@@ -40606,41 +41006,6 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
|
|
|
40606
41006
|
}));
|
|
40607
41007
|
return { orchestration: listPhoneChats(), projects, defaults: phoneAccountDefaults() };
|
|
40608
41008
|
}
|
|
40609
|
-
function historyStamp(thread) {
|
|
40610
|
-
return thread.archivedAt || thread.updatedAt;
|
|
40611
|
-
}
|
|
40612
|
-
function historyCursor(chat) {
|
|
40613
|
-
return `${chat.updatedAt} ${chat.id}`;
|
|
40614
|
-
}
|
|
40615
|
-
function historyQueryMatch(chat, query) {
|
|
40616
|
-
if (!query) return true;
|
|
40617
|
-
return `${chat.title} ${chat.where} ${chat.agent} ${chat.preview}`.toLowerCase().includes(query);
|
|
40618
|
-
}
|
|
40619
|
-
function listPhoneHistory(opts) {
|
|
40620
|
-
const query = opts?.query?.trim().toLowerCase() ?? "";
|
|
40621
|
-
const after = opts?.after?.trim() ?? "";
|
|
40622
|
-
const all = listThreads({ includeArchived: true }).filter((thread) => thread.status === "archived").filter((thread) => isGlobalThread(thread) || isProjectPath(thread.repoPath)).sort((a, b) => historyStamp(a) < historyStamp(b) ? 1 : historyStamp(a) > historyStamp(b) ? -1 : 0).map((thread) => ({
|
|
40623
|
-
id: thread.id,
|
|
40624
|
-
title: thread.title?.trim() || "Untitled",
|
|
40625
|
-
preview: previewOf(thread),
|
|
40626
|
-
updatedAt: historyStamp(thread),
|
|
40627
|
-
where: isGlobalThread(thread) ? "Orchestration" : repoName(thread.repoPath),
|
|
40628
|
-
agent: thread.agent
|
|
40629
|
-
})).filter((chat) => historyQueryMatch(chat, query));
|
|
40630
|
-
let start = 0;
|
|
40631
|
-
if (after) {
|
|
40632
|
-
const index = all.findIndex((chat) => historyCursor(chat) === after);
|
|
40633
|
-
start = index >= 0 ? index + 1 : all.length;
|
|
40634
|
-
}
|
|
40635
|
-
const chats = all.slice(start, start + HISTORY_PAGE_SIZE);
|
|
40636
|
-
const last = chats.at(-1);
|
|
40637
|
-
const more = start + chats.length < all.length;
|
|
40638
|
-
return {
|
|
40639
|
-
chats,
|
|
40640
|
-
total: all.length,
|
|
40641
|
-
...more && last ? { next: historyCursor(last) } : {}
|
|
40642
|
-
};
|
|
40643
|
-
}
|
|
40644
41009
|
function matchPhoneThread(chatId) {
|
|
40645
41010
|
const id = chatId.trim();
|
|
40646
41011
|
if (!id) return null;
|
|
@@ -40653,7 +41018,7 @@ function matchPhoneThread(chatId) {
|
|
|
40653
41018
|
}
|
|
40654
41019
|
function visiblePhoneThread(thread) {
|
|
40655
41020
|
if (isGlobalThread(thread)) return true;
|
|
40656
|
-
return
|
|
41021
|
+
return isProjectPath2(thread.repoPath);
|
|
40657
41022
|
}
|
|
40658
41023
|
function findPhoneChat(chatId) {
|
|
40659
41024
|
const thread = matchPhoneThread(chatId);
|
|
@@ -40719,7 +41084,7 @@ function projectPlace(thread) {
|
|
|
40719
41084
|
}
|
|
40720
41085
|
function assertKnownProject(repoPath) {
|
|
40721
41086
|
const path2 = repoPath.trim();
|
|
40722
|
-
if (!
|
|
41087
|
+
if (!isProjectPath2(path2)) throw new Error("Pick a project on this Mac.");
|
|
40723
41088
|
const known = listWorkspaces().some((workspace) => sameRepoPath3(workspace.path, path2)) || listThreads().some(
|
|
40724
41089
|
(thread) => thread.status !== "archived" && sameRepoPath3(thread.repoPath, path2)
|
|
40725
41090
|
);
|
|
@@ -40822,6 +41187,55 @@ function archivePhoneChat(chatId) {
|
|
|
40822
41187
|
return true;
|
|
40823
41188
|
}
|
|
40824
41189
|
|
|
41190
|
+
// src/remote/phone-workspace-ops.ts
|
|
41191
|
+
function dispatchPhoneWorkspace(cmd, emit, publishOpened) {
|
|
41192
|
+
if (cmd.op === "pane") {
|
|
41193
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
41194
|
+
if (!thread) {
|
|
41195
|
+
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
41196
|
+
return;
|
|
41197
|
+
}
|
|
41198
|
+
void readPhonePane(thread, cmd.pane, cmd.scope).then((body) => {
|
|
41199
|
+
emit({
|
|
41200
|
+
op: "pane",
|
|
41201
|
+
chatId: cmd.chatId,
|
|
41202
|
+
pane: cmd.pane,
|
|
41203
|
+
rows: body.rows,
|
|
41204
|
+
...body.note ? { note: body.note } : {}
|
|
41205
|
+
});
|
|
41206
|
+
});
|
|
41207
|
+
return;
|
|
41208
|
+
}
|
|
41209
|
+
if (cmd.op === "header") {
|
|
41210
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
41211
|
+
if (!thread) {
|
|
41212
|
+
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
41213
|
+
return;
|
|
41214
|
+
}
|
|
41215
|
+
void readPhoneHeader(thread).then((header) => {
|
|
41216
|
+
emit({ op: "header", chatId: cmd.chatId, ...header });
|
|
41217
|
+
});
|
|
41218
|
+
return;
|
|
41219
|
+
}
|
|
41220
|
+
if (cmd.op === "git") {
|
|
41221
|
+
void getOrchestrator().askGit(cmd.chatId, cmd.action).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
41222
|
+
emit({
|
|
41223
|
+
op: "error",
|
|
41224
|
+
chatId: cmd.chatId,
|
|
41225
|
+
message: err instanceof Error ? err.message : String(err)
|
|
41226
|
+
});
|
|
41227
|
+
});
|
|
41228
|
+
return;
|
|
41229
|
+
}
|
|
41230
|
+
void getOrchestrator().requestReview(cmd.chatId).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
41231
|
+
emit({
|
|
41232
|
+
op: "error",
|
|
41233
|
+
chatId: cmd.chatId,
|
|
41234
|
+
message: err instanceof Error ? err.message : String(err)
|
|
41235
|
+
});
|
|
41236
|
+
});
|
|
41237
|
+
}
|
|
41238
|
+
|
|
40825
41239
|
// src/remote/phone-sources.ts
|
|
40826
41240
|
init_worktree();
|
|
40827
41241
|
function sourceWarning(label, err) {
|
|
@@ -41398,10 +41812,25 @@ function handlePhoneControl(cmd, opts) {
|
|
|
41398
41812
|
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That file is not in this worktree." });
|
|
41399
41813
|
return;
|
|
41400
41814
|
}
|
|
41401
|
-
|
|
41402
|
-
|
|
41815
|
+
const preview = phoneFilePreview(thread.worktreePath, relative, kind === "dir" ? "dir" : "file");
|
|
41816
|
+
if (!preview) {
|
|
41817
|
+
emitControl(opts, {
|
|
41818
|
+
op: "error",
|
|
41819
|
+
chatId: cmd.chatId,
|
|
41820
|
+
message: "That file could not be opened on the phone."
|
|
41821
|
+
});
|
|
41822
|
+
return;
|
|
41823
|
+
}
|
|
41824
|
+
emitControl(opts, {
|
|
41825
|
+
op: "file",
|
|
41826
|
+
chatId: cmd.chatId,
|
|
41403
41827
|
path: relative,
|
|
41404
|
-
|
|
41828
|
+
content: preview.content,
|
|
41829
|
+
encoding: preview.encoding,
|
|
41830
|
+
...preview.binary ? { binary: true } : {},
|
|
41831
|
+
...preview.directory ? { directory: true } : {},
|
|
41832
|
+
...preview.truncated ? { truncated: true } : {},
|
|
41833
|
+
...preview.mime ? { mime: preview.mime } : {},
|
|
41405
41834
|
...cmd.startLine != null ? { startLine: cmd.startLine } : {},
|
|
41406
41835
|
...cmd.endLine != null ? { endLine: cmd.endLine } : {}
|
|
41407
41836
|
});
|
|
@@ -41416,13 +41845,34 @@ function handlePhoneControl(cmd, opts) {
|
|
|
41416
41845
|
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
41417
41846
|
return;
|
|
41418
41847
|
}
|
|
41419
|
-
|
|
41420
|
-
|
|
41421
|
-
|
|
41422
|
-
|
|
41848
|
+
const liveParts = readTurnLiveParts(thread.id);
|
|
41849
|
+
const docs = phoneArtifactDocuments([
|
|
41850
|
+
...(thread.messages ?? []).filter((message) => message.role === "agent").map((message) => ({ text: message.text.trim(), parts: message.parts })),
|
|
41851
|
+
{ text: visibleAssistantText(void 0, liveParts), parts: liveParts }
|
|
41852
|
+
]);
|
|
41853
|
+
const body = phoneArtifactReply(docs, { title: cmd.title, ...cmd.hint ? { hint: cmd.hint } : {} });
|
|
41854
|
+
if (!body) {
|
|
41855
|
+
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That artifact is not in this chat." });
|
|
41856
|
+
return;
|
|
41857
|
+
}
|
|
41858
|
+
emitControl(opts, {
|
|
41859
|
+
op: "artifact",
|
|
41860
|
+
chatId: cmd.chatId,
|
|
41861
|
+
title: body.title,
|
|
41862
|
+
kind: body.kind,
|
|
41863
|
+
content: body.content,
|
|
41864
|
+
...body.truncated ? { truncated: true } : {}
|
|
41423
41865
|
});
|
|
41424
41866
|
return;
|
|
41425
41867
|
}
|
|
41868
|
+
if (cmd.op === "pane" || cmd.op === "header" || cmd.op === "git" || cmd.op === "review") {
|
|
41869
|
+
dispatchPhoneWorkspace(
|
|
41870
|
+
cmd,
|
|
41871
|
+
(reply) => emitControl(opts, reply),
|
|
41872
|
+
(chatId2) => publishOpenedChat(opts, chatId2)
|
|
41873
|
+
);
|
|
41874
|
+
return;
|
|
41875
|
+
}
|
|
41426
41876
|
if (cmd.op === "stop") {
|
|
41427
41877
|
if (!readPhoneThread(cmd.chatId)) {
|
|
41428
41878
|
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
@@ -41501,7 +41951,7 @@ function handleRemoteInbound(text7, opts) {
|
|
|
41501
41951
|
}
|
|
41502
41952
|
|
|
41503
41953
|
// src/remote/phone-board-sync.ts
|
|
41504
|
-
var
|
|
41954
|
+
var import_node_path70 = require("path");
|
|
41505
41955
|
var import_chokidar = require("chokidar");
|
|
41506
41956
|
init_orchestrator();
|
|
41507
41957
|
init_paths();
|
|
@@ -41546,7 +41996,7 @@ function subscribePhoneBoard(notify) {
|
|
|
41546
41996
|
threads.on("error", () => void 0);
|
|
41547
41997
|
const data = (0, import_chokidar.watch)(appDataDir(), { ignoreInitial: true, depth: 0 });
|
|
41548
41998
|
const onData = (changed) => {
|
|
41549
|
-
const name = (0,
|
|
41999
|
+
const name = (0, import_node_path70.basename)(changed);
|
|
41550
42000
|
if (name !== "workspaces.json" && name !== "removed-workspaces.json" && name !== "settings.json") return;
|
|
41551
42001
|
notify();
|
|
41552
42002
|
};
|
|
@@ -41857,14 +42307,14 @@ init_fetch();
|
|
|
41857
42307
|
|
|
41858
42308
|
// src/relay/accounts.ts
|
|
41859
42309
|
var import_node_crypto27 = require("crypto");
|
|
41860
|
-
var
|
|
42310
|
+
var import_node_fs72 = require("fs");
|
|
41861
42311
|
var import_node_module7 = require("module");
|
|
41862
|
-
var
|
|
42312
|
+
var import_node_path71 = require("path");
|
|
41863
42313
|
var GITHUB_ACCOUNT_ISSUER = "https://github.com";
|
|
41864
42314
|
var RELAY_DEVICE_CAP = 3;
|
|
41865
42315
|
function thisModuleFile3() {
|
|
41866
42316
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
41867
|
-
return cjsFile || process.argv[1] || (0,
|
|
42317
|
+
return cjsFile || process.argv[1] || (0, import_node_path71.join)(process.cwd(), "package.json");
|
|
41868
42318
|
}
|
|
41869
42319
|
function openDatabase(filePath) {
|
|
41870
42320
|
const req = (0, import_node_module7.createRequire)(thisModuleFile3());
|
|
@@ -41901,8 +42351,8 @@ function assertRelayAccountsDurable(filePath) {
|
|
|
41901
42351
|
if (process.env.SIDEBOARD_RELAY_ACCOUNTS_EPHEMERAL === "1") return;
|
|
41902
42352
|
if (process.env.NODE_ENV !== "production") return;
|
|
41903
42353
|
if (process.platform !== "linux") return;
|
|
41904
|
-
const dir = (0,
|
|
41905
|
-
const mounts = (0,
|
|
42354
|
+
const dir = (0, import_node_fs72.realpathSync)((0, import_node_path71.dirname)(filePath));
|
|
42355
|
+
const mounts = (0, import_node_fs72.readFileSync)("/proc/mounts", "utf8");
|
|
41906
42356
|
const point = longestMountPoint(dir, mounts);
|
|
41907
42357
|
if (point === "/") {
|
|
41908
42358
|
throw new Error(
|
|
@@ -41913,7 +42363,7 @@ function assertRelayAccountsDurable(filePath) {
|
|
|
41913
42363
|
var RelayAccountStore = class {
|
|
41914
42364
|
db;
|
|
41915
42365
|
constructor(filePath) {
|
|
41916
|
-
(0,
|
|
42366
|
+
(0, import_node_fs72.mkdirSync)((0, import_node_path71.dirname)(filePath), { recursive: true });
|
|
41917
42367
|
this.db = openDatabase(filePath);
|
|
41918
42368
|
this.db.exec(`
|
|
41919
42369
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
@@ -42947,9 +43397,9 @@ var import_node_http5 = require("http");
|
|
|
42947
43397
|
var import_ws6 = require("ws");
|
|
42948
43398
|
|
|
42949
43399
|
// src/relay/static.ts
|
|
42950
|
-
var
|
|
43400
|
+
var import_node_fs73 = require("fs");
|
|
42951
43401
|
var import_promises = require("fs/promises");
|
|
42952
|
-
var
|
|
43402
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
42953
43403
|
var TYPES = {
|
|
42954
43404
|
".css": "text/css; charset=utf-8",
|
|
42955
43405
|
".html": "text/html; charset=utf-8",
|
|
@@ -42980,9 +43430,9 @@ function resolveStaticPath(root, requestUrl) {
|
|
|
42980
43430
|
return null;
|
|
42981
43431
|
}
|
|
42982
43432
|
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
42983
|
-
const rootResolved =
|
|
42984
|
-
const candidate =
|
|
42985
|
-
if (candidate !== rootResolved && !candidate.startsWith(rootResolved +
|
|
43433
|
+
const rootResolved = import_node_path72.default.resolve(root);
|
|
43434
|
+
const candidate = import_node_path72.default.resolve(rootResolved, `.${pathname}`);
|
|
43435
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path72.default.sep)) {
|
|
42986
43436
|
return null;
|
|
42987
43437
|
}
|
|
42988
43438
|
return candidate;
|
|
@@ -42996,7 +43446,7 @@ async function fileSize(file) {
|
|
|
42996
43446
|
}
|
|
42997
43447
|
}
|
|
42998
43448
|
function sendFile(req, res, file, size) {
|
|
42999
|
-
const ext =
|
|
43449
|
+
const ext = import_node_path72.default.extname(file).toLowerCase();
|
|
43000
43450
|
res.writeHead(200, {
|
|
43001
43451
|
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
43002
43452
|
"Content-Length": size,
|
|
@@ -43006,7 +43456,7 @@ function sendFile(req, res, file, size) {
|
|
|
43006
43456
|
res.end();
|
|
43007
43457
|
return true;
|
|
43008
43458
|
}
|
|
43009
|
-
(0,
|
|
43459
|
+
(0, import_node_fs73.createReadStream)(file).pipe(res);
|
|
43010
43460
|
return true;
|
|
43011
43461
|
}
|
|
43012
43462
|
async function tryServeStatic(req, res, root) {
|
|
@@ -43015,7 +43465,7 @@ async function tryServeStatic(req, res, root) {
|
|
|
43015
43465
|
if (!candidate) return false;
|
|
43016
43466
|
const direct = await fileSize(candidate);
|
|
43017
43467
|
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
43018
|
-
const asIndex =
|
|
43468
|
+
const asIndex = import_node_path72.default.join(candidate, "index.html");
|
|
43019
43469
|
const indexSize = await fileSize(asIndex);
|
|
43020
43470
|
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
43021
43471
|
return false;
|
|
@@ -43380,8 +43830,8 @@ async function startRelayServer(opts) {
|
|
|
43380
43830
|
}
|
|
43381
43831
|
|
|
43382
43832
|
// src/slack/outbound-watch.ts
|
|
43383
|
-
var
|
|
43384
|
-
var
|
|
43833
|
+
var import_node_fs74 = require("fs");
|
|
43834
|
+
var import_node_path73 = require("path");
|
|
43385
43835
|
init_paths();
|
|
43386
43836
|
init_private_file();
|
|
43387
43837
|
init_secure_file();
|
|
@@ -43394,7 +43844,7 @@ var POLL_INTERVAL_MS = 12e3;
|
|
|
43394
43844
|
var lastPollMs = 0;
|
|
43395
43845
|
var nameCache = /* @__PURE__ */ new Map();
|
|
43396
43846
|
function storePath4() {
|
|
43397
|
-
return (0,
|
|
43847
|
+
return (0, import_node_path73.join)(appDataDir(), "slack-outbound-watch.json");
|
|
43398
43848
|
}
|
|
43399
43849
|
function watchId(teamId, channelId, ts) {
|
|
43400
43850
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -43407,9 +43857,9 @@ function tsNewer(a, b) {
|
|
|
43407
43857
|
}
|
|
43408
43858
|
function readStore4() {
|
|
43409
43859
|
const path2 = storePath4();
|
|
43410
|
-
if (!(0,
|
|
43860
|
+
if (!(0, import_node_fs74.existsSync)(path2)) return [];
|
|
43411
43861
|
try {
|
|
43412
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
43862
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs74.readFileSync)(path2, "utf8"));
|
|
43413
43863
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
43414
43864
|
} catch {
|
|
43415
43865
|
return [];
|