@codebyplan/cli 2.1.0 → 2.2.0
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/cli.js +295 -43
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ var VERSION, PACKAGE_NAME;
|
|
|
37
37
|
var init_version = __esm({
|
|
38
38
|
"src/lib/version.ts"() {
|
|
39
39
|
"use strict";
|
|
40
|
-
VERSION = "2.
|
|
40
|
+
VERSION = "2.2.0";
|
|
41
41
|
PACKAGE_NAME = "@codebyplan/cli";
|
|
42
42
|
}
|
|
43
43
|
});
|
|
@@ -23526,63 +23526,232 @@ var init_read = __esm({
|
|
|
23526
23526
|
}
|
|
23527
23527
|
});
|
|
23528
23528
|
|
|
23529
|
-
// src/lib/
|
|
23529
|
+
// src/lib/git-pr.ts
|
|
23530
23530
|
import { exec as execCb } from "node:child_process";
|
|
23531
23531
|
import { promisify } from "node:util";
|
|
23532
|
-
async function
|
|
23533
|
-
|
|
23532
|
+
async function createPR(options) {
|
|
23533
|
+
const { repoPath, head, base, title, body } = options;
|
|
23534
23534
|
try {
|
|
23535
|
-
|
|
23536
|
-
|
|
23537
|
-
|
|
23535
|
+
try {
|
|
23536
|
+
const { stdout: existing } = await exec(
|
|
23537
|
+
`gh pr list --head "${head}" --base "${base}" --json number,url --jq '.[0]'`,
|
|
23538
|
+
{ cwd: repoPath }
|
|
23539
|
+
);
|
|
23540
|
+
if (existing.trim()) {
|
|
23541
|
+
const pr = JSON.parse(existing.trim());
|
|
23542
|
+
return { pr_url: pr.url, pr_number: pr.number };
|
|
23543
|
+
}
|
|
23544
|
+
} catch {
|
|
23545
|
+
}
|
|
23546
|
+
const { stdout: stdout5 } = await exec(
|
|
23547
|
+
`gh pr create --head "${head}" --base "${base}" --title "${title.replace(/"/g, '\\"')}" --body "${body.replace(/"/g, '\\"')}"`,
|
|
23548
|
+
{ cwd: repoPath }
|
|
23549
|
+
);
|
|
23550
|
+
const prUrl = stdout5.trim();
|
|
23551
|
+
const prNumber = parseInt(prUrl.split("/").pop() ?? "0", 10);
|
|
23552
|
+
return { pr_url: prUrl, pr_number: prNumber || null };
|
|
23553
|
+
} catch (err) {
|
|
23554
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
23555
|
+
return { pr_url: null, pr_number: null, error: errorMessage };
|
|
23556
|
+
}
|
|
23557
|
+
}
|
|
23558
|
+
async function getPRStatus(repoPath, prNumber) {
|
|
23559
|
+
try {
|
|
23560
|
+
const { stdout: stdout5 } = await exec(
|
|
23561
|
+
`gh pr view ${prNumber} --json state,mergeable,title,url,number`,
|
|
23562
|
+
{ cwd: repoPath }
|
|
23563
|
+
);
|
|
23564
|
+
const pr = JSON.parse(stdout5.trim());
|
|
23538
23565
|
return {
|
|
23539
|
-
|
|
23540
|
-
|
|
23541
|
-
|
|
23566
|
+
state: pr.state,
|
|
23567
|
+
mergeable: pr.mergeable,
|
|
23568
|
+
title: pr.title,
|
|
23569
|
+
url: pr.url,
|
|
23570
|
+
number: pr.number
|
|
23542
23571
|
};
|
|
23543
|
-
}
|
|
23544
|
-
|
|
23572
|
+
} catch (err) {
|
|
23573
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
23545
23574
|
return {
|
|
23546
|
-
|
|
23547
|
-
|
|
23575
|
+
state: "UNKNOWN",
|
|
23576
|
+
mergeable: "UNKNOWN",
|
|
23577
|
+
title: "",
|
|
23578
|
+
url: "",
|
|
23579
|
+
number: prNumber,
|
|
23580
|
+
error: errorMessage
|
|
23548
23581
|
};
|
|
23549
23582
|
}
|
|
23550
|
-
|
|
23583
|
+
}
|
|
23584
|
+
var exec;
|
|
23585
|
+
var init_git_pr = __esm({
|
|
23586
|
+
"src/lib/git-pr.ts"() {
|
|
23587
|
+
"use strict";
|
|
23588
|
+
exec = promisify(execCb);
|
|
23589
|
+
}
|
|
23590
|
+
});
|
|
23591
|
+
|
|
23592
|
+
// src/lib/promotion.ts
|
|
23593
|
+
async function promoteCheckpoint(checkpointId) {
|
|
23594
|
+
try {
|
|
23595
|
+
const checkpointRes = await apiGet(`/checkpoints/${checkpointId}`);
|
|
23596
|
+
const checkpoint = checkpointRes.data;
|
|
23597
|
+
if (!checkpoint.branch_name) {
|
|
23598
|
+
return {
|
|
23599
|
+
promoted: false,
|
|
23600
|
+
pr_url: null,
|
|
23601
|
+
pr_number: null,
|
|
23602
|
+
checklist_id: null,
|
|
23603
|
+
message: "Checkpoint has no branch_name set",
|
|
23604
|
+
error: "No branch_name on checkpoint"
|
|
23605
|
+
};
|
|
23606
|
+
}
|
|
23607
|
+
const repoRes = await apiGet(`/repos/${checkpoint.repo_id}`);
|
|
23608
|
+
const repo = repoRes.data;
|
|
23609
|
+
if (!repo.path) {
|
|
23610
|
+
return {
|
|
23611
|
+
promoted: false,
|
|
23612
|
+
pr_url: null,
|
|
23613
|
+
pr_number: null,
|
|
23614
|
+
checklist_id: null,
|
|
23615
|
+
message: "Repo path not configured",
|
|
23616
|
+
error: "Repo path not configured"
|
|
23617
|
+
};
|
|
23618
|
+
}
|
|
23619
|
+
const baseBranch = repo.git_branch ?? "development";
|
|
23620
|
+
const chkNumber = checkpoint.number.toString().padStart(3, "0");
|
|
23621
|
+
const checklist = await createChecklistFromTemplates(
|
|
23622
|
+
checkpoint.repo_id,
|
|
23623
|
+
checkpointId,
|
|
23624
|
+
"feat_to_development",
|
|
23625
|
+
`CHK-${chkNumber}: ${checkpoint.title ?? "Untitled"} \u2192 ${baseBranch}`
|
|
23626
|
+
);
|
|
23627
|
+
const prResult = await createPR({
|
|
23628
|
+
repoPath: repo.path,
|
|
23629
|
+
head: checkpoint.branch_name,
|
|
23630
|
+
base: baseBranch,
|
|
23631
|
+
title: `CHK-${chkNumber}: ${checkpoint.title ?? "Checkpoint completion"}`,
|
|
23632
|
+
body: `## Checkpoint CHK-${chkNumber}
|
|
23633
|
+
|
|
23634
|
+
**Goal**: ${checkpoint.goal ?? "N/A"}
|
|
23635
|
+
|
|
23636
|
+
Automatically created by CodeByPlan promotion engine.`
|
|
23637
|
+
});
|
|
23638
|
+
if (checklist && prResult.pr_url) {
|
|
23639
|
+
await apiPut(`/merge-checklists/${checklist.id}`, {
|
|
23640
|
+
pr_url: prResult.pr_url,
|
|
23641
|
+
pr_number: prResult.pr_number,
|
|
23642
|
+
status: "in_progress"
|
|
23643
|
+
});
|
|
23644
|
+
}
|
|
23551
23645
|
return {
|
|
23552
|
-
|
|
23553
|
-
|
|
23554
|
-
|
|
23646
|
+
promoted: true,
|
|
23647
|
+
pr_url: prResult.pr_url,
|
|
23648
|
+
pr_number: prResult.pr_number,
|
|
23649
|
+
checklist_id: checklist?.id ?? null,
|
|
23650
|
+
message: prResult.error ? `PR creation issue: ${prResult.error}` : `PR created: ${prResult.pr_url}`
|
|
23651
|
+
};
|
|
23652
|
+
} catch (err) {
|
|
23653
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
23654
|
+
return {
|
|
23655
|
+
promoted: false,
|
|
23656
|
+
pr_url: null,
|
|
23657
|
+
pr_number: null,
|
|
23658
|
+
checklist_id: null,
|
|
23659
|
+
message: "Promotion failed",
|
|
23660
|
+
error: errorMessage
|
|
23555
23661
|
};
|
|
23556
23662
|
}
|
|
23557
|
-
|
|
23663
|
+
}
|
|
23664
|
+
async function promoteToMain(repoId) {
|
|
23558
23665
|
try {
|
|
23559
|
-
|
|
23560
|
-
|
|
23561
|
-
|
|
23562
|
-
|
|
23666
|
+
const repoRes = await apiGet(`/repos/${repoId}`);
|
|
23667
|
+
const repo = repoRes.data;
|
|
23668
|
+
if (!repo.path) {
|
|
23669
|
+
return {
|
|
23670
|
+
promoted: false,
|
|
23671
|
+
pr_url: null,
|
|
23672
|
+
pr_number: null,
|
|
23673
|
+
checklist_id: null,
|
|
23674
|
+
message: "Repo path not configured",
|
|
23675
|
+
error: "Repo path not configured"
|
|
23676
|
+
};
|
|
23677
|
+
}
|
|
23678
|
+
const sourceBranch = repo.git_branch ?? "development";
|
|
23679
|
+
const prResult = await createPR({
|
|
23680
|
+
repoPath: repo.path,
|
|
23681
|
+
head: sourceBranch,
|
|
23682
|
+
base: "main",
|
|
23683
|
+
title: `Promote ${sourceBranch} \u2192 main`,
|
|
23684
|
+
body: `Promotion from ${sourceBranch} to main.
|
|
23685
|
+
|
|
23686
|
+
Automatically created by CodeByPlan promotion engine.`
|
|
23687
|
+
});
|
|
23563
23688
|
return {
|
|
23564
|
-
|
|
23565
|
-
|
|
23689
|
+
promoted: true,
|
|
23690
|
+
pr_url: prResult.pr_url,
|
|
23691
|
+
pr_number: prResult.pr_number,
|
|
23692
|
+
checklist_id: null,
|
|
23693
|
+
message: prResult.error ? `PR creation issue: ${prResult.error}` : `PR created: ${prResult.pr_url}`
|
|
23566
23694
|
};
|
|
23567
23695
|
} catch (err) {
|
|
23568
|
-
try {
|
|
23569
|
-
await exec(`git checkout ${sourceBranch}`, { cwd: repo.path });
|
|
23570
|
-
} catch {
|
|
23571
|
-
}
|
|
23572
23696
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
23573
23697
|
return {
|
|
23574
|
-
|
|
23575
|
-
|
|
23698
|
+
promoted: false,
|
|
23699
|
+
pr_url: null,
|
|
23700
|
+
pr_number: null,
|
|
23701
|
+
checklist_id: null,
|
|
23702
|
+
message: "Promotion to main failed",
|
|
23576
23703
|
error: errorMessage
|
|
23577
23704
|
};
|
|
23578
23705
|
}
|
|
23579
23706
|
}
|
|
23580
|
-
|
|
23581
|
-
|
|
23582
|
-
|
|
23707
|
+
async function createChecklistFromTemplates(repoId, checkpointId, branchLevel, title) {
|
|
23708
|
+
try {
|
|
23709
|
+
const templatesRes = await apiGet(
|
|
23710
|
+
`/repos/${repoId}/checklist-templates`,
|
|
23711
|
+
{ branch_level: branchLevel }
|
|
23712
|
+
);
|
|
23713
|
+
const templates = templatesRes.data ?? [];
|
|
23714
|
+
const items = templates.map((t) => ({
|
|
23715
|
+
title: t.title,
|
|
23716
|
+
description: t.description,
|
|
23717
|
+
is_required: t.is_required,
|
|
23718
|
+
checked: false,
|
|
23719
|
+
checked_at: null
|
|
23720
|
+
}));
|
|
23721
|
+
const checklistRes = await apiPost(
|
|
23722
|
+
"/merge-checklists",
|
|
23723
|
+
{
|
|
23724
|
+
checkpoint_id: checkpointId,
|
|
23725
|
+
branch_level: branchLevel,
|
|
23726
|
+
title,
|
|
23727
|
+
status: "pending",
|
|
23728
|
+
items
|
|
23729
|
+
}
|
|
23730
|
+
);
|
|
23731
|
+
return checklistRes.data;
|
|
23732
|
+
} catch {
|
|
23733
|
+
try {
|
|
23734
|
+
const checklistRes = await apiPost(
|
|
23735
|
+
"/merge-checklists",
|
|
23736
|
+
{
|
|
23737
|
+
checkpoint_id: checkpointId,
|
|
23738
|
+
branch_level: branchLevel,
|
|
23739
|
+
title,
|
|
23740
|
+
status: "pending",
|
|
23741
|
+
items: []
|
|
23742
|
+
}
|
|
23743
|
+
);
|
|
23744
|
+
return checklistRes.data;
|
|
23745
|
+
} catch {
|
|
23746
|
+
return null;
|
|
23747
|
+
}
|
|
23748
|
+
}
|
|
23749
|
+
}
|
|
23750
|
+
var init_promotion = __esm({
|
|
23751
|
+
"src/lib/promotion.ts"() {
|
|
23583
23752
|
"use strict";
|
|
23584
23753
|
init_api();
|
|
23585
|
-
|
|
23754
|
+
init_git_pr();
|
|
23586
23755
|
}
|
|
23587
23756
|
});
|
|
23588
23757
|
|
|
@@ -23659,6 +23828,7 @@ function registerWriteTools(server) {
|
|
|
23659
23828
|
launch_id: external_exports.string().uuid().nullable().optional().describe("Launch UUID to connect (or null to disconnect)"),
|
|
23660
23829
|
worktree_id: external_exports.string().uuid().nullable().optional().describe("Worktree UUID to assign (or null to unassign)"),
|
|
23661
23830
|
assigned_to: external_exports.string().nullable().optional().describe("Who/what claimed this checkpoint"),
|
|
23831
|
+
branch_name: external_exports.string().nullable().optional().describe("Git branch name for this checkpoint (e.g. feat/CHK-061-git-overhaul)"),
|
|
23662
23832
|
ideas: external_exports.array(external_exports.object({
|
|
23663
23833
|
description: external_exports.string().describe("Idea description"),
|
|
23664
23834
|
requirements: external_exports.array(external_exports.string()).optional().describe("List of requirements for this idea"),
|
|
@@ -23668,7 +23838,7 @@ function registerWriteTools(server) {
|
|
|
23668
23838
|
research: external_exports.any().optional().describe("Research JSONB (topics with findings and sources)"),
|
|
23669
23839
|
qa: external_exports.any().optional().describe("QA JSONB (checklist items with type, check, status)")
|
|
23670
23840
|
}
|
|
23671
|
-
}, async ({ checkpoint_id, title, goal, status, deadline, completed_at, launch_id, worktree_id, assigned_to, ideas, context, research, qa }) => {
|
|
23841
|
+
}, async ({ checkpoint_id, title, goal, status, deadline, completed_at, launch_id, worktree_id, assigned_to, branch_name, ideas, context, research, qa }) => {
|
|
23672
23842
|
const update = {};
|
|
23673
23843
|
if (title !== void 0) update.title = title;
|
|
23674
23844
|
if (goal !== void 0) update.goal = goal;
|
|
@@ -23678,6 +23848,7 @@ function registerWriteTools(server) {
|
|
|
23678
23848
|
if (launch_id !== void 0) update.launch_id = launch_id;
|
|
23679
23849
|
if (worktree_id !== void 0) update.worktree_id = worktree_id;
|
|
23680
23850
|
if (assigned_to !== void 0) update.assigned_to = assigned_to;
|
|
23851
|
+
if (branch_name !== void 0) update.branch_name = branch_name;
|
|
23681
23852
|
if (ideas !== void 0) update.ideas = ideas;
|
|
23682
23853
|
if (context !== void 0) update.context = context;
|
|
23683
23854
|
if (research !== void 0) update.research = research;
|
|
@@ -23693,7 +23864,7 @@ function registerWriteTools(server) {
|
|
|
23693
23864
|
}
|
|
23694
23865
|
});
|
|
23695
23866
|
server.registerTool("complete_checkpoint", {
|
|
23696
|
-
description: "Mark a checkpoint as completed. Sets status to 'completed', completed_at to now, and triggers
|
|
23867
|
+
description: "Mark a checkpoint as completed. Sets status to 'completed', completed_at to now, and triggers promotion (creates PR from feat branch to development).",
|
|
23697
23868
|
inputSchema: {
|
|
23698
23869
|
checkpoint_id: external_exports.string().uuid().describe("The checkpoint UUID")
|
|
23699
23870
|
}
|
|
@@ -23704,8 +23875,13 @@ function registerWriteTools(server) {
|
|
|
23704
23875
|
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
23705
23876
|
});
|
|
23706
23877
|
const checkpoint = res.data;
|
|
23707
|
-
const
|
|
23708
|
-
|
|
23878
|
+
const featToDevResult = await promoteCheckpoint(checkpoint_id);
|
|
23879
|
+
let devToMainResult = null;
|
|
23880
|
+
const repoRes = await apiGet(`/repos/${checkpoint.repo_id}`);
|
|
23881
|
+
if (repoRes.data.auto_push_enabled) {
|
|
23882
|
+
devToMainResult = await promoteToMain(checkpoint.repo_id);
|
|
23883
|
+
}
|
|
23884
|
+
return { content: [{ type: "text", text: JSON.stringify({ checkpoint, promotion: { feat_to_development: featToDevResult, development_to_main: devToMainResult } }, null, 2) }] };
|
|
23709
23885
|
} catch (err) {
|
|
23710
23886
|
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
23711
23887
|
}
|
|
@@ -24101,13 +24277,74 @@ function registerWriteTools(server) {
|
|
|
24101
24277
|
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
24102
24278
|
}
|
|
24103
24279
|
});
|
|
24280
|
+
server.registerTool("create_pr", {
|
|
24281
|
+
description: "Create a GitHub PR for a repo. Uses gh CLI.",
|
|
24282
|
+
inputSchema: {
|
|
24283
|
+
repo_id: external_exports.string().uuid().describe("The repo UUID"),
|
|
24284
|
+
head: external_exports.string().describe("Source branch name"),
|
|
24285
|
+
base: external_exports.string().describe("Target branch name"),
|
|
24286
|
+
title: external_exports.string().describe("PR title"),
|
|
24287
|
+
body: external_exports.string().optional().describe("PR description body")
|
|
24288
|
+
}
|
|
24289
|
+
}, async ({ repo_id, head, base, title, body }) => {
|
|
24290
|
+
try {
|
|
24291
|
+
const repoRes = await apiGet(`/repos/${repo_id}`);
|
|
24292
|
+
const repo = repoRes.data;
|
|
24293
|
+
if (!repo.path) {
|
|
24294
|
+
return { content: [{ type: "text", text: "Error: Repo path is not configured." }], isError: true };
|
|
24295
|
+
}
|
|
24296
|
+
const result = await createPR({
|
|
24297
|
+
repoPath: repo.path,
|
|
24298
|
+
head,
|
|
24299
|
+
base,
|
|
24300
|
+
title,
|
|
24301
|
+
body: body ?? ""
|
|
24302
|
+
});
|
|
24303
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24304
|
+
} catch (err) {
|
|
24305
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
24306
|
+
}
|
|
24307
|
+
});
|
|
24308
|
+
server.registerTool("get_pr_status", {
|
|
24309
|
+
description: "Get the status of a GitHub PR by number.",
|
|
24310
|
+
inputSchema: {
|
|
24311
|
+
repo_id: external_exports.string().uuid().describe("The repo UUID"),
|
|
24312
|
+
pr_number: external_exports.number().int().describe("The PR number")
|
|
24313
|
+
}
|
|
24314
|
+
}, async ({ repo_id, pr_number }) => {
|
|
24315
|
+
try {
|
|
24316
|
+
const repoRes = await apiGet(`/repos/${repo_id}`);
|
|
24317
|
+
const repo = repoRes.data;
|
|
24318
|
+
if (!repo.path) {
|
|
24319
|
+
return { content: [{ type: "text", text: "Error: Repo path is not configured." }], isError: true };
|
|
24320
|
+
}
|
|
24321
|
+
const status = await getPRStatus(repo.path, pr_number);
|
|
24322
|
+
return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
|
|
24323
|
+
} catch (err) {
|
|
24324
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
24325
|
+
}
|
|
24326
|
+
});
|
|
24327
|
+
server.registerTool("promote_checkpoint", {
|
|
24328
|
+
description: "Trigger full promotion flow for a checkpoint. Creates merge checklist from templates and GitHub PR (feat branch \u2192 development).",
|
|
24329
|
+
inputSchema: {
|
|
24330
|
+
checkpoint_id: external_exports.string().uuid().describe("The checkpoint UUID")
|
|
24331
|
+
}
|
|
24332
|
+
}, async ({ checkpoint_id }) => {
|
|
24333
|
+
try {
|
|
24334
|
+
const result = await promoteCheckpoint(checkpoint_id);
|
|
24335
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24336
|
+
} catch (err) {
|
|
24337
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
24338
|
+
}
|
|
24339
|
+
});
|
|
24104
24340
|
}
|
|
24105
24341
|
var init_write = __esm({
|
|
24106
24342
|
"src/tools/write.ts"() {
|
|
24107
24343
|
"use strict";
|
|
24108
24344
|
init_zod();
|
|
24109
24345
|
init_api();
|
|
24110
|
-
|
|
24346
|
+
init_promotion();
|
|
24347
|
+
init_git_pr();
|
|
24111
24348
|
init_sync_engine();
|
|
24112
24349
|
}
|
|
24113
24350
|
});
|
|
@@ -24117,30 +24354,45 @@ import { exec as execCb2 } from "node:child_process";
|
|
|
24117
24354
|
import { promisify as promisify2 } from "node:util";
|
|
24118
24355
|
function registerFileGenTools(server) {
|
|
24119
24356
|
server.registerTool("git_commit", {
|
|
24120
|
-
description: "Stage files and create a git commit in a repo. If files are specified, stages only those files. Otherwise stages all changes.",
|
|
24357
|
+
description: "Stage files and create a git commit in a repo. If files are specified, stages only those files. Otherwise stages all changes. Optionally verifies the current branch matches branch_name.",
|
|
24121
24358
|
inputSchema: {
|
|
24122
24359
|
repo_id: external_exports.string().uuid().describe("The repo UUID"),
|
|
24123
24360
|
message: external_exports.string().describe("Commit message"),
|
|
24124
|
-
files: external_exports.array(external_exports.string()).optional().describe("Specific file paths to stage (relative to repo root). If omitted, stages all changes.")
|
|
24361
|
+
files: external_exports.array(external_exports.string()).optional().describe("Specific file paths to stage (relative to repo root). If omitted, stages all changes."),
|
|
24362
|
+
branch_name: external_exports.string().optional().describe("Expected branch name. If provided, verifies the repo is on this branch before committing.")
|
|
24125
24363
|
}
|
|
24126
|
-
}, async ({ repo_id, message, files }) => {
|
|
24364
|
+
}, async ({ repo_id, message, files, branch_name }) => {
|
|
24127
24365
|
try {
|
|
24128
24366
|
const repoRes = await apiGet(`/repos/${repo_id}`);
|
|
24129
24367
|
const repo = repoRes.data;
|
|
24130
24368
|
if (!repo.path) {
|
|
24131
24369
|
return { content: [{ type: "text", text: "Error: Repo path is not configured." }], isError: true };
|
|
24132
24370
|
}
|
|
24371
|
+
if (branch_name) {
|
|
24372
|
+
const { stdout: currentBranch } = await exec2("git rev-parse --abbrev-ref HEAD", { cwd: repo.path });
|
|
24373
|
+
if (currentBranch.trim() !== branch_name) {
|
|
24374
|
+
return {
|
|
24375
|
+
content: [{
|
|
24376
|
+
type: "text",
|
|
24377
|
+
text: `Error: Expected branch "${branch_name}" but currently on "${currentBranch.trim()}".`
|
|
24378
|
+
}],
|
|
24379
|
+
isError: true
|
|
24380
|
+
};
|
|
24381
|
+
}
|
|
24382
|
+
}
|
|
24133
24383
|
const addCmd = files && files.length > 0 ? `git add ${files.map((f) => `"${f}"`).join(" ")}` : "git add .";
|
|
24134
24384
|
await exec2(addCmd, { cwd: repo.path });
|
|
24135
24385
|
const { stdout: stdout5, stderr } = await exec2(
|
|
24136
24386
|
`git commit -m "${message.replace(/"/g, '\\"')}"`,
|
|
24137
24387
|
{ cwd: repo.path }
|
|
24138
24388
|
);
|
|
24389
|
+
const { stdout: branch } = await exec2("git rev-parse --abbrev-ref HEAD", { cwd: repo.path });
|
|
24139
24390
|
return {
|
|
24140
24391
|
content: [{
|
|
24141
24392
|
type: "text",
|
|
24142
24393
|
text: JSON.stringify({
|
|
24143
24394
|
status: "committed",
|
|
24395
|
+
branch: branch.trim(),
|
|
24144
24396
|
output: stdout5.trim(),
|
|
24145
24397
|
warnings: stderr.trim() || void 0
|
|
24146
24398
|
}, null, 2)
|