@sideboard-ai/core 0.1.19 → 0.1.23

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.
@@ -11,7 +11,7 @@ import {
11
11
  listBrightsyChatTargets,
12
12
  opencodeAdapter,
13
13
  permissionMode
14
- } from "./chunk-JQJZTL2Q.js";
14
+ } from "./chunk-WK6AK7NK.js";
15
15
  import "./chunk-ILQK4P5R.js";
16
16
  import {
17
17
  cursorSdkMessageToEvents,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveGithubRepoSlug
3
- } from "./chunk-LXHSRNJJ.js";
3
+ } from "./chunk-UFWEANLU.js";
4
4
  import {
5
5
  globalAgentCwd,
6
6
  sideboardReposDir
@@ -31,7 +31,7 @@ function coordinatorGreenfieldPlaybook(reposDir) {
31
31
  "- Examples:",
32
32
  ` - Clone: \`git clone <url> ${reposDir}/<name>\``,
33
33
  ` - New GitHub repo: \`gh repo create <owner>/<name> --private --clone -- ${reposDir}/<name>\` (or mkdir + git init + gh repo create + remote add + push)`,
34
- "- Then: add_workspace with that absolute path \u2192 create_thread (repoPath + parentThreadId) \u2192 send_to_thread (build) \u2192 wait_for_turn \u2192 send_to_thread (`gh pr create --draft -R <origin-owner/name>`) or create_draft_pr.",
34
+ "- Then: add_workspace with that absolute path \u2192 create_thread (repoPath + parentThreadId) \u2192 send_to_thread (build) \u2192 wait_for_turn \u2192 send_to_thread (`gh pr create --draft -R <origin-owner/name>`).",
35
35
  "- Always target the child worktree's **origin** (`github:` slug from list_workspaces / `git remote get-url origin` in that worktree). Never open PRs against `upstream`.",
36
36
  "- Do coding work in the child worktree thread, not by editing files in this home cwd."
37
37
  ].join("\n");
@@ -56,10 +56,8 @@ var COORDINATOR_TOOL_PLAYBOOK = [
56
56
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
57
57
  "Inspect / PRs:",
58
58
  "- get_diff \u2014 compact diff summary",
59
- "- preview_land \u2014 preview push+PR (does not push)",
60
- "- Prefer asking the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (use the workspace `github:` slug / that worktree's origin \u2014 never upstream) so it owns title/body from the diff.",
61
- "- create_draft_pr \u2014 fallback: commit (if dirty), push to origin, open/update a DRAFT PR from the orchestrator (always against origin)",
62
- "Human-only (do not attempt): ready-for-review confirm_land, purge_thread.",
59
+ "- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
60
+ "Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
63
61
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
64
62
  "Bash / Read / etc: allowed for (1) inspecting target worktrees / registered repo paths from MCP, and (2) greenfield setup under ~/sideboard/repos (git clone, gh repo create, git init+remote). Never git init/clone *inside* this synthetic home cwd \u2014 emptiness here is expected, not a bug."
65
63
  ].join("\n");
@@ -98,8 +96,8 @@ function ensureGlobalCoordinatorCwd() {
98
96
  "",
99
97
  "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered) and `parentThreadId` for children.",
100
98
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn.",
101
- "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 draft PR.",
102
- "Prefer asking worktree agents to open draft PRs; use create_draft_pr as fallback."
99
+ "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
100
+ "Always ask worktree agents to open draft PRs (`send_to_thread` + `gh pr create --draft -R <origin>`); never open PRs from the orchestrator."
103
101
  ].join("\n");
104
102
  writeFileSync(join(dir, "CLAUDE.md"), `${body}
105
103
  `, "utf8");
@@ -124,8 +122,8 @@ function coordinatorSystemPrompt(opts) {
124
122
  COORDINATOR_TOOL_PLAYBOOK,
125
123
  coordinatorGreenfieldPlaybook(reposDir),
126
124
  "When creating threads, pass the correct repoPath for the target workspace and parentThreadId for children.",
127
- "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 send_to_thread (ask for `gh pr create --draft -R <origin-owner/name>` using the workspace github slug) \u2192 wait_for_turn. Use create_draft_pr only if the child cannot open the PR. Never target upstream.",
128
- "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR.",
125
+ "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 send_to_thread (ask for `gh pr create --draft -R <origin-owner/name>` using the workspace github slug) \u2192 wait_for_turn. Never target upstream. Never open PRs from the orchestrator.",
126
+ "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
129
127
  `Goal: ${opts.goal}`,
130
128
  `Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
131
129
  "Registered workspaces:",
@@ -3,7 +3,7 @@ import {
3
3
  ensureWorkspace,
4
4
  removeWorkspace,
5
5
  syncWorkspacesFromThreads
6
- } from "./chunk-LIUV5ONW.js";
6
+ } from "./chunk-PER4N6LS.js";
7
7
  import {
8
8
  GLOBAL_WORKSPACE_ID,
9
9
  createGlobalChat,
@@ -13,19 +13,19 @@ import {
13
13
  isGlobalThread,
14
14
  isOrchestratorThread,
15
15
  orchestratorSessionPoisonedByBuiltins
16
- } from "./chunk-5263JXQY.js";
16
+ } from "./chunk-Y2EWQ4TL.js";
17
17
  import {
18
18
  coordinatorSystemPrompt,
19
19
  coordinatorTurnReminder,
20
20
  enrichWorkspacesWithGithub,
21
21
  ensureGlobalCoordinatorCwd
22
- } from "./chunk-SNHWAARD.js";
22
+ } from "./chunk-BMB7WCGF.js";
23
23
  import {
24
24
  PLAN_MODE_INSTRUCTION,
25
25
  allAdapters,
26
26
  getAdapter,
27
27
  parseBrightsyCliLine
28
- } from "./chunk-JQJZTL2Q.js";
28
+ } from "./chunk-WK6AK7NK.js";
29
29
  import {
30
30
  childEnvWithAppSettings,
31
31
  getLinearApiKey,
@@ -64,7 +64,7 @@ import {
64
64
  takenSlugsFromThread,
65
65
  threadDisplayLabel,
66
66
  worktreeNameFromPath
67
- } from "./chunk-LXHSRNJJ.js";
67
+ } from "./chunk-UFWEANLU.js";
68
68
  import {
69
69
  appendMessage,
70
70
  createEmptyThread,
@@ -248,6 +248,18 @@ function toolDescription(name, input) {
248
248
  if (/connectedAgentRequest/i.test(name)) {
249
249
  return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
250
250
  }
251
+ if (/present_artifact$/i.test(name)) {
252
+ return str(input?.title) ? `Present ${str(input?.title)}` : "Present artifact";
253
+ }
254
+ if (/present_schema$/i.test(name)) {
255
+ return str(input?.title) ? `Schema ${str(input?.title)}` : "Present schema";
256
+ }
257
+ if (/present_files$/i.test(name)) {
258
+ return str(input?.title) ? `Files ${str(input?.title)}` : "Present files";
259
+ }
260
+ if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
261
+ return str(input?.title) ? `Artifact ${str(input?.title)}` : "Artifact";
262
+ }
251
263
  if (!input) return n;
252
264
  if (/bash|shell|terminal/i.test(name) && str(input.command)) {
253
265
  const cmd = str(input.command);
@@ -432,9 +444,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
432
444
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
433
445
  );
434
446
  }
435
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-IV6LIDTO.js");
447
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-LM4AA4RO.js");
436
448
  if (isGlobalThread2(thread)) {
437
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-QPTX6YCW.js");
449
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-QH35ES7Y.js");
438
450
  ensureGlobalCoordinatorCwd2();
439
451
  }
440
452
  const adapter = getAdapter(thread.agent);
@@ -606,6 +618,26 @@ function formatWorktreeDirective(thread, opts) {
606
618
  }
607
619
  return lines.join("\n");
608
620
  }
621
+ function formatArtifactDirective() {
622
+ return [
623
+ "Sideboard side column (desktop UI):",
624
+ "claude.ai\u2019s \u201CArtifact\u201D tool does NOT exist in Claude Code. That is expected.",
625
+ "Documents (HTML/SVG/markdown):",
626
+ "1) Emit a fenced code block tagged `html` (preferred), `svg`, or `markdown` with the FULL document \u2014 Sideboard opens a side column. Example:",
627
+ "```html",
628
+ "<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
629
+ "```",
630
+ "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content.",
631
+ "CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
632
+ "3) Call Sideboard MCP `present_schema` with title, mode (table|form), and either:",
633
+ " - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
634
+ " - datasource=inline + resource: { id, title, schema, schemaUi } and optional records/record.",
635
+ "Files / media browser (CMS file manager column):",
636
+ "4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
637
+ " Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
638
+ "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages."
639
+ ].join("\n");
640
+ }
609
641
  var FILES_BY_AGENT = {
610
642
  claude: [
611
643
  "CLAUDE.md",
@@ -1473,6 +1505,27 @@ function isImageRelativePath(relativePath) {
1473
1505
  const ext = base.includes(".") ? base.split(".").pop() || "" : "";
1474
1506
  return IMAGE_EXTENSIONS.has(ext);
1475
1507
  }
1508
+ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
1509
+ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
1510
+ assertSafeRelativePath(relativePath);
1511
+ const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
1512
+ const abs = join4(worktreePath, relativePath);
1513
+ const st = statSync2(abs);
1514
+ if (!st.isFile()) {
1515
+ throw new Error(`Not a file: ${relativePath}`);
1516
+ }
1517
+ if (st.size > maxBytes) {
1518
+ throw new Error(
1519
+ `File too large to upload (${st.size} bytes; max ${maxBytes})`
1520
+ );
1521
+ }
1522
+ const buf = readFileSync4(abs);
1523
+ return {
1524
+ path: relativePath,
1525
+ contentBase64: buf.toString("base64"),
1526
+ size: buf.length
1527
+ };
1528
+ }
1476
1529
  function readWorktreeFile(worktreePath, relativePath, opts) {
1477
1530
  assertSafeRelativePath(relativePath);
1478
1531
  const maxBytes = opts?.maxBytes ?? 2e5;
@@ -2273,7 +2326,7 @@ async function createThread(input, onSetupLine) {
2273
2326
  return readThread(thread.id) ?? thread;
2274
2327
  }
2275
2328
  async function listLinearIssues(agent, repoPath) {
2276
- const { getAdapter: getAdapter2 } = await import("./agents-2XMZO3CY.js");
2329
+ const { getAdapter: getAdapter2 } = await import("./agents-LJJRPW4Y.js");
2277
2330
  await requireAgent(agent, { requireLinear: true });
2278
2331
  const adapter = getAdapter2(agent);
2279
2332
  if (!adapter.listLinearIssues) {
@@ -2489,7 +2542,7 @@ async function adoptThread(input) {
2489
2542
  messages: input.messages ?? []
2490
2543
  });
2491
2544
  writeThread(thread);
2492
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-JBWIRU55.js");
2545
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-23GHLR7I.js");
2493
2546
  await ensureWorkspace2(repoPath);
2494
2547
  return thread;
2495
2548
  }
@@ -3189,9 +3242,18 @@ var Orchestrator = class {
3189
3242
  parentId: threadId,
3190
3243
  goal: thread.sourceRef || thread.title
3191
3244
  }) : null;
3245
+ const artifactReminder = thread.agent !== "brightsy" ? [
3246
+ "Sideboard side column (important):",
3247
+ "There is no claude.ai Artifact tool here \u2014 that is normal.",
3248
+ "HTML/SVG/markdown: ```html fence or MCP present_artifact.",
3249
+ "CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
3250
+ "Files column: MCP present_files (brightsy account storage or memory).",
3251
+ "Do not say artifacts/CMS UI are unavailable."
3252
+ ].join(" ") : null;
3192
3253
  const agentPrompt = [
3193
3254
  thread.planMode ? PLAN_MODE_INSTRUCTION : null,
3194
3255
  orchestrationReminder,
3256
+ artifactReminder,
3195
3257
  expandedPrompt
3196
3258
  ].filter(Boolean).join("\n\n");
3197
3259
  const instructionFiles = loadAgentInstructions(thread.worktreePath, thread.agent);
@@ -3216,6 +3278,7 @@ var Orchestrator = class {
3216
3278
  () => null
3217
3279
  )
3218
3280
  });
