meshy-node 0.1.9 → 0.2.1

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/main.cjs CHANGED
@@ -32727,7 +32727,7 @@ function parseTask(value) {
32727
32727
  }
32728
32728
  const status = asTaskStatus(value.status);
32729
32729
  const priority = asTaskPriority(value.priority);
32730
- if (typeof value.id !== "string" || typeof value.title !== "string" || typeof value.description !== "string" || typeof value.agent !== "string" || value.project !== null && typeof value.project !== "string" || value.effectiveProjectPath !== null && value.effectiveProjectPath !== void 0 && typeof value.effectiveProjectPath !== "string" || !isPlainObject(value.payload) || status === null || priority === null || value.assignedTo !== null && typeof value.assignedTo !== "string" || value.assignedNodeName !== void 0 && value.assignedNodeName !== null && typeof value.assignedNodeName !== "string" || typeof value.createdBy !== "string" || value.result !== null && !isPlainObject(value.result) || value.error !== null && typeof value.error !== "string" || typeof value.retryCount !== "number" || !Number.isFinite(value.retryCount) || typeof value.maxRetries !== "number" || !Number.isFinite(value.maxRetries) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt)) {
32730
+ if (typeof value.id !== "string" || typeof value.title !== "string" || typeof value.description !== "string" || typeof value.agent !== "string" || value.project !== null && typeof value.project !== "string" || value.effectiveProjectPath !== null && value.effectiveProjectPath !== void 0 && typeof value.effectiveProjectPath !== "string" || value.branch !== null && value.branch !== void 0 && typeof value.branch !== "string" || !isPlainObject(value.payload) || status === null || priority === null || value.assignedTo !== null && typeof value.assignedTo !== "string" || value.assignedNodeName !== void 0 && value.assignedNodeName !== null && typeof value.assignedNodeName !== "string" || typeof value.createdBy !== "string" || value.result !== null && !isPlainObject(value.result) || value.error !== null && typeof value.error !== "string" || typeof value.retryCount !== "number" || !Number.isFinite(value.retryCount) || typeof value.maxRetries !== "number" || !Number.isFinite(value.maxRetries) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt) || typeof value.updatedAt !== "number" || !Number.isFinite(value.updatedAt)) {
32731
32731
  return null;
32732
32732
  }
