@sideboard-ai/core 0.1.289 → 0.1.291
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 +599 -98
- package/dist/index.js +565 -75
- 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,327 @@ 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-code-refs.ts
|
|
40508
|
+
var MAX_REFS = 8;
|
|
40509
|
+
var MAX_TEXT = 2e4;
|
|
40510
|
+
var MAX_TOTAL = 4e4;
|
|
40511
|
+
function lineNumber(value, key) {
|
|
40512
|
+
const raw = value[key];
|
|
40513
|
+
if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 1 || raw > 1e6) return void 0;
|
|
40514
|
+
return raw;
|
|
40515
|
+
}
|
|
40516
|
+
function parsePhoneCodeRefs(value) {
|
|
40517
|
+
if (value == null) return [];
|
|
40518
|
+
if (!Array.isArray(value) || value.length > MAX_REFS) return "invalid";
|
|
40519
|
+
const refs = [];
|
|
40520
|
+
let total = 0;
|
|
40521
|
+
for (const item of value) {
|
|
40522
|
+
if (!item || typeof item !== "object") return "invalid";
|
|
40523
|
+
const pathRaw = item.path;
|
|
40524
|
+
const path2 = typeof pathRaw === "string" ? pathRaw.trim().replace(/\\/g, "/").slice(0, 500) : "";
|
|
40525
|
+
const startLine = lineNumber(item, "startLine");
|
|
40526
|
+
const endLine = lineNumber(item, "endLine");
|
|
40527
|
+
const textRaw = item.text;
|
|
40528
|
+
const text7 = typeof textRaw === "string" ? textRaw.replace(/\n$/, "").slice(0, MAX_TEXT) : "";
|
|
40529
|
+
if (!path2 || !startLine || !endLine || endLine < startLine || !text7.trim()) return "invalid";
|
|
40530
|
+
total += text7.length;
|
|
40531
|
+
if (total > MAX_TOTAL) return "invalid";
|
|
40532
|
+
refs.push({ path: path2, startLine, endLine, text: text7 });
|
|
40533
|
+
}
|
|
40534
|
+
return refs;
|
|
40535
|
+
}
|
|
40536
|
+
|
|
40537
|
+
// src/remote/phone-panes.ts
|
|
40538
|
+
init_orchestrator();
|
|
40539
|
+
var MAX_ROWS = 200;
|
|
40540
|
+
var MAX_QUERY = 200;
|
|
40541
|
+
function parsePhonePane(value, chatId) {
|
|
40542
|
+
const pane = value && typeof value === "object" ? value.pane : void 0;
|
|
40543
|
+
if (pane !== "files" && pane !== "changes" && pane !== "checks") return "invalid";
|
|
40544
|
+
const scopeRaw = value.scope;
|
|
40545
|
+
const scope = scopeRaw === "uncommitted" || scopeRaw === "commits" ? scopeRaw : void 0;
|
|
40546
|
+
const queryRaw = value.query;
|
|
40547
|
+
const query = typeof queryRaw === "string" ? queryRaw.trim().slice(0, MAX_QUERY) : "";
|
|
40548
|
+
return {
|
|
40549
|
+
op: "pane",
|
|
40550
|
+
chatId,
|
|
40551
|
+
pane,
|
|
40552
|
+
...scope && pane === "changes" ? { scope } : {},
|
|
40553
|
+
...query && pane === "files" ? { query } : {}
|
|
40554
|
+
};
|
|
40555
|
+
}
|
|
40556
|
+
function filterPhoneFiles(paths, query) {
|
|
40557
|
+
const q = query.trim().toLowerCase();
|
|
40558
|
+
if (!q) return paths;
|
|
40559
|
+
return paths.filter((path2) => path2.toLowerCase().includes(q));
|
|
40560
|
+
}
|
|
40561
|
+
async function readPhonePane(thread, pane, scope, query) {
|
|
40562
|
+
try {
|
|
40563
|
+
if (pane === "files") return await readFiles(thread.id, query);
|
|
40564
|
+
if (pane === "changes") return await readChanges(thread.id, scope ?? "commits");
|
|
40565
|
+
return await readChecks(thread.id);
|
|
40566
|
+
} catch (err) {
|
|
40567
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40568
|
+
return { rows: [], note: message };
|
|
40569
|
+
}
|
|
40570
|
+
}
|
|
40571
|
+
async function readFiles(threadId, query) {
|
|
40572
|
+
const paths = filterPhoneFiles(await getOrchestrator().listFiles(threadId), query ?? "");
|
|
40573
|
+
const shown = paths.slice(0, MAX_ROWS);
|
|
40574
|
+
const extra = paths.length - shown.length;
|
|
40575
|
+
const note = extra > 0 ? query?.trim() ? `${extra} more matching files` : `${extra} more files on the Mac` : void 0;
|
|
40576
|
+
return {
|
|
40577
|
+
rows: shown.map((path2) => ({ label: path2, path: path2 })),
|
|
40578
|
+
...note ? { note } : {}
|
|
40579
|
+
};
|
|
40580
|
+
}
|
|
40581
|
+
async function readChanges(threadId, scope) {
|
|
40582
|
+
const diff = await getOrchestrator().diff(threadId, { includePatches: false, scope });
|
|
40583
|
+
const shown = diff.files.slice(0, MAX_ROWS);
|
|
40584
|
+
return {
|
|
40585
|
+
rows: shown.map((file) => ({
|
|
40586
|
+
label: file.path,
|
|
40587
|
+
path: file.path,
|
|
40588
|
+
detail: changeDetail(file.additions, file.deletions)
|
|
40589
|
+
})),
|
|
40590
|
+
...diff.files.length > shown.length ? { note: `${diff.files.length - shown.length} more changed files` } : {}
|
|
40591
|
+
};
|
|
40592
|
+
}
|
|
40593
|
+
function changeDetail(additions, deletions) {
|
|
40594
|
+
const add = additions ?? 0;
|
|
40595
|
+
const del = deletions ?? 0;
|
|
40596
|
+
if (add === 0 && del === 0) return void 0;
|
|
40597
|
+
return `+${add} \u2212${del}`;
|
|
40598
|
+
}
|
|
40599
|
+
async function readChecks(threadId) {
|
|
40600
|
+
const checks = await getOrchestrator().getPrChecks(threadId);
|
|
40601
|
+
if (!checks) return { rows: [], note: "No pull request on this branch." };
|
|
40602
|
+
const shown = checks.slice(0, MAX_ROWS);
|
|
40603
|
+
return {
|
|
40604
|
+
rows: shown.map((check) => ({
|
|
40605
|
+
label: check.name,
|
|
40606
|
+
detail: check.bucket || check.state,
|
|
40607
|
+
...check.link ? { href: check.link } : {}
|
|
40608
|
+
}))
|
|
40609
|
+
};
|
|
40610
|
+
}
|
|
40230
40611
|
|
|
40231
40612
|
// src/remote/phone-defaults.ts
|
|
40232
40613
|
init_app_settings();
|
|
@@ -40332,10 +40713,63 @@ function listPhoneMessages(thread) {
|
|
|
40332
40713
|
return live.slice(-TRANSCRIPT_LIMIT);
|
|
40333
40714
|
}
|
|
40334
40715
|
|
|
40335
|
-
// src/remote/phone-
|
|
40336
|
-
|
|
40716
|
+
// src/remote/phone-history.ts
|
|
40717
|
+
init_global_workspace();
|
|
40718
|
+
init_thread_store();
|
|
40337
40719
|
var PREVIEW_LIMIT = 90;
|
|
40338
40720
|
var HISTORY_PAGE_SIZE = 40;
|
|
40721
|
+
function previewOf(thread) {
|
|
40722
|
+
const messages = listPhoneMessages(thread);
|
|
40723
|
+
const last = messages[messages.length - 1];
|
|
40724
|
+
if (!last) return "";
|
|
40725
|
+
return clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT);
|
|
40726
|
+
}
|
|
40727
|
+
function repoName(repoPath) {
|
|
40728
|
+
const parts = repoPath.replace(/\/$/, "").split("/");
|
|
40729
|
+
return parts[parts.length - 1] || repoPath;
|
|
40730
|
+
}
|
|
40731
|
+
function isProjectPath(path2) {
|
|
40732
|
+
if (!path2 || path2 === "/" || path2 === ".") return false;
|
|
40733
|
+
return !isGlobalThread({ repoPath: path2 });
|
|
40734
|
+
}
|
|
40735
|
+
function historyStamp(thread) {
|
|
40736
|
+
return thread.archivedAt || thread.updatedAt;
|
|
40737
|
+
}
|
|
40738
|
+
function historyCursor(chat) {
|
|
40739
|
+
return `${chat.updatedAt} ${chat.id}`;
|
|
40740
|
+
}
|
|
40741
|
+
function listPhoneHistory(opts) {
|
|
40742
|
+
const query = opts?.query?.trim().toLowerCase() ?? "";
|
|
40743
|
+
const after = opts?.after?.trim() ?? "";
|
|
40744
|
+
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) => ({
|
|
40745
|
+
id: thread.id,
|
|
40746
|
+
title: thread.title?.trim() || "Untitled",
|
|
40747
|
+
preview: previewOf(thread),
|
|
40748
|
+
updatedAt: historyStamp(thread),
|
|
40749
|
+
where: isGlobalThread(thread) ? "Orchestration" : repoName(thread.repoPath),
|
|
40750
|
+
agent: thread.agent
|
|
40751
|
+
})).filter((chat) => {
|
|
40752
|
+
if (!query) return true;
|
|
40753
|
+
return `${chat.title} ${chat.where} ${chat.agent} ${chat.preview}`.toLowerCase().includes(query);
|
|
40754
|
+
});
|
|
40755
|
+
let start = 0;
|
|
40756
|
+
if (after) {
|
|
40757
|
+
const index = all.findIndex((chat) => historyCursor(chat) === after);
|
|
40758
|
+
start = index >= 0 ? index + 1 : all.length;
|
|
40759
|
+
}
|
|
40760
|
+
const chats = all.slice(start, start + HISTORY_PAGE_SIZE);
|
|
40761
|
+
const last = chats.at(-1);
|
|
40762
|
+
const more = start + chats.length < all.length;
|
|
40763
|
+
return {
|
|
40764
|
+
chats,
|
|
40765
|
+
total: all.length,
|
|
40766
|
+
...more && last ? { next: historyCursor(last) } : {}
|
|
40767
|
+
};
|
|
40768
|
+
}
|
|
40769
|
+
|
|
40770
|
+
// src/remote/phone-chats.ts
|
|
40771
|
+
var PHONE_CONTROL_PREFIX = "\0sb.phone\n";
|
|
40772
|
+
var PREVIEW_LIMIT2 = 90;
|
|
40339
40773
|
var AGENT_KINDS = /* @__PURE__ */ new Set(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
40340
40774
|
var MAX_PHONE_FILES = 8;
|
|
40341
40775
|
var MAX_PHONE_FILE_CHARS = Math.ceil(8 * 1024 * 1024 * 4 / 3);
|
|
@@ -40365,7 +40799,7 @@ function parsePhoneControl(value) {
|
|
|
40365
40799
|
}
|
|
40366
40800
|
if (op === "sources") {
|
|
40367
40801
|
const repoPath = textField(value, "repoPath");
|
|
40368
|
-
if (!repoPath || !
|
|
40802
|
+
if (!repoPath || !isProjectPath2(repoPath)) return "invalid";
|
|
40369
40803
|
const query = textField(value, "query");
|
|
40370
40804
|
return { op: "sources", repoPath, ...query ? { query } : {} };
|
|
40371
40805
|
}
|
|
@@ -40383,7 +40817,15 @@ function parsePhoneControl(value) {
|
|
|
40383
40817
|
if (op === "create") return parsePhoneCreate(value);
|
|
40384
40818
|
const chatId = typeof value.chatId === "string" ? value.chatId.trim() : "";
|
|
40385
40819
|
if (!chatId) return "invalid";
|
|
40386
|
-
if (op === "open" || op === "archive" || op === "restore" || op === "stop"
|
|
40820
|
+
if (op === "open" || op === "archive" || op === "restore" || op === "stop" || op === "review" || op === "header") {
|
|
40821
|
+
return { op, chatId };
|
|
40822
|
+
}
|
|
40823
|
+
if (op === "git") {
|
|
40824
|
+
const action = textField(value, "action");
|
|
40825
|
+
if (!PHONE_HEADER_GIT_ACTIONS.includes(action)) return "invalid";
|
|
40826
|
+
return { op: "git", chatId, action };
|
|
40827
|
+
}
|
|
40828
|
+
if (op === "pane") return parsePhonePane(value, chatId);
|
|
40387
40829
|
if (op === "open-artifact") return parseOpenArtifact(value, chatId);
|
|
40388
40830
|
if (op === "open-file" || op === "media") {
|
|
40389
40831
|
const path2 = textField(value, "path");
|
|
@@ -40404,7 +40846,7 @@ function parsePhoneControl(value) {
|
|
|
40404
40846
|
if (op === "options") return { op: "options", chatId, ...draft };
|
|
40405
40847
|
if (op === "prompt") {
|
|
40406
40848
|
const text7 = typeof value.text === "string" ? value.text.trim() : "";
|
|
40407
|
-
const hasPayload = Boolean(text7 || draft.files?.length || draft.links?.length);
|
|
40849
|
+
const hasPayload = Boolean(text7 || draft.files?.length || draft.links?.length || draft.refs?.length);
|
|
40408
40850
|
if (!hasPayload) return "invalid";
|
|
40409
40851
|
return { op: "prompt", chatId, text: text7, ...draft };
|
|
40410
40852
|
}
|
|
@@ -40468,6 +40910,9 @@ function parsePhoneDraft(value) {
|
|
|
40468
40910
|
const links = parsePhoneLinks(value.links);
|
|
40469
40911
|
if (links === "invalid") return "invalid";
|
|
40470
40912
|
if (links.length) draft.links = links;
|
|
40913
|
+
const refs = parsePhoneCodeRefs(value.refs);
|
|
40914
|
+
if (refs === "invalid") return "invalid";
|
|
40915
|
+
if (refs.length) draft.refs = refs;
|
|
40471
40916
|
const prompt = textField(value, "prompt");
|
|
40472
40917
|
if (prompt) draft.prompt = prompt.slice(0, 2e4);
|
|
40473
40918
|
return draft;
|
|
@@ -40523,7 +40968,7 @@ function parsePhoneCreate(value) {
|
|
|
40523
40968
|
}
|
|
40524
40969
|
if (where === "project") {
|
|
40525
40970
|
const repoPath = textField(value, "repoPath");
|
|
40526
|
-
if (!repoPath || !
|
|
40971
|
+
if (!repoPath || !isProjectPath2(repoPath)) return "invalid";
|
|
40527
40972
|
const sourceRaw = textField(value, "sourceType");
|
|
40528
40973
|
let sourceType;
|
|
40529
40974
|
if (sourceRaw === "branch" || sourceRaw === "pr" || sourceRaw === "ticket") sourceType = sourceRaw;
|
|
@@ -40546,26 +40991,30 @@ function parsePhoneCreate(value) {
|
|
|
40546
40991
|
return "invalid";
|
|
40547
40992
|
}
|
|
40548
40993
|
function summarize(thread) {
|
|
40994
|
+
const pr = phonePrPill(thread);
|
|
40549
40995
|
return {
|
|
40550
40996
|
id: thread.id,
|
|
40551
40997
|
title: thread.title?.trim() || "Untitled",
|
|
40552
40998
|
status: thread.status,
|
|
40553
|
-
preview:
|
|
40999
|
+
preview: previewOf2(thread),
|
|
40554
41000
|
updatedAt: thread.updatedAt,
|
|
40555
|
-
agent: thread.agent
|
|
41001
|
+
agent: thread.agent,
|
|
41002
|
+
...pr?.url ? { prUrl: pr.url } : {},
|
|
41003
|
+
...pr?.number ? { prNumber: pr.number } : {},
|
|
41004
|
+
...pr?.status ? { prStatus: pr.status } : {}
|
|
40556
41005
|
};
|
|
40557
41006
|
}
|
|
40558
|
-
function
|
|
41007
|
+
function previewOf2(thread) {
|
|
40559
41008
|
const messages = listPhoneMessages(thread);
|
|
40560
41009
|
const last = messages[messages.length - 1];
|
|
40561
41010
|
if (!last) return "";
|
|
40562
|
-
return clip(last.text.replace(/\s+/g, " ").trim(),
|
|
41011
|
+
return clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT2);
|
|
40563
41012
|
}
|
|
40564
|
-
function
|
|
41013
|
+
function repoName2(repoPath) {
|
|
40565
41014
|
const parts = repoPath.replace(/\/$/, "").split("/");
|
|
40566
41015
|
return parts[parts.length - 1] || repoPath;
|
|
40567
41016
|
}
|
|
40568
|
-
function
|
|
41017
|
+
function isProjectPath2(path2) {
|
|
40569
41018
|
if (!path2 || path2 === "/" || path2 === ".") return false;
|
|
40570
41019
|
return !isGlobalThread({ repoPath: path2 });
|
|
40571
41020
|
}
|
|
@@ -40577,17 +41026,17 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
|
|
|
40577
41026
|
const threads = listThreads();
|
|
40578
41027
|
const byRepo = /* @__PURE__ */ new Map();
|
|
40579
41028
|
for (const thread of threads) {
|
|
40580
|
-
if (!
|
|
41029
|
+
if (!isProjectPath2(thread.repoPath) || isRemovedWorkspace(thread.repoPath)) continue;
|
|
40581
41030
|
const list = byRepo.get(thread.repoPath) ?? [];
|
|
40582
41031
|
list.push(thread);
|
|
40583
41032
|
byRepo.set(thread.repoPath, list);
|
|
40584
41033
|
}
|
|
40585
41034
|
for (const workspace of listWorkspaces()) {
|
|
40586
|
-
if (!
|
|
41035
|
+
if (!isProjectPath2(workspace.path) || byRepo.has(workspace.path)) continue;
|
|
40587
41036
|
byRepo.set(workspace.path, []);
|
|
40588
41037
|
}
|
|
40589
|
-
const projects = [...byRepo.entries()].sort(([a], [b]) =>
|
|
40590
|
-
name:
|
|
41038
|
+
const projects = [...byRepo.entries()].sort(([a], [b]) => repoName2(a).localeCompare(repoName2(b))).map(([path2, repoThreads]) => ({
|
|
41039
|
+
name: repoName2(path2),
|
|
40591
41040
|
path: path2,
|
|
40592
41041
|
worktrees: groupHomeBoardWorktrees(repoThreads).map((group) => {
|
|
40593
41042
|
const tags = workspaceTagsFromGroup(group);
|
|
@@ -40606,41 +41055,6 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
|
|
|
40606
41055
|
}));
|
|
40607
41056
|
return { orchestration: listPhoneChats(), projects, defaults: phoneAccountDefaults() };
|
|
40608
41057
|
}
|
|
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
41058
|
function matchPhoneThread(chatId) {
|
|
40645
41059
|
const id = chatId.trim();
|
|
40646
41060
|
if (!id) return null;
|
|
@@ -40653,7 +41067,7 @@ function matchPhoneThread(chatId) {
|
|
|
40653
41067
|
}
|
|
40654
41068
|
function visiblePhoneThread(thread) {
|
|
40655
41069
|
if (isGlobalThread(thread)) return true;
|
|
40656
|
-
return
|
|
41070
|
+
return isProjectPath2(thread.repoPath);
|
|
40657
41071
|
}
|
|
40658
41072
|
function findPhoneChat(chatId) {
|
|
40659
41073
|
const thread = matchPhoneThread(chatId);
|
|
@@ -40719,7 +41133,7 @@ function projectPlace(thread) {
|
|
|
40719
41133
|
}
|
|
40720
41134
|
function assertKnownProject(repoPath) {
|
|
40721
41135
|
const path2 = repoPath.trim();
|
|
40722
|
-
if (!
|
|
41136
|
+
if (!isProjectPath2(path2)) throw new Error("Pick a project on this Mac.");
|
|
40723
41137
|
const known = listWorkspaces().some((workspace) => sameRepoPath3(workspace.path, path2)) || listThreads().some(
|
|
40724
41138
|
(thread) => thread.status !== "archived" && sameRepoPath3(thread.repoPath, path2)
|
|
40725
41139
|
);
|
|
@@ -40822,6 +41236,56 @@ function archivePhoneChat(chatId) {
|
|
|
40822
41236
|
return true;
|
|
40823
41237
|
}
|
|
40824
41238
|
|
|
41239
|
+
// src/remote/phone-workspace-ops.ts
|
|
41240
|
+
function dispatchPhoneWorkspace(cmd, emit, publishOpened) {
|
|
41241
|
+
if (cmd.op === "pane") {
|
|
41242
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
41243
|
+
if (!thread) {
|
|
41244
|
+
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
41245
|
+
return;
|
|
41246
|
+
}
|
|
41247
|
+
void readPhonePane(thread, cmd.pane, cmd.scope, cmd.query).then((body) => {
|
|
41248
|
+
emit({
|
|
41249
|
+
op: "pane",
|
|
41250
|
+
chatId: cmd.chatId,
|
|
41251
|
+
pane: cmd.pane,
|
|
41252
|
+
rows: body.rows,
|
|
41253
|
+
...body.note ? { note: body.note } : {},
|
|
41254
|
+
...cmd.pane === "files" ? { query: cmd.query ?? "" } : {}
|
|
41255
|
+
});
|
|
41256
|
+
});
|
|
41257
|
+
return;
|
|
41258
|
+
}
|
|
41259
|
+
if (cmd.op === "header") {
|
|
41260
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
41261
|
+
if (!thread) {
|
|
41262
|
+
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
41263
|
+
return;
|
|
41264
|
+
}
|
|
41265
|
+
void readPhoneHeader(thread).then((header) => {
|
|
41266
|
+
emit({ op: "header", chatId: cmd.chatId, ...header });
|
|
41267
|
+
});
|
|
41268
|
+
return;
|
|
41269
|
+
}
|
|
41270
|
+
if (cmd.op === "git") {
|
|
41271
|
+
void getOrchestrator().askGit(cmd.chatId, cmd.action).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
41272
|
+
emit({
|
|
41273
|
+
op: "error",
|
|
41274
|
+
chatId: cmd.chatId,
|
|
41275
|
+
message: err instanceof Error ? err.message : String(err)
|
|
41276
|
+
});
|
|
41277
|
+
});
|
|
41278
|
+
return;
|
|
41279
|
+
}
|
|
41280
|
+
void getOrchestrator().requestReview(cmd.chatId).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
41281
|
+
emit({
|
|
41282
|
+
op: "error",
|
|
41283
|
+
chatId: cmd.chatId,
|
|
41284
|
+
message: err instanceof Error ? err.message : String(err)
|
|
41285
|
+
});
|
|
41286
|
+
});
|
|
41287
|
+
}
|
|
41288
|
+
|
|
40825
41289
|
// src/remote/phone-sources.ts
|
|
40826
41290
|
init_worktree();
|
|
40827
41291
|
function sourceWarning(label, err) {
|
|
@@ -41197,7 +41661,8 @@ function stagePhoneTurnFiles(worktreePath, draft) {
|
|
|
41197
41661
|
worktreePath,
|
|
41198
41662
|
(draft.files ?? []).map((file) => ({ name: file.name, dataBase64: file.dataBase64 }))
|
|
41199
41663
|
);
|
|
41200
|
-
|
|
41664
|
+
const refs = (draft.refs ?? []).map((ref) => buildCodeRefAttachment(ref));
|
|
41665
|
+
return [...links, ...files, ...refs];
|
|
41201
41666
|
}
|
|
41202
41667
|
function handlePhoneControl(cmd, opts) {
|
|
41203
41668
|
const log = opts.onLog ?? (() => void 0);
|
|
@@ -41398,10 +41863,25 @@ function handlePhoneControl(cmd, opts) {
|
|
|
41398
41863
|
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That file is not in this worktree." });
|
|
41399
41864
|
return;
|
|
41400
41865
|
}
|
|
41401
|
-
|
|
41402
|
-
|
|
41866
|
+
const preview = phoneFilePreview(thread.worktreePath, relative, kind === "dir" ? "dir" : "file");
|
|
41867
|
+
if (!preview) {
|
|
41868
|
+
emitControl(opts, {
|
|
41869
|
+
op: "error",
|
|
41870
|
+
chatId: cmd.chatId,
|
|
41871
|
+
message: "That file could not be opened on the phone."
|
|
41872
|
+
});
|
|
41873
|
+
return;
|
|
41874
|
+
}
|
|
41875
|
+
emitControl(opts, {
|
|
41876
|
+
op: "file",
|
|
41877
|
+
chatId: cmd.chatId,
|
|
41403
41878
|
path: relative,
|
|
41404
|
-
|
|
41879
|
+
content: preview.content,
|
|
41880
|
+
encoding: preview.encoding,
|
|
41881
|
+
...preview.binary ? { binary: true } : {},
|
|
41882
|
+
...preview.directory ? { directory: true } : {},
|
|
41883
|
+
...preview.truncated ? { truncated: true } : {},
|
|
41884
|
+
...preview.mime ? { mime: preview.mime } : {},
|
|
41405
41885
|
...cmd.startLine != null ? { startLine: cmd.startLine } : {},
|
|
41406
41886
|
...cmd.endLine != null ? { endLine: cmd.endLine } : {}
|
|
41407
41887
|
});
|
|
@@ -41416,13 +41896,34 @@ function handlePhoneControl(cmd, opts) {
|
|
|
41416
41896
|
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
41417
41897
|
return;
|
|
41418
41898
|
}
|
|
41419
|
-
|
|
41420
|
-
|
|
41421
|
-
|
|
41422
|
-
|
|
41899
|
+
const liveParts = readTurnLiveParts(thread.id);
|
|
41900
|
+
const docs = phoneArtifactDocuments([
|
|
41901
|
+
...(thread.messages ?? []).filter((message) => message.role === "agent").map((message) => ({ text: message.text.trim(), parts: message.parts })),
|
|
41902
|
+
{ text: visibleAssistantText(void 0, liveParts), parts: liveParts }
|
|
41903
|
+
]);
|
|
41904
|
+
const body = phoneArtifactReply(docs, { title: cmd.title, ...cmd.hint ? { hint: cmd.hint } : {} });
|
|
41905
|
+
if (!body) {
|
|
41906
|
+
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That artifact is not in this chat." });
|
|
41907
|
+
return;
|
|
41908
|
+
}
|
|
41909
|
+
emitControl(opts, {
|
|
41910
|
+
op: "artifact",
|
|
41911
|
+
chatId: cmd.chatId,
|
|
41912
|
+
title: body.title,
|
|
41913
|
+
kind: body.kind,
|
|
41914
|
+
content: body.content,
|
|
41915
|
+
...body.truncated ? { truncated: true } : {}
|
|
41423
41916
|
});
|
|
41424
41917
|
return;
|
|
41425
41918
|
}
|
|
41919
|
+
if (cmd.op === "pane" || cmd.op === "header" || cmd.op === "git" || cmd.op === "review") {
|
|
41920
|
+
dispatchPhoneWorkspace(
|
|
41921
|
+
cmd,
|
|
41922
|
+
(reply) => emitControl(opts, reply),
|
|
41923
|
+
(chatId2) => publishOpenedChat(opts, chatId2)
|
|
41924
|
+
);
|
|
41925
|
+
return;
|
|
41926
|
+
}
|
|
41426
41927
|
if (cmd.op === "stop") {
|
|
41427
41928
|
if (!readPhoneThread(cmd.chatId)) {
|
|
41428
41929
|
emitControl(opts, { op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
@@ -41501,7 +42002,7 @@ function handleRemoteInbound(text7, opts) {
|
|
|
41501
42002
|
}
|
|
41502
42003
|
|
|
41503
42004
|
// src/remote/phone-board-sync.ts
|
|
41504
|
-
var
|
|
42005
|
+
var import_node_path70 = require("path");
|
|
41505
42006
|
var import_chokidar = require("chokidar");
|
|
41506
42007
|
init_orchestrator();
|
|
41507
42008
|
init_paths();
|
|
@@ -41546,7 +42047,7 @@ function subscribePhoneBoard(notify) {
|
|
|
41546
42047
|
threads.on("error", () => void 0);
|
|
41547
42048
|
const data = (0, import_chokidar.watch)(appDataDir(), { ignoreInitial: true, depth: 0 });
|
|
41548
42049
|
const onData = (changed) => {
|
|
41549
|
-
const name = (0,
|
|
42050
|
+
const name = (0, import_node_path70.basename)(changed);
|
|
41550
42051
|
if (name !== "workspaces.json" && name !== "removed-workspaces.json" && name !== "settings.json") return;
|
|
41551
42052
|
notify();
|
|
41552
42053
|
};
|
|
@@ -41857,14 +42358,14 @@ init_fetch();
|
|
|
41857
42358
|
|
|
41858
42359
|
// src/relay/accounts.ts
|
|
41859
42360
|
var import_node_crypto27 = require("crypto");
|
|
41860
|
-
var
|
|
42361
|
+
var import_node_fs72 = require("fs");
|
|
41861
42362
|
var import_node_module7 = require("module");
|
|
41862
|
-
var
|
|
42363
|
+
var import_node_path71 = require("path");
|
|
41863
42364
|
var GITHUB_ACCOUNT_ISSUER = "https://github.com";
|
|
41864
42365
|
var RELAY_DEVICE_CAP = 3;
|
|
41865
42366
|
function thisModuleFile3() {
|
|
41866
42367
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
41867
|
-
return cjsFile || process.argv[1] || (0,
|
|
42368
|
+
return cjsFile || process.argv[1] || (0, import_node_path71.join)(process.cwd(), "package.json");
|
|
41868
42369
|
}
|
|
41869
42370
|
function openDatabase(filePath) {
|
|
41870
42371
|
const req = (0, import_node_module7.createRequire)(thisModuleFile3());
|
|
@@ -41901,8 +42402,8 @@ function assertRelayAccountsDurable(filePath) {
|
|
|
41901
42402
|
if (process.env.SIDEBOARD_RELAY_ACCOUNTS_EPHEMERAL === "1") return;
|
|
41902
42403
|
if (process.env.NODE_ENV !== "production") return;
|
|
41903
42404
|
if (process.platform !== "linux") return;
|
|
41904
|
-
const dir = (0,
|
|
41905
|
-
const mounts = (0,
|
|
42405
|
+
const dir = (0, import_node_fs72.realpathSync)((0, import_node_path71.dirname)(filePath));
|
|
42406
|
+
const mounts = (0, import_node_fs72.readFileSync)("/proc/mounts", "utf8");
|
|
41906
42407
|
const point = longestMountPoint(dir, mounts);
|
|
41907
42408
|
if (point === "/") {
|
|
41908
42409
|
throw new Error(
|
|
@@ -41913,7 +42414,7 @@ function assertRelayAccountsDurable(filePath) {
|
|
|
41913
42414
|
var RelayAccountStore = class {
|
|
41914
42415
|
db;
|
|
41915
42416
|
constructor(filePath) {
|
|
41916
|
-
(0,
|
|
42417
|
+
(0, import_node_fs72.mkdirSync)((0, import_node_path71.dirname)(filePath), { recursive: true });
|
|
41917
42418
|
this.db = openDatabase(filePath);
|
|
41918
42419
|
this.db.exec(`
|
|
41919
42420
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
@@ -42947,9 +43448,9 @@ var import_node_http5 = require("http");
|
|
|
42947
43448
|
var import_ws6 = require("ws");
|
|
42948
43449
|
|
|
42949
43450
|
// src/relay/static.ts
|
|
42950
|
-
var
|
|
43451
|
+
var import_node_fs73 = require("fs");
|
|
42951
43452
|
var import_promises = require("fs/promises");
|
|
42952
|
-
var
|
|
43453
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
42953
43454
|
var TYPES = {
|
|
42954
43455
|
".css": "text/css; charset=utf-8",
|
|
42955
43456
|
".html": "text/html; charset=utf-8",
|
|
@@ -42980,9 +43481,9 @@ function resolveStaticPath(root, requestUrl) {
|
|
|
42980
43481
|
return null;
|
|
42981
43482
|
}
|
|
42982
43483
|
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
42983
|
-
const rootResolved =
|
|
42984
|
-
const candidate =
|
|
42985
|
-
if (candidate !== rootResolved && !candidate.startsWith(rootResolved +
|
|
43484
|
+
const rootResolved = import_node_path72.default.resolve(root);
|
|
43485
|
+
const candidate = import_node_path72.default.resolve(rootResolved, `.${pathname}`);
|
|
43486
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path72.default.sep)) {
|
|
42986
43487
|
return null;
|
|
42987
43488
|
}
|
|
42988
43489
|
return candidate;
|
|
@@ -42996,7 +43497,7 @@ async function fileSize(file) {
|
|
|
42996
43497
|
}
|
|
42997
43498
|
}
|
|
42998
43499
|
function sendFile(req, res, file, size) {
|
|
42999
|
-
const ext =
|
|
43500
|
+
const ext = import_node_path72.default.extname(file).toLowerCase();
|
|
43000
43501
|
res.writeHead(200, {
|
|
43001
43502
|
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
43002
43503
|
"Content-Length": size,
|
|
@@ -43006,7 +43507,7 @@ function sendFile(req, res, file, size) {
|
|
|
43006
43507
|
res.end();
|
|
43007
43508
|
return true;
|
|
43008
43509
|
}
|
|
43009
|
-
(0,
|
|
43510
|
+
(0, import_node_fs73.createReadStream)(file).pipe(res);
|
|
43010
43511
|
return true;
|
|
43011
43512
|
}
|
|
43012
43513
|
async function tryServeStatic(req, res, root) {
|
|
@@ -43015,7 +43516,7 @@ async function tryServeStatic(req, res, root) {
|
|
|
43015
43516
|
if (!candidate) return false;
|
|
43016
43517
|
const direct = await fileSize(candidate);
|
|
43017
43518
|
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
43018
|
-
const asIndex =
|
|
43519
|
+
const asIndex = import_node_path72.default.join(candidate, "index.html");
|
|
43019
43520
|
const indexSize = await fileSize(asIndex);
|
|
43020
43521
|
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
43021
43522
|
return false;
|
|
@@ -43380,8 +43881,8 @@ async function startRelayServer(opts) {
|
|
|
43380
43881
|
}
|
|
43381
43882
|
|
|
43382
43883
|
// src/slack/outbound-watch.ts
|
|
43383
|
-
var
|
|
43384
|
-
var
|
|
43884
|
+
var import_node_fs74 = require("fs");
|
|
43885
|
+
var import_node_path73 = require("path");
|
|
43385
43886
|
init_paths();
|
|
43386
43887
|
init_private_file();
|
|
43387
43888
|
init_secure_file();
|
|
@@ -43394,7 +43895,7 @@ var POLL_INTERVAL_MS = 12e3;
|
|
|
43394
43895
|
var lastPollMs = 0;
|
|
43395
43896
|
var nameCache = /* @__PURE__ */ new Map();
|
|
43396
43897
|
function storePath4() {
|
|
43397
|
-
return (0,
|
|
43898
|
+
return (0, import_node_path73.join)(appDataDir(), "slack-outbound-watch.json");
|
|
43398
43899
|
}
|
|
43399
43900
|
function watchId(teamId, channelId, ts) {
|
|
43400
43901
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -43407,9 +43908,9 @@ function tsNewer(a, b) {
|
|
|
43407
43908
|
}
|
|
43408
43909
|
function readStore4() {
|
|
43409
43910
|
const path2 = storePath4();
|
|
43410
|
-
if (!(0,
|
|
43911
|
+
if (!(0, import_node_fs74.existsSync)(path2)) return [];
|
|
43411
43912
|
try {
|
|
43412
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
43913
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs74.readFileSync)(path2, "utf8"));
|
|
43413
43914
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
43414
43915
|
} catch {
|
|
43415
43916
|
return [];
|