3281
+ const artifactDirective = isBrightsy ? null : formatArtifactDirective();
3219
3282
  const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
3220
3283
  const { autoRenameBranchEnabled } = await import("./app-settings-BDMLWCWI.js");
3221
3284
  const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled() ? formatRenameBranchDirective(fresh, {
@@ -3243,6 +3306,7 @@ var Orchestrator = class {
3243
3306
  const cachedPrefix = [
3244
3307
  coordinatorDirective,
3245
3308
  worktreeDirective,
3309
+ artifactDirective,
3246
3310
  renameBranchDirective,
3247
3311
  ...fresh.agent === "claude" && fresh.sessionId ? [] : [instructions, seed]
3248
3312
  ].filter(Boolean).join("\n\n---\n\n");
@@ -3663,6 +3727,13 @@ var Orchestrator = class {
3663
3727
  }
3664
3728
  return readWorktreeFile(thread.worktreePath, relativePath);
3665
3729
  }
3730
+ async readFileForUpload(threadRef, relativePath) {
3731
+ const thread = this.requireThread(threadRef);
3732
+ if (relativePath.includes("..") || relativePath.startsWith("/")) {
3733
+ throw new Error("Invalid path");
3734
+ }
3735
+ return readWorktreeFileForUpload(thread.worktreePath, relativePath);
3736
+ }
3666
3737
  async writeFile(threadRef, relativePath, content) {
3667
3738
  const thread = this.requireThread(threadRef);
3668
3739
  if (relativePath.includes("..") || relativePath.startsWith("/")) {
@@ -3859,7 +3930,7 @@ var Orchestrator = class {
3859
3930
  return setStatus(thread.id, "idle");
3860
3931
  }
3861
3932
  if (!existsSync10(thread.worktreePath)) {
3862
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-TYI2SANE.js");
3933
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-RYTBDHHP.js");
3863
3934
  const { execa: execa6 } = await import("execa");
3864
3935
  const slug = thread.worktreePath.split("/").pop();
3865
3936
  const dest = thread.worktreePath;
@@ -3936,7 +4007,7 @@ async function startOrchestration(opts) {
3936
4007
  sourceRef: "default",
3937
4008
  ...createOpts
3938
4009
  }).catch(async () => {
3939
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-TYI2SANE.js");
4010
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-RYTBDHHP.js");
3940
4011
  const repo = await resolveRepoRoot2(repoPath);
3941
4012
  const def = await resolveDefaultBranch2(repo);
3942
4013
  return createThread({
@@ -4038,6 +4109,82 @@ async function startMcpServer() {
4038
4109
  return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
4039
4110
  }
4040
4111
  );
4112
+ server.tool(
4113
+ "present_artifact",
4114
+ "Show an HTML, SVG, or markdown document in Sideboard\u2019s Claude-style side column (desktop). Use instead of claude.ai\u2019s artifact tool \u2014 pass the full document content. Prefer type=html for interactive pages.",
4115
+ {
4116
+ title: z.string().describe("Short title shown in the artifact pane header"),
4117
+ type: z.enum(["html", "svg", "markdown"]).describe("Artifact kind \u2014 html opens an iframe preview"),
4118
+ content: z.string().describe("Full document body (complete HTML page, SVG markup, or markdown)"),
4119
+ artifact_id: z.string().optional().describe("Stable id when updating the same artifact across turns")
4120
+ },
4121
+ async ({ title, type, content, artifact_id }) => {
4122
+ const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
4123
+ const payload = {
4124
+ ok: true,
4125
+ artifact_id: id,
4126
+ title,
4127
+ type,
4128
+ content,
4129
+ message: "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
4130
+ };
4131
+ return { content: [{ type: "text", text: JSON.stringify(payload) }] };
4132
+ }
4133
+ );
4134
+ server.tool(
4135
+ "present_schema",
4136
+ "Open Sideboard\u2019s schema-driven CMS side column (filterable table and/or form). Pass JSON Schema + schemaUi (Brightsy extensions supported). Use datasource=brightsy with resource_id (record type UUID) when logged into Brightsy; use datasource=inline with embedded resource/records for any other source.",
4137
+ {
4138
+ title: z.string().describe("Pane title"),
4139
+ mode: z.enum(["table", "form"]).optional().describe("table = list/filter records; form = edit one record"),
4140
+ datasource: z.enum(["brightsy", "inline"]).optional().describe("brightsy resolves via login; inline uses embedded resource/records"),
4141
+ resource_id: z.string().optional().describe("Brightsy record type UUID (or generic resource id)"),
4142
+ record_id: z.string().optional().describe("Record id when opening form mode"),
4143
+ resource: z.record(z.unknown()).optional().describe("Inline { id, title, schema, schemaUi?, slug? }"),
4144
+ record: z.record(z.unknown()).optional().describe("Inline record { id, data, published_at? }"),
4145
+ records: z.array(z.record(z.unknown())).optional().describe("Inline records for table mode"),
4146
+ pane_id: z.string().optional().describe("Stable pane id across updates")
4147
+ },
4148
+ async (args) => {
4149
+ const id = args.pane_id?.trim() || `schema_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
4150
+ const payload = {
4151
+ ok: true,
4152
+ pane_id: id,
4153
+ title: args.title,
4154
+ mode: args.mode ?? (args.record_id || args.record ? "form" : "table"),
4155
+ datasource: args.datasource ?? (args.resource ? "inline" : "brightsy"),
4156
+ resource_id: args.resource_id,
4157
+ record_id: args.record_id,
4158
+ resource: args.resource,
4159
+ record: args.record,
4160
+ records: args.records,
4161
+ message: "Schema pane accepted. Sideboard desktop opens the CMS column beside chat."
4162
+ };
4163
+ return { content: [{ type: "text", text: JSON.stringify(payload) }] };
4164
+ }
4165
+ );
4166
+ server.tool(
4167
+ "present_files",
4168
+ "Open Sideboard\u2019s Files column (CMS-style file manager: browse, upload, pick). Use datasource=brightsy when the user is logged into Brightsy account storage; datasource=memory for a session-local demo store. Prefer this over claiming a file manager UI is unavailable. Pair with present_schema when editing records that need media.",
4169
+ {
4170
+ title: z.string().optional().describe("Pane title (default: Files)"),
4171
+ datasource: z.enum(["brightsy", "memory"]).optional().describe("brightsy = account storage via login; memory = session demo store"),
4172
+ path: z.string().optional().describe("Initial folder path (e.g. public)"),
4173
+ pane_id: z.string().optional().describe("Stable pane id across updates")
4174
+ },
4175
+ async (args) => {
4176
+ const id = args.pane_id?.trim() || `files_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
4177
+ const payload = {
4178
+ ok: true,
4179
+ pane_id: id,
4180
+ title: args.title?.trim() || "Files",
4181
+ datasource: args.datasource ?? "brightsy",
4182
+ path: args.path,
4183
+ message: "Files pane accepted. Sideboard desktop opens the Files column beside chat."
4184
+ };
4185
+ return { content: [{ type: "text", text: JSON.stringify(payload) }] };
4186
+ }
4187
+ );
4041
4188
  server.tool(
4042
4189
  "create_thread",
4043
4190
  "Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces and parentThreadId when spawning from an orchestrator. Then use send_to_thread to chat.",
@@ -4379,45 +4526,6 @@ async function startMcpServer() {
4379
4526
  };
4380
4527
  }
4381
4528
  );
4382
- server.tool(
4383
- "preview_land",
4384
- "Preview push+PR land (does NOT push). Use before create_draft_pr.",
4385
- { ref: z.string() },
4386
- async ({ ref }) => {
4387
- const preview = await orch.previewLand(ref);
4388
- return { content: [{ type: "text", text: JSON.stringify(preview, null, 2) }] };
4389
- }
4390
- );
4391
- server.tool(
4392
- "create_draft_pr",
4393
- "Commit dirty changes if needed, push the thread branch to origin, and create/update a DRAFT GitHub PR against that worktree's origin (never upstream). Ready-for-review / non-draft land stays human-only (CLI/app confirm_land). Prefer this when the orchestrator should open a PR itself; alternatively send_to_thread asking the worktree agent to run `gh pr create --draft -R <origin-owner/name>`.",
4394
- { ref: z.string() },
4395
- async ({ ref }) => {
4396
- try {
4397
- const result = await orch.confirmLand(ref, { draft: true });
4398
- return {
4399
- content: [
4400
- {
4401
- type: "text",
4402
- text: JSON.stringify(
4403
- {
4404
- prUrl: result.prUrl,
4405
- pushed: result.pushed,
4406
- committed: result.committed,
4407
- draft: true
4408
- },
4409
- null,
4410
- 2
4411
- )
4412
- }
4413
- ]
4414
- };
4415
- } catch (err) {
4416
- const message = err instanceof Error ? err.message : String(err);
4417
- return { content: [{ type: "text", text: message }], isError: true };
4418
- }
4419
- }
4420
- );
4421
4529
  server.tool(
4422
4530
  "list_branches",
4423
4531
  "List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
@@ -4504,6 +4612,7 @@ export {
4504
4612
  spawnAgentTurn,
4505
4613
  formatRenameBranchDirective,
4506
4614
  formatWorktreeDirective,
4615
+ formatArtifactDirective,
4507
4616
  loadAgentInstructions,
4508
4617
  formatAgentInstructions,
4509
4618
  withAgentInstructions,
@@ -4531,6 +4640,7 @@ export {
4531
4640
  listBranchCommits,
4532
4641
  getDiff,
4533
4642
  listWorktreeFiles,
4643
+ readWorktreeFileForUpload,
4534
4644
  readWorktreeFile,
4535
4645
  writeWorktreeFile,
4536
4646
  getDiffSummary,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-5263JXQY.js";
3
+ } from "./chunk-Y2EWQ4TL.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
7
- } from "./chunk-LXHSRNJJ.js";
7
+ } from "./chunk-UFWEANLU.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-M37RITA6.js";