32733
32733
  return {
@@ -32737,6 +32737,7 @@ function parseTask(value) {
32737
32737
  agent: value.agent,
32738
32738
  project: value.project ?? null,
32739
32739
  effectiveProjectPath: typeof value.effectiveProjectPath === "string" ? value.effectiveProjectPath : null,
32740
+ branch: value.branch === void 0 ? void 0 : typeof value.branch === "string" ? value.branch : null,
32740
32741
  payload: clone(value.payload),
32741
32742
  status,
32742
32743
  priority,
@@ -33350,6 +33351,7 @@ var TaskEngine = class {
33350
33351
  agent: input.agent,
33351
33352
  project: input.project ?? null,
33352
33353
  effectiveProjectPath: null,
33354
+ branch: input.branch ?? null,
33353
33355
  payload: input.payload,
33354
33356
  status: "pending",
33355
33357
  priority: input.priority ?? "normal",
@@ -33593,10 +33595,12 @@ var TaskEngine = class {
33593
33595
  const now = Date.now();
33594
33596
  const existing = this.store.getTask(task.id);
33595
33597
  const effectiveProjectPath = task.effectiveProjectPath ?? existing?.effectiveProjectPath ?? null;
33598
+ const branch = task.branch ?? existing?.branch ?? null;
33596
33599
  if (!existing) {
33597
33600
  this.store.createTask({
33598
33601
  ...task,
33599
33602
  effectiveProjectPath,
33603
+ branch,
33600
33604
  status: "running",
33601
33605
  updatedAt: now
33602
33606
  });
@@ -33604,6 +33608,7 @@ var TaskEngine = class {
33604
33608
  this.store.updateTask(task.id, {
33605
33609
  status: "running",
33606
33610
  effectiveProjectPath,
33611
+ branch,
33607
33612
  updatedAt: now
33608
33613
  });
33609
33614
  }
@@ -34951,6 +34956,7 @@ function buildLeaderTaskPatch(data) {
34951
34956
  if (data.result !== void 0) body.result = data.result;
34952
34957
  if (data.error !== void 0) body.error = data.error;
34953
34958
  if (data.effectiveProjectPath !== void 0) body.effectiveProjectPath = data.effectiveProjectPath;
34959
+ if (data.branch !== void 0) body.branch = data.branch;
34954
34960
  if (data.status === "pending") body.assignedTo = null;
34955
34961
  return body;
34956
34962
  }
@@ -34992,9 +34998,10 @@ function forwardLeaderTaskPatch(log2, nodeRegistry, taskId, data, options) {
34992
34998
  });
34993
34999
  });
34994
35000
  }
34995
- function forwardRunningStatusToLeader(log2, nodeRegistry, taskId, effectiveProjectPath) {
35001
+ function forwardRunningStatusToLeader(log2, nodeRegistry, taskId, effectiveProjectPath, branch) {
34996
35002
  const data = { status: "running" };
34997
35003
  if (effectiveProjectPath !== void 0) data.effectiveProjectPath = effectiveProjectPath;
35004
+ if (branch !== void 0) data.branch = branch;
34998
35005
  forwardLeaderTaskPatch(log2, nodeRegistry, taskId, data, {
34999
35006
  successMessage: "forwarded running status to leader",
35000
35007
  rejectedMessage: "leader rejected running status update",
@@ -35457,6 +35464,31 @@ function buildAssistantEvent(text, timestamp = (/* @__PURE__ */ new Date()).toIS
35457
35464
  timestamp
35458
35465
  };
35459
35466
  }
35467
+ function buildAssistantThinkingEvent(thinking, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
35468
+ return {
35469
+ type: "assistant",
35470
+ message: {
35471
+ role: "assistant",
35472
+ content: [{ type: "thinking", thinking }]
35473
+ },
35474
+ timestamp
35475
+ };
35476
+ }
35477
+ function extractCodexReasoningText(item) {
35478
+ if (typeof item.text === "string") {
35479
+ return item.text.trim();
35480
+ }
35481
+ if (Array.isArray(item.summary)) {
35482
+ return item.summary.map((entry) => {
35483
+ if (typeof entry === "string") return entry.trim();
35484
+ if (typeof entry === "object" && entry !== null && typeof entry.text === "string") {
35485
+ return String(entry.text).trim();
35486
+ }
35487
+ return "";
35488
+ }).filter(Boolean).join("\n\n");
35489
+ }
35490
+ return "";
35491
+ }
35460
35492
  function sanitizeFilename(filename) {
35461
35493
  return filename.replace(/[^a-zA-Z0-9._-]/g, "-");
35462
35494
  }
@@ -35671,6 +35703,12 @@ var CodexEngine = class extends ExecutionEngine {
35671
35703
  if (item?.type === "agent_message" && typeof item.text === "string" && item.text.trim()) {
35672
35704
  return buildAssistantEvent(item.text);
35673
35705
  }
35706
+ if (item?.type === "reasoning" || item?.type === "agent_reasoning") {
35707
+ const reasoning = extractCodexReasoningText(item);
35708
+ if (reasoning) {
35709
+ return buildAssistantThinkingEvent(reasoning);
35710
+ }
35711
+ }
35674
35712
  }
35675
35713
  return null;
35676
35714
  }
@@ -40752,6 +40790,12 @@ var NodeWorkDirEntrySchema = external_exports.object({
40752
40790
  mimeType: external_exports.string().optional(),
40753
40791
  kind: external_exports.enum(["text", "json", "markdown", "image", "html", "pdf", "binary"]).optional()
40754
40792
  });
40793
+ var GitRemoteBranchOptionSchema = external_exports.object({
40794
+ name: external_exports.string(),
40795
+ remote: external_exports.enum(["origin", "upstream"]),
40796
+ branch: external_exports.string(),
40797
+ ref: external_exports.string()
40798
+ });
40755
40799
  var NodeListQuery = external_exports.object({
40756
40800
  status: external_exports.enum(["online", "busy", "offline"]).optional(),
40757
40801
  capability: external_exports.string().optional()
@@ -40775,6 +40819,12 @@ var NodeWorkDirTreeQuery = external_exports.object({
40775
40819
  directoriesOnly: QueryBoolean,
40776
40820
  allowAbsolute: QueryBoolean
40777
40821
  });
40822
+ var NodeWorkDirBranchQuery = external_exports.object({
40823
+ path: external_exports.string().default("."),
40824
+ limit: external_exports.coerce.number().int().min(1).max(20).default(20),
40825
+ offset: external_exports.coerce.number().int().min(0).default(0),
40826
+ allowAbsolute: QueryBoolean
40827
+ });
40778
40828
  var NodeWorkDirTreeResponse = external_exports.object({
40779
40829
  nodeId: external_exports.string(),
40780
40830
  rootPath: external_exports.string(),
@@ -40788,6 +40838,29 @@ var NodeWorkDirTreeResponse = external_exports.object({
40788
40838
  isAbsolute: external_exports.boolean(),
40789
40839
  parentPath: external_exports.string().nullable()
40790
40840
  });
40841
+ var NodeWorkDirBranchResponse = external_exports.object({
40842
+ nodeId: external_exports.string(),
40843
+ path: external_exports.string(),
40844
+ available: external_exports.boolean(),
40845
+ repoRoot: external_exports.string().nullable(),
40846
+ currentBranch: external_exports.string().nullable(),
40847
+ branches: external_exports.array(GitRemoteBranchOptionSchema),
40848
+ limit: external_exports.number().int().min(1),
40849
+ offset: external_exports.number().int().min(0),
40850
+ total: external_exports.number().int().min(0),
40851
+ hasMore: external_exports.boolean()
40852
+ });
40853
+ var CreateNodeWorkDirBranchBody = external_exports.object({
40854
+ path: external_exports.string().default("."),
40855
+ branchName: external_exports.string().trim().min(1),
40856
+ startPoint: external_exports.string().trim().min(1),
40857
+ limit: external_exports.coerce.number().int().min(1).max(20).default(20),
40858
+ offset: external_exports.coerce.number().int().min(0).default(0),
40859
+ allowAbsolute: external_exports.boolean().default(true)
40860
+ });
40861
+ var CreateNodeWorkDirBranchResponse = NodeWorkDirBranchResponse.extend({
40862
+ createdBranch: external_exports.string()
40863
+ });
40791
40864
  var UpdateNodeBody = external_exports.object({
40792
40865
  name: external_exports.string().min(1).optional(),
40793
40866
  capabilities: external_exports.array(external_exports.string()).optional()
@@ -40811,6 +40884,7 @@ var CreateTaskBody = external_exports.object({
40811
40884
  description: external_exports.string().default(""),
40812
40885
  agent: external_exports.enum(AGENT_OPTIONS),
40813
40886
  project: external_exports.string().nullable().optional().default(null),
40887
+ branch: external_exports.string().nullable().optional().default(null),
40814
40888
  payload: TaskPayload.default({}),
40815
40889
  priority: external_exports.enum(["low", "normal", "high", "critical"]).default("normal"),
40816
40890
  assignTo: external_exports.string().optional()
@@ -40830,6 +40904,7 @@ var TaskListResponse = external_exports.object({
40830
40904
  agent: external_exports.string(),
40831
40905
  project: external_exports.string().nullable(),
40832
40906
  effectiveProjectPath: external_exports.string().nullable(),
40907
+ branch: external_exports.string().nullable().optional(),
40833
40908
  payload: external_exports.record(external_exports.unknown()),
40834
40909
  status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]),
40835
40910
  priority: external_exports.enum(["low", "normal", "high", "critical"]),
@@ -40852,7 +40927,8 @@ var UpdateTaskBody = external_exports.object({
40852
40927
  status: external_exports.enum(["pending", "assigned", "running", "completed", "failed", "cancelled", "archived"]).optional(),
40853
40928
  result: external_exports.record(external_exports.unknown()).nullable().optional(),
40854
40929
  error: external_exports.string().nullable().optional(),
40855
- effectiveProjectPath: external_exports.string().nullable().optional()
40930
+ effectiveProjectPath: external_exports.string().nullable().optional(),
40931
+ branch: external_exports.string().nullable().optional()
40856
40932
  });
40857
40933
  var AssignTaskBody = external_exports.object({
40858
40934
  nodeId: external_exports.string().min(1)
@@ -41605,7 +41681,7 @@ function readFileContent(root, relativePath) {
41605
41681
  };
41606
41682
  }
41607
41683
 
41608
- // ../../packages/api/src/output/git-diff.ts
41684
+ // ../../packages/api/src/output/git-branches.ts
41609
41685
  var import_node_child_process4 = require("child_process");
41610
41686
  function git(args, cwd) {
41611
41687
  try {
@@ -41618,19 +41694,192 @@ function git(args, cwd) {
41618
41694
  return "";
41619
41695
  }
41620
41696
  }
41697
+ function gitSucceeds(args, cwd) {
41698
+ try {
41699
+ (0, import_node_child_process4.execFileSync)("git", ["-C", cwd, ...args], {
41700
+ encoding: "utf-8",
41701
+ timeout: 1e4,
41702
+ stdio: ["pipe", "pipe", "pipe"]
41703
+ });
41704
+ return true;
41705
+ } catch {
41706
+ return false;
41707
+ }
41708
+ }
41709
+ function runGit(args, cwd) {
41710
+ return (0, import_node_child_process4.execFileSync)("git", ["-C", cwd, ...args], {
41711
+ encoding: "utf-8",
41712
+ timeout: 1e4,
41713
+ stdio: ["pipe", "pipe", "pipe"]
41714
+ }).trim();
41715
+ }
41621
41716
  function isGitRepo(dirPath) {
41622
- const result = git(["rev-parse", "--is-inside-work-tree"], dirPath);
41717
+ return git(["rev-parse", "--is-inside-work-tree"], dirPath) === "true";
41718
+ }
41719
+ function normalizeCurrentBranch(branch) {
41720
+ if (!branch || branch === "HEAD") {
41721
+ return null;
41722
+ }
41723
+ return branch;
41724
+ }
41725
+ function parseRemoteBranch(ref) {
41726
+ const normalized = ref.trim();
41727
+ if (!normalized || normalized.includes(" -> ")) {
41728
+ return null;
41729
+ }
41730
+ const [remote, ...branchParts] = normalized.split("/");
41731
+ if (remote !== "origin" && remote !== "upstream" || branchParts.length === 0) {
41732
+ return null;
41733
+ }
41734
+ return {
41735
+ name: normalized,
41736
+ remote,
41737
+ branch: branchParts.join("/"),
41738
+ ref: normalized
41739
+ };
41740
+ }
41741
+ function branchPriority(branch) {
41742
+ const name2 = branch.branch.toLowerCase();
41743
+ const mainScore = name2 === "main" ? 0 : name2 === "master" ? 1 : 2;
41744
+ const remoteScore = branch.remote === "upstream" ? 0 : 1;
41745
+ return [mainScore, remoteScore, branch.branch];
41746
+ }
41747
+ function compareRemoteBranches(left, right) {
41748
+ const [leftMain, leftRemote, leftName] = branchPriority(left);
41749
+ const [rightMain, rightRemote, rightName] = branchPriority(right);
41750
+ if (leftMain !== rightMain) {
41751
+ return leftMain - rightMain;
41752
+ }
41753
+ if (leftRemote !== rightRemote) {
41754
+ return leftRemote - rightRemote;
41755
+ }
41756
+ const branchCompare = leftName.localeCompare(rightName);
41757
+ if (branchCompare !== 0) {
41758
+ return branchCompare;
41759
+ }
41760
+ return left.remote.localeCompare(right.remote);
41761
+ }
41762
+ function listRemoteBranches(repoRoot2) {
41763
+ const output = git([
41764
+ "for-each-ref",
41765
+ "--format=%(refname:short)",
41766
+ "refs/remotes/origin",
41767
+ "refs/remotes/upstream"
41768
+ ], repoRoot2);
41769
+ if (!output) {
41770
+ return [];
41771
+ }
41772
+ return output.split("\n").map(parseRemoteBranch).filter((value) => value !== null).sort(compareRemoteBranches);
41773
+ }
41774
+ function getRemoteStartPoint(repoRoot2, value) {
41775
+ const trimmed = value.trim();
41776
+ if (!trimmed) {
41777
+ throw new Error("A base branch is required");
41778
+ }
41779
+ const directRemote = parseRemoteBranch(trimmed);
41780
+ if (directRemote) {
41781
+ if (!gitSucceeds(["show-ref", "--verify", "--quiet", `refs/remotes/${directRemote.ref}`], repoRoot2)) {
41782
+ throw new Error(`Remote branch ${directRemote.ref} not found`);
41783
+ }
41784
+ return { ref: directRemote.ref, track: true };
41785
+ }
41786
+ for (const remote of ["upstream", "origin"]) {
41787
+ const remoteRef = `${remote}/${trimmed}`;
41788
+ if (gitSucceeds(["show-ref", "--verify", "--quiet", `refs/remotes/${remoteRef}`], repoRoot2)) {
41789
+ return { ref: remoteRef, track: true };
41790
+ }
41791
+ }
41792
+ if (gitSucceeds(["show-ref", "--verify", "--quiet", `refs/heads/${trimmed}`], repoRoot2)) {
41793
+ return { ref: trimmed, track: false };
41794
+ }
41795
+ throw new Error(`Branch ${trimmed} not found on upstream/origin or locally`);
41796
+ }
41797
+ function getGitBranchInfo(dirPath, options) {
41798
+ const limit = Math.max(1, Math.min(20, Math.trunc(options.limit)));
41799
+ const offset = Math.max(0, Math.trunc(options.offset));
41800
+ if (!isGitRepo(dirPath)) {
41801
+ return {
41802
+ available: false,
41803
+ repoRoot: null,
41804
+ currentBranch: null,
41805
+ branches: [],
41806
+ limit,
41807
+ offset,
41808
+ total: 0,
41809
+ hasMore: false
41810
+ };
41811
+ }
41812
+ const repoRoot2 = git(["rev-parse", "--show-toplevel"], dirPath);
41813
+ const currentBranch = normalizeCurrentBranch(git(["rev-parse", "--abbrev-ref", "HEAD"], dirPath));
41814
+ const remoteBranches = listRemoteBranches(repoRoot2);
41815
+ const branches = remoteBranches.slice(offset, offset + limit);
41816
+ return {
41817
+ available: true,
41818
+ repoRoot: repoRoot2,
41819
+ currentBranch,
41820
+ branches,
41821
+ limit,
41822
+ offset,
41823
+ total: remoteBranches.length,
41824
+ hasMore: offset + branches.length < remoteBranches.length
41825
+ };
41826
+ }
41827
+ function createGitBranch(dirPath, branchName, startPoint, options) {
41828
+ if (!isGitRepo(dirPath)) {
41829
+ throw new Error("Selected working directory is not inside a git repository");
41830
+ }
41831
+ const repoRoot2 = git(["rev-parse", "--show-toplevel"], dirPath);
41832
+ const name2 = branchName.trim();
41833
+ if (!name2) {
41834
+ throw new Error("A new branch name is required");
41835
+ }
41836
+ try {
41837
+ runGit(["check-ref-format", "--branch", name2], repoRoot2);
41838
+ } catch {
41839
+ throw new Error(`Invalid branch name: ${name2}`);
41840
+ }
41841
+ if (gitSucceeds(["show-ref", "--verify", "--quiet", `refs/heads/${name2}`], repoRoot2)) {
41842
+ throw new Error(`Local branch ${name2} already exists`);
41843
+ }
41844
+ const target = getRemoteStartPoint(repoRoot2, startPoint);
41845
+ if (target.track) {
41846
+ runGit(["switch", "-c", name2, "--track", target.ref], repoRoot2);
41847
+ } else {
41848
+ runGit(["switch", "-c", name2, target.ref], repoRoot2);
41849
+ }
41850
+ return {
41851
+ createdBranch: name2,
41852
+ ...getGitBranchInfo(dirPath, options),
41853
+ currentBranch: name2
41854
+ };
41855
+ }
41856
+
41857
+ // ../../packages/api/src/output/git-diff.ts
41858
+ var import_node_child_process5 = require("child_process");
41859
+ function git2(args, cwd) {
41860
+ try {
41861
+ return (0, import_node_child_process5.execFileSync)("git", ["-C", cwd, ...args], {
41862
+ encoding: "utf-8",
41863
+ timeout: 1e4,
41864
+ stdio: ["pipe", "pipe", "pipe"]
41865
+ }).trim();
41866
+ } catch {
41867
+ return "";
41868
+ }
41869
+ }
41870
+ function isGitRepo2(dirPath) {
41871
+ const result = git2(["rev-parse", "--is-inside-work-tree"], dirPath);
41623
41872
  return result === "true";
41624
41873
  }
41625
41874
  function getGitDiff(dirPath) {
41626
- if (!isGitRepo(dirPath)) {
41875
+ if (!isGitRepo2(dirPath)) {
41627
41876
  return { available: false };
41628
41877
  }
41629
- const repoRoot2 = git(["rev-parse", "--show-toplevel"], dirPath);
41630
- const branch = git(["rev-parse", "--abbrev-ref", "HEAD"], dirPath) || null;
41631
- const staged = git(["diff", "--cached"], dirPath);
41632
- const unstaged = git(["diff"], dirPath);
41633
- const statusOutput = git(["status", "--porcelain"], dirPath);
41878
+ const repoRoot2 = git2(["rev-parse", "--show-toplevel"], dirPath);
41879
+ const branch = git2(["rev-parse", "--abbrev-ref", "HEAD"], dirPath) || null;
41880
+ const staged = git2(["diff", "--cached"], dirPath);
41881
+ const unstaged = git2(["diff"], dirPath);
41882
+ const statusOutput = git2(["status", "--porcelain"], dirPath);
41634
41883
  const changedFiles = [];
41635
41884
  const untrackedFiles = [];
41636
41885
  for (const line of statusOutput.split("\n")) {
@@ -41658,20 +41907,33 @@ function getGitDiff(dirPath) {
41658
41907
  function isAbsolutePath(p) {
41659
41908
  return path12.isAbsolute(p) || /^[A-Za-z]:[\\/]/.test(p);
41660
41909
  }
41661
- function getLocalNodeWorkDirTree(nodeId, rootPath, currentPath, options) {
41910
+ function resolveNodeWorkDirTarget(nodeId, rootPath, currentPath, allowAbsolute) {
41662
41911
  if (!rootPath) {
41663
41912
  throw new MeshyError("VALIDATION_ERROR", `Node ${nodeId} does not expose a working directory`, 400);
41664
41913
  }
41665
- const useAbsolute = options.allowAbsolute && isAbsolutePath(currentPath);
41914
+ const useAbsolute = allowAbsolute && isAbsolutePath(currentPath);
41666
41915
  const resolvedPath = useAbsolute ? path12.resolve(currentPath) : currentPath;
41916
+ return {
41917
+ rootPath,
41918
+ resolvedPath,
41919
+ useAbsolute
41920
+ };
41921
+ }
41922
+ function getLocalNodeWorkDirTree(nodeId, rootPath, currentPath, options) {
41923
+ const { rootPath: resolvedRootPath, resolvedPath, useAbsolute } = resolveNodeWorkDirTarget(
41924
+ nodeId,
41925
+ rootPath,
41926
+ currentPath,
41927
+ options.allowAbsolute
41928
+ );
41667
41929
  try {
41668
- const entries = useAbsolute ? listAbsoluteDirectory(resolvedPath) : listDirectory(rootPath, resolvedPath);
41930
+ const entries = useAbsolute ? listAbsoluteDirectory(resolvedPath) : listDirectory(resolvedRootPath, resolvedPath);
41669
41931
  const visibleEntries = options.directoriesOnly ? entries.filter((entry) => entry.type === "directory") : entries;
41670
41932
  const pagedEntries = visibleEntries.slice(options.offset, options.offset + options.limit);
41671
- const parentPath = computeParentPath(rootPath, resolvedPath, useAbsolute);
41933
+ const parentPath = computeParentPath(resolvedRootPath, resolvedPath, useAbsolute);
41672
41934
  return {
41673
41935
  nodeId,
41674
- rootPath,
41936
+ rootPath: resolvedRootPath,
41675
41937
  currentPath: resolvedPath,
41676
41938
  entries: pagedEntries,
41677
41939
  limit: options.limit,
@@ -41689,6 +41951,50 @@ function getLocalNodeWorkDirTree(nodeId, rootPath, currentPath, options) {
41689
41951
  throw err;
41690
41952
  }
41691
41953
  }
41954
+ function getLocalNodeWorkDirBranchInfo(nodeId, rootPath, currentPath, options) {
41955
+ const { resolvedPath } = resolveNodeWorkDirTarget(
41956
+ nodeId,
41957
+ rootPath,
41958
+ currentPath,
41959
+ options.allowAbsolute
41960
+ );
41961
+ const branchInfo = getGitBranchInfo(resolvedPath, {
41962
+ limit: options.limit,
41963
+ offset: options.offset
41964
+ });
41965
+ return {
41966
+ nodeId,
41967
+ path: resolvedPath,
41968
+ ...branchInfo
41969
+ };
41970
+ }
41971
+ function createLocalNodeWorkDirBranch(nodeId, rootPath, currentPath, options) {
41972
+ const { resolvedPath } = resolveNodeWorkDirTarget(
41973
+ nodeId,
41974
+ rootPath,
41975
+ currentPath,
41976
+ options.allowAbsolute
41977
+ );
41978
+ try {
41979
+ const result = createGitBranch(
41980
+ resolvedPath,
41981
+ options.branchName,
41982
+ options.startPoint,
41983
+ { limit: options.limit, offset: options.offset }
41984
+ );
41985
+ return {
41986
+ nodeId,
41987
+ path: resolvedPath,
41988
+ ...result
41989
+ };
41990
+ } catch (err) {
41991
+ throw new MeshyError(
41992
+ "VALIDATION_ERROR",
41993
+ err instanceof Error ? err.message : String(err),
41994
+ 400
41995
+ );
41996
+ }
41997
+ }
41692
41998
  function computeParentPath(rootPath, currentPath, useAbsolute) {
41693
41999
  if (useAbsolute) {
41694
42000
  const parent = path12.dirname(currentPath);
@@ -41724,6 +42030,44 @@ function sendLocalNodeWorkDirTree(req, res, nodeId, options = {}) {
41724
42030
  }
41725
42031
  ));
41726
42032
  }
42033
+ function sendLocalNodeWorkDirBranchInfo(req, res, nodeId, options = {}) {
42034
+ const query = NodeWorkDirBranchQuery.parse(req.query);
42035
+ const { nodeRegistry, workDir } = req.app.locals.deps;
42036
+ const self2 = nodeRegistry.getSelf();
42037
+ if (options.requireSelfNode && nodeId !== self2.id) {
42038
+ throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
42039
+ }
42040
+ res.json(getLocalNodeWorkDirBranchInfo(
42041
+ self2.id,
42042
+ self2.workDir ?? workDir,
42043
+ query.path,
42044
+ {
42045
+ limit: query.limit,
42046
+ offset: query.offset,
42047
+ allowAbsolute: query.allowAbsolute
42048
+ }
42049
+ ));
42050
+ }
42051
+ function sendLocalNodeWorkDirBranchCreate(req, res, nodeId, options = {}) {
42052
+ const body = CreateNodeWorkDirBranchBody.parse(req.body);
42053
+ const { nodeRegistry, workDir } = req.app.locals.deps;
42054
+ const self2 = nodeRegistry.getSelf();
42055
+ if (options.requireSelfNode && nodeId !== self2.id) {
42056
+ throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
42057
+ }
42058
+ res.json(createLocalNodeWorkDirBranch(
42059
+ self2.id,
42060
+ self2.workDir ?? workDir,
42061
+ body.path,
42062
+ {
42063
+ branchName: body.branchName,
42064
+ startPoint: body.startPoint,
42065
+ limit: body.limit,
42066
+ offset: body.offset,
42067
+ allowAbsolute: body.allowAbsolute
42068
+ }
42069
+ ));
42070
+ }
41727
42071
 
41728
42072
  // ../../packages/api/src/task-route-utils.ts
41729
42073
  var fs11 = __toESM(require("fs"), 1);
@@ -42256,6 +42600,44 @@ async function executeWorkerControlRequest(deps, request) {
42256
42600
  );
42257
42601
  break;
42258
42602
  }
42603
+ case "node-workdir-branch-info": {
42604
+ const self2 = deps.nodeRegistry.getSelf();
42605
+ response = jsonResponse(
42606
+ request.requestId,
42607
+ 200,
42608
+ getLocalNodeWorkDirBranchInfo(
42609
+ self2.id,
42610
+ self2.workDir ?? deps.workDir,
42611
+ request.path ?? ".",
42612
+ {
42613
+ limit: request.limit ?? 20,
42614
+ offset: request.offset ?? 0,
42615
+ allowAbsolute: request.allowAbsolute ?? true
42616
+ }
42617
+ )
42618
+ );
42619
+ break;
42620
+ }
42621
+ case "node-workdir-branch-create": {
42622
+ const self2 = deps.nodeRegistry.getSelf();
42623
+ response = jsonResponse(
42624
+ request.requestId,
42625
+ 200,
42626
+ createLocalNodeWorkDirBranch(
42627
+ self2.id,
42628
+ self2.workDir ?? deps.workDir,
42629
+ request.path ?? ".",
42630
+ {
42631
+ branchName: request.branchName ?? "",
42632
+ startPoint: request.startPoint ?? "",
42633
+ limit: request.limit ?? 20,
42634
+ offset: request.offset ?? 0,
42635
+ allowAbsolute: request.allowAbsolute ?? true
42636
+ }
42637
+ )
42638
+ );
42639
+ break;
42640
+ }
42259
42641
  case "devtunnel": {
42260
42642
  assertCanChangeNodeDevTunnel(deps.taskEngine, deps.nodeRegistry.getSelf().id);
42261
42643
  if (request.enabled) {
@@ -42520,6 +42902,148 @@ async function maybeHandleRemoteNodeWorkDirRequest(req, res, nodeId) {
42520
42902
  throw new MeshyError("NODE_OFFLINE", `Cannot reach node ${nodeId} to browse its working directory`, 502);
42521
42903
  }
42522
42904
  }
42905
+ async function maybeHandleRemoteNodeWorkDirBranchInfoRequest(req, res, nodeId) {
42906
+ const query = NodeWorkDirBranchQuery.parse(req.query);
42907
+ const { nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42908
+ const selfId = nodeRegistry.getSelf().id;
42909
+ if (nodeId === selfId) {
42910
+ return false;
42911
+ }
42912
+ const node = nodeRegistry.getNode(nodeId);
42913
+ if (!node) {
42914
+ throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
42915
+ }
42916
+ const log2 = rootLogger.child("nodes/workdir-branch");
42917
+ const proxyPath = req.originalUrl ?? `/api/nodes/${nodeId}/workdir/branch`;
42918
+ const fallbackRequest = {
42919
+ kind: "node-workdir-branch-info",
42920
+ path: query.path,
42921
+ limit: query.limit,
42922
+ offset: query.offset,
42923
+ allowAbsolute: query.allowAbsolute
42924
+ };
42925
+ const canPushToNode = heartbeat?.canPushToNode?.(nodeId) ?? true;
42926
+ if (!canPushToNode && heartbeat?.requestWorkerControl) {
42927
+ log2.warn("node workdir branch request falling back to keepalive control", {
42928
+ nodeId,
42929
+ proxyPath
42930
+ });
42931
+ const controlResponse = await heartbeat.requestWorkerControl(nodeId, fallbackRequest);
42932
+ sendWorkerControlResponse(res, controlResponse);
42933
+ return true;
42934
+ }
42935
+ try {
42936
+ const { endpoint, response } = await fetchNodeWithFallback(
42937
+ node,
42938
+ proxyPath,
42939
+ void 0,
42940
+ NODE_WORKDIR_PROXY_TIMEOUT_MS,
42941
+ createNodeWorkdirProxyTrace(log2, nodeId, proxyPath),
42942
+ { preferPublicEndpoint: true }
42943
+ );
42944
+ log2.debug("proxying node workdir branch request", {
42945
+ nodeId,
42946
+ endpoint,
42947
+ proxyPath
42948
+ });
42949
+ await sendProxyResponse(res, response);
42950
+ return true;
42951
+ } catch (err) {
42952
+ const errorDetails = describeProxyError(err);
42953
+ log2.warn("node workdir branch proxy error", {
42954
+ nodeId,
42955
+ proxyPath,
42956
+ timeoutMs: NODE_WORKDIR_PROXY_TIMEOUT_MS,
42957
+ ...errorDetails
42958
+ });
42959
+ if (heartbeat?.requestWorkerControl) {
42960
+ log2.warn("node workdir branch proxy failed, falling back to keepalive control", {
42961
+ nodeId,
42962
+ proxyPath,
42963
+ timeoutMs: NODE_WORKDIR_PROXY_TIMEOUT_MS,
42964
+ ...errorDetails
42965
+ });
42966
+ const controlResponse = await heartbeat.requestWorkerControl(nodeId, fallbackRequest);
42967
+ sendWorkerControlResponse(res, controlResponse);
42968
+ return true;
42969
+ }
42970
+ throw new MeshyError("NODE_OFFLINE", `Cannot reach node ${nodeId} to inspect its git branch`, 502);
42971
+ }
42972
+ }
42973
+ async function maybeHandleRemoteNodeWorkDirBranchCreateRequest(req, res, nodeId) {
42974
+ const body = CreateNodeWorkDirBranchBody.parse(req.body);
42975
+ const { nodeRegistry, heartbeat, logger: rootLogger } = req.app.locals.deps;
42976
+ const selfId = nodeRegistry.getSelf().id;
42977
+ if (nodeId === selfId) {
42978
+ return false;
42979
+ }
42980
+ const node = nodeRegistry.getNode(nodeId);
42981
+ if (!node) {
42982
+ throw new MeshyError("NODE_NOT_FOUND", `Node ${nodeId} not found`, 404);
42983
+ }
42984
+ const log2 = rootLogger.child("nodes/workdir-branch-create");
42985
+ const proxyPath = req.originalUrl ?? `/api/nodes/${nodeId}/workdir/branch`;
42986
+ const fallbackRequest = {
42987
+ kind: "node-workdir-branch-create",
42988
+ path: body.path,
42989
+ branchName: body.branchName,
42990
+ startPoint: body.startPoint,
42991
+ limit: body.limit,
42992
+ offset: body.offset,
42993
+ allowAbsolute: body.allowAbsolute
42994
+ };
42995
+ const canPushToNode = heartbeat?.canPushToNode?.(nodeId) ?? true;
42996
+ if (!canPushToNode && heartbeat?.requestWorkerControl) {
42997
+ log2.warn("node workdir branch create request falling back to keepalive control", {
42998
+ nodeId,
42999
+ proxyPath
43000
+ });
43001
+ const controlResponse = await heartbeat.requestWorkerControl(nodeId, fallbackRequest);
43002
+ sendWorkerControlResponse(res, controlResponse);
43003
+ return true;
43004
+ }
43005
+ try {
43006
+ const { endpoint, response } = await fetchNodeWithFallback(
43007
+ node,
43008
+ proxyPath,
43009
+ {
43010
+ method: "POST",
43011
+ headers: { "Content-Type": "application/json" },
43012
+ body: JSON.stringify(body)
43013
+ },
43014
+ NODE_WORKDIR_PROXY_TIMEOUT_MS,
43015
+ createNodeWorkdirProxyTrace(log2, nodeId, proxyPath),
43016
+ { preferPublicEndpoint: true }
43017
+ );
43018
+ log2.debug("proxying node workdir branch create request", {
43019
+ nodeId,
43020
+ endpoint,
43021
+ proxyPath
43022
+ });
43023
+ await sendProxyResponse(res, response);
43024
+ return true;
43025
+ } catch (err) {
43026
+ const errorDetails = describeProxyError(err);
43027
+ log2.warn("node workdir branch create proxy error", {
43028
+ nodeId,
43029
+ proxyPath,
43030
+ timeoutMs: NODE_WORKDIR_PROXY_TIMEOUT_MS,
43031
+ ...errorDetails
43032
+ });
43033
+ if (heartbeat?.requestWorkerControl) {
43034
+ log2.warn("node workdir branch create proxy failed, falling back to keepalive control", {
43035
+ nodeId,
43036
+ proxyPath,
43037
+ timeoutMs: NODE_WORKDIR_PROXY_TIMEOUT_MS,
43038
+ ...errorDetails
43039
+ });
43040
+ const controlResponse = await heartbeat.requestWorkerControl(nodeId, fallbackRequest);
43041
+ sendWorkerControlResponse(res, controlResponse);
43042
+ return true;
43043
+ }
43044
+ throw new MeshyError("NODE_OFFLINE", `Cannot reach node ${nodeId} to create a git branch`, 502);
43045
+ }
43046
+ }
42523
43047
  function createNodeRoutes() {
42524
43048
  const router = (0, import_express3.Router)();
42525
43049
  router.get("/", asyncHandler2(async (req, res) => {
@@ -42567,6 +43091,22 @@ function createNodeRoutes() {
42567
43091
  }
42568
43092
  sendLocalNodeWorkDirTree(req, res, nodeId);
42569
43093
  }));
43094
+ router.get("/:id/workdir/branch", asyncHandler2(async (req, res) => {
43095
+ const nodeId = req.params.id;
43096
+ const handled = await maybeHandleRemoteNodeWorkDirBranchInfoRequest(req, res, nodeId);
43097
+ if (handled) {
43098
+ return;
43099
+ }
43100
+ sendLocalNodeWorkDirBranchInfo(req, res, nodeId);
43101
+ }));
43102
+ router.post("/:id/workdir/branch", asyncHandler2(async (req, res) => {
43103
+ const nodeId = req.params.id;
43104
+ const handled = await maybeHandleRemoteNodeWorkDirBranchCreateRequest(req, res, nodeId);
43105
+ if (handled) {
43106
+ return;
43107
+ }
43108
+ sendLocalNodeWorkDirBranchCreate(req, res, nodeId);
43109
+ }));
42570
43110
  router.patch("/:id", asyncHandler2(async (req, res) => {
42571
43111
  const { nodeRegistry, persistNodeNamePreference } = req.app.locals.deps;
42572
43112
  const updates = UpdateNodeBody.parse(req.body);
@@ -43058,6 +43598,7 @@ function createTaskRoutes() {
43058
43598
  description: body.description ?? "",
43059
43599
  agent: body.agent,
43060
43600
  project: body.project ?? null,
43601
+ branch: body.branch ?? null,
43061
43602
  payload: body.payload ?? {},
43062
43603
  priority: body.priority,
43063
43604
  createdBy: "api"
@@ -43399,10 +43940,11 @@ function createWorkerRoutes() {
43399
43940
  const task = req.body;
43400
43941
  const effectiveWorkDir = workDir ?? nodeRegistry.getSelf().workDir ?? process.cwd();
43401
43942
  task.effectiveProjectPath = resolveTaskWorkDir(task.project, effectiveWorkDir);
43943
+ task.branch = getGitBranchInfo(task.effectiveProjectPath, { limit: 20, offset: 0 }).currentBranch;
43402
43944
  await taskEngine.executeTask(task);
43403
43945
  res.json({ ok: true });
43404
43946
  if (!nodeRegistry.isLeader()) {
43405
- forwardRunningStatusToLeader(log2, nodeRegistry, task.id, task.effectiveProjectPath);
43947
+ forwardRunningStatusToLeader(log2, nodeRegistry, task.id, task.effectiveProjectPath, task.branch);
43406
43948
  }
43407
43949
  const engine = engineRegistry.get(task.agent);
43408
43950
  if (engine) {
@@ -43484,7 +44026,7 @@ function createWorkerRoutes() {
43484
44026
  }
43485
44027
  taskEngine.updateTask(body.taskId, { status: "running" });
43486
44028
  if (!nodeRegistry.isLeader()) {
43487
- forwardRunningStatusToLeader(log2, nodeRegistry, body.taskId);
44029
+ forwardRunningStatusToLeader(log2, nodeRegistry, body.taskId, void 0, task.branch);
43488
44030
  }
43489
44031
  let cleanupForwarding = null;
43490
44032
  if (!nodeRegistry.isLeader()) {
@@ -43639,7 +44181,7 @@ var import_express7 = __toESM(require_express2(), 1);
43639
44181
 
43640
44182
  // ../../packages/api/src/system-info.ts
43641
44183
  var os5 = __toESM(require("os"), 1);
43642
- var import_node_child_process5 = require("child_process");
44184
+ var import_node_child_process6 = require("child_process");
43643
44185
  var RUNTIME_TOOLS = [
43644
44186
  { id: "claude", label: "Claude Code", command: "claude" },
43645
44187
  { id: "codex", label: "Codex", command: "codex" }
@@ -43653,7 +44195,7 @@ function normalizeOutput(output) {
43653
44195
  }
43654
44196
  function resolveCommandPath(command) {
43655
44197
  const lookupCommand = process.platform === "win32" ? "where" : "which";
43656
- const result = (0, import_node_child_process5.spawnSync)(lookupCommand, [command], {
44198
+ const result = (0, import_node_child_process6.spawnSync)(lookupCommand, [command], {
43657
44199
  encoding: "utf-8",
43658
44200
  shell: false,
43659
44201
  windowsHide: true,
@@ -43682,7 +44224,7 @@ function inspectTool(definition) {
43682
44224
  detail: resolved.detail ?? "Command not found on PATH"
43683
44225
  };
43684
44226
  }
43685
- const versionResult = (0, import_node_child_process5.spawnSync)(definition.command, ["--version"], {
44227
+ const versionResult = (0, import_node_child_process6.spawnSync)(definition.command, ["--version"], {
43686
44228
  encoding: "utf-8",
43687
44229
  shell: process.platform === "win32",
43688
44230
  windowsHide: true,
@@ -44128,10 +44670,10 @@ var DirectTransport = class {
44128
44670
  };
44129
44671
 
44130
44672
  // ../../packages/transport/src/devtunnel.ts
44131
- var import_node_child_process6 = require("child_process");
44673
+ var import_node_child_process7 = require("child_process");
44132
44674
  function isInstalled(cmd) {
44133
44675
  try {
44134
- (0, import_node_child_process6.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
44676
+ (0, import_node_child_process7.execSync)(process.platform === "win32" ? `where ${cmd}` : `command -v ${cmd}`, { stdio: "pipe" });
44135
44677
  return true;
44136
44678
  } catch {
44137
44679
  return false;
@@ -44154,14 +44696,14 @@ var DevTunnelTransport = class {
44154
44696
  );
44155
44697
  }
44156
44698
  try {
44157
- (0, import_node_child_process6.execSync)("devtunnel user show", { stdio: "pipe" });
44699
+ (0, import_node_child_process7.execSync)("devtunnel user show", { stdio: "pipe" });
44158
44700
  } catch {
44159
44701
  throw new Error(
44160
44702
  "Not logged in to devtunnel. Run: devtunnel user login"
44161
44703
  );
44162
44704
  }
44163
44705
  const hostArgs = this.buildHostArgs(localPort);
44164
- const child = (0, import_node_child_process6.spawn)("devtunnel", hostArgs, {
44706
+ const child = (0, import_node_child_process7.spawn)("devtunnel", hostArgs, {
44165
44707
  stdio: ["pipe", "pipe", "pipe"]
44166
44708
  });
44167
44709
  this.process = child;
@@ -44266,7 +44808,7 @@ ${lines.join("")}`
44266
44808
  return void 0;
44267
44809
  }
44268
44810
  try {
44269
- (0, import_node_child_process6.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
44811
+ (0, import_node_child_process7.execFileSync)("devtunnel", ["show", tunnelId], { stdio: "pipe" });
44270
44812
  return tunnelId;
44271
44813
  } catch {
44272
44814
  const createArgs = ["create", tunnelId];
@@ -44274,7 +44816,7 @@ ${lines.join("")}`
44274
44816
  createArgs.push("-a");
44275
44817
  }
44276
44818
  try {
44277
- (0, import_node_child_process6.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
44819
+ (0, import_node_child_process7.execFileSync)("devtunnel", createArgs, { stdio: "pipe" });
44278
44820
  return tunnelId;
44279
44821
  } catch (err) {
44280
44822
  throw new Error(
@@ -44289,7 +44831,7 @@ ${lines.join("")}`
44289
44831
  return;
44290
44832
  }
44291
44833
  try {
44292
- (0, import_node_child_process6.execFileSync)(
44834
+ (0, import_node_child_process7.execFileSync)(
44293
44835
  "devtunnel",
44294
44836
  ["port", "create", tunnelId, "-p", String(localPort), "--protocol", "http"],
44295
44837
  { stdio: "pipe" }
@@ -44305,7 +44847,7 @@ ${lines.join("")}`
44305
44847
  }
44306
44848
  listTunnelPorts(tunnelId) {
44307
44849
  try {
44308
- const output = (0, import_node_child_process6.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
44850
+ const output = (0, import_node_child_process7.execFileSync)("devtunnel", ["port", "list", tunnelId, "-j"], { stdio: "pipe" });
44309
44851
  const parsed = JSON.parse(output.toString());
44310
44852
  const items = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.ports) ? parsed.ports : parsed && typeof parsed === "object" && Array.isArray(parsed.value) ? parsed.value : [];
44311
44853
  return items.map((item) => getPortNumber(item)).filter((value) => value !== void 0);
@@ -44317,7 +44859,7 @@ ${lines.join("")}`
44317
44859
  }
44318
44860
  hasTunnelPort(tunnelId, localPort) {
44319
44861
  try {
44320
- (0, import_node_child_process6.execFileSync)(
44862
+ (0, import_node_child_process7.execFileSync)(
44321
44863
  "devtunnel",
44322
44864
  ["port", "show", tunnelId, "-p", String(localPort), "-j"],
44323
44865
  { stdio: "pipe" }
@@ -44375,7 +44917,7 @@ function createTransport(config) {
44375
44917
  var fs15 = __toESM(require("fs"), 1);
44376
44918
  var path16 = __toESM(require("path"), 1);
44377
44919
  var readline = __toESM(require("readline/promises"), 1);
44378
- var import_node_child_process7 = require("child_process");
44920
+ var import_node_child_process8 = require("child_process");
44379
44921
  function getDefaultNodeName() {
44380
44922
  return getDeviceNodeName();
44381
44923
  }
@@ -44422,7 +44964,7 @@ function createPromptSession(prompt) {
44422
44964
  }
44423
44965
  function createDefaultCommandRunner(platform2) {
44424
44966
  return (command, args, interactive = false) => {
44425
- const result = (0, import_node_child_process7.spawnSync)(command, args, {
44967
+ const result = (0, import_node_child_process8.spawnSync)(command, args, {
44426
44968
  encoding: "utf-8",
44427
44969
  shell: platform2 === "win32",
44428
44970
  stdio: interactive ? "inherit" : "pipe"
@@ -44863,7 +45405,7 @@ function formatLoadedStartMetadata(info, authEnabled) {
44863
45405
  // src/runtime-metadata.ts
44864
45406
  var fs16 = __toESM(require("fs"), 1);
44865
45407
  var path17 = __toESM(require("path"), 1);
44866
- var import_node_child_process8 = require("child_process");
45408
+ var import_node_child_process9 = require("child_process");
44867
45409
  var runtimeDir = resolveRuntimeDir();
44868
45410
  var appRoot = resolveAppRoot(runtimeDir);
44869
45411
  var repoRoot = path17.resolve(appRoot, "../..");
@@ -44958,7 +45500,7 @@ function readRepositoryUrlFromManifest(manifest) {
44958
45500
  }
44959
45501
  function readGitValue(args) {
44960
45502
  try {
44961
- const output = (0, import_node_child_process8.execFileSync)("git", args, {
45503
+ const output = (0, import_node_child_process9.execFileSync)("git", args, {
44962
45504
  cwd: repoRoot,
44963
45505
  encoding: "utf-8",
44964
45506
  stdio: ["ignore", "pipe", "ignore"],