@bridge_gpt/mcp-server 0.1.16 → 0.1.17
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/README.md +36 -1
- package/build/agent-launchers/claude.js +85 -0
- package/build/agent-launchers/index.js +17 -0
- package/build/agent-launchers/types.js +1 -0
- package/build/chain-orchestrator.js +1150 -0
- package/build/chain-utils.js +68 -0
- package/build/commands.generated.js +3 -1
- package/build/fetch-stub.js +139 -0
- package/build/index.js +137 -10
- package/build/pipeline-orchestrator.js +57 -0
- package/build/pipelines.generated.js +132 -3
- package/build/schedule-run.js +951 -0
- package/build/schedule-store.js +132 -0
- package/build/scheduler-backends/at-fallback.js +144 -0
- package/build/scheduler-backends/escaping.js +113 -0
- package/build/scheduler-backends/index.js +72 -0
- package/build/scheduler-backends/launchd.js +216 -0
- package/build/scheduler-backends/systemd-user.js +237 -0
- package/build/scheduler-backends/task-scheduler.js +219 -0
- package/build/scheduler-backends/types.js +23 -0
- package/build/start-tickets.js +119 -59
- package/build/version.generated.js +1 -1
- package/package.json +7 -7
- package/pipelines/full-automation.json +47 -0
- package/pipelines/idea-to-ticket.json +71 -0
- package/smoke-test/SMOKE-TEST.md +509 -0
- package/smoke-test/smoke-test-mcp.md +23 -0
package/build/start-tickets.js
CHANGED
|
@@ -89,7 +89,8 @@ export function getStartTicketsUsage() {
|
|
|
89
89
|
" --terminal terminal|iterm Override the macOS terminal app (default: auto-detect via $TERM_PROGRAM); honored on macOS only",
|
|
90
90
|
" --dry-run Print intended actions; create no worktrees, open no tabs",
|
|
91
91
|
" --branch KEY=BRANCH Use BRANCH instead of feature/KEY for that ticket (repeatable)",
|
|
92
|
-
" --
|
|
92
|
+
" --base-branch BRANCH Cut new worktrees from BRANCH and refresh origin/BRANCH (default: main)",
|
|
93
|
+
" --no-refresh-main Skip refresh of the configured base branch (default main); historical name retained for backward compatibility",
|
|
93
94
|
" --max-parallel N Max worktrees to create concurrently (default: 3)",
|
|
94
95
|
" -h, --help Show this help",
|
|
95
96
|
"",
|
|
@@ -116,9 +117,11 @@ export function parseStartTicketsArgs(argv) {
|
|
|
116
117
|
}
|
|
117
118
|
let terminal;
|
|
118
119
|
let dryRun = false;
|
|
120
|
+
let autoApprove = false;
|
|
119
121
|
let refreshMain = true;
|
|
120
122
|
let maxParallelRaw;
|
|
121
123
|
let agentName = DEFAULT_AGENT_NAME;
|
|
124
|
+
let baseBranch = "main";
|
|
122
125
|
const branchEntries = [];
|
|
123
126
|
const keys = [];
|
|
124
127
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -198,10 +201,36 @@ export function parseStartTicketsArgs(argv) {
|
|
|
198
201
|
branchEntries.push(value);
|
|
199
202
|
continue;
|
|
200
203
|
}
|
|
204
|
+
if (arg === "--base-branch" || arg.startsWith("--base-branch=")) {
|
|
205
|
+
let value;
|
|
206
|
+
if (arg.startsWith("--base-branch=")) {
|
|
207
|
+
value = arg.slice("--base-branch=".length);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
// For the space-separated form, reject a following option token so we
|
|
211
|
+
// don't silently consume "--dry-run" (etc.) as the branch value.
|
|
212
|
+
const next = i + 1 < argv.length ? argv[i + 1] : undefined;
|
|
213
|
+
if (next === undefined || next.startsWith("-")) {
|
|
214
|
+
return { status: "error", message: "--base-branch requires a value (a branch name)." };
|
|
215
|
+
}
|
|
216
|
+
value = takeValue();
|
|
217
|
+
}
|
|
218
|
+
const trimmed = (value ?? "").trim();
|
|
219
|
+
const error = validateBranchName(trimmed);
|
|
220
|
+
if (error) {
|
|
221
|
+
return { status: "error", message: `Invalid --base-branch value: ${error}` };
|
|
222
|
+
}
|
|
223
|
+
baseBranch = trimmed;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
201
226
|
if (arg === "--dry-run") {
|
|
202
227
|
dryRun = true;
|
|
203
228
|
continue;
|
|
204
229
|
}
|
|
230
|
+
if (arg === "--auto-approve") {
|
|
231
|
+
autoApprove = true;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
205
234
|
if (arg === "--no-refresh-main") {
|
|
206
235
|
refreshMain = false;
|
|
207
236
|
continue;
|
|
@@ -277,13 +306,15 @@ export function parseStartTicketsArgs(argv) {
|
|
|
277
306
|
}
|
|
278
307
|
return {
|
|
279
308
|
status: "ok",
|
|
280
|
-
options: { keys, terminal, dryRun, refreshMain, maxParallel, branchOverrides, agentName },
|
|
309
|
+
options: { keys, terminal, dryRun, autoApprove, refreshMain, maxParallel, branchOverrides, agentName, baseBranch },
|
|
281
310
|
};
|
|
282
311
|
}
|
|
283
312
|
/** Returns an error string for an unsafe branch name, or null when valid. */
|
|
284
|
-
function validateBranchName(branch) {
|
|
285
|
-
if (branch.length === 0)
|
|
313
|
+
export function validateBranchName(branch) {
|
|
314
|
+
if (branch.trim().length === 0)
|
|
286
315
|
return "branch name must not be empty.";
|
|
316
|
+
if (branch.length > 255)
|
|
317
|
+
return "branch name must be 255 characters or fewer.";
|
|
287
318
|
if (branch.startsWith("-"))
|
|
288
319
|
return "branch name must not start with '-'.";
|
|
289
320
|
// Reject ASCII control characters (0x00-0x1F and 0x7F) without embedding
|
|
@@ -343,7 +374,7 @@ export function getDefaultSpawnTerminalTabForPlatform(platform) {
|
|
|
343
374
|
* are always honored). Returns a structured error for unsupported platforms;
|
|
344
375
|
* never throws.
|
|
345
376
|
*/
|
|
346
|
-
export function resolveStartTicketsPlatformConfig(deps, agent) {
|
|
377
|
+
export function resolveStartTicketsPlatformConfig(deps, agent, autoApprove = false) {
|
|
347
378
|
if (!isSupportedStartTicketsPlatform(deps.platform)) {
|
|
348
379
|
return { ok: false, error: unsupportedPlatformMessage(deps.platform) };
|
|
349
380
|
}
|
|
@@ -353,7 +384,7 @@ export function resolveStartTicketsPlatformConfig(deps, agent) {
|
|
|
353
384
|
config: {
|
|
354
385
|
platform,
|
|
355
386
|
worktrunkBinary: resolveWorktrunkBinary(platform, deps.env),
|
|
356
|
-
buildAgentShellCommand: (key, worktreePath) => buildAgentShellCommand(agent, key, worktreePath, platform),
|
|
387
|
+
buildAgentShellCommand: (key, worktreePath) => buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove),
|
|
357
388
|
spawnTerminalTab: deps.spawnTerminalTab,
|
|
358
389
|
},
|
|
359
390
|
};
|
|
@@ -522,84 +553,106 @@ export function parseGitWorktreeList(output) {
|
|
|
522
553
|
entries.push(current);
|
|
523
554
|
return entries;
|
|
524
555
|
}
|
|
525
|
-
/** Return the worktree path owning branch `
|
|
526
|
-
export function
|
|
556
|
+
/** Return the worktree path owning branch `baseBranch`, or null. */
|
|
557
|
+
export function findBaseWorktreePath(entries, baseBranch) {
|
|
527
558
|
for (const entry of entries) {
|
|
528
|
-
if (entry.branch ===
|
|
559
|
+
if (entry.branch === baseBranch)
|
|
529
560
|
return entry.path;
|
|
530
561
|
}
|
|
531
562
|
return null;
|
|
532
563
|
}
|
|
533
564
|
/**
|
|
534
|
-
*
|
|
535
|
-
*
|
|
565
|
+
* Compatibility wrapper: returns the worktree path owning branch `main`, or
|
|
566
|
+
* null. Defers to {@link findBaseWorktreePath} so the `main` and non-main paths
|
|
567
|
+
* stay identical.
|
|
568
|
+
*/
|
|
569
|
+
export function findMainWorktreePath(entries) {
|
|
570
|
+
return findBaseWorktreePath(entries, "main");
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Fetch origin/<baseBranch> and fast-forward the local base branch. No-op when
|
|
574
|
+
* `refreshMain` is false. (The option key keeps its historical name so the
|
|
575
|
+
* `--no-refresh-main` user-facing flag remains backward-compatible; the
|
|
576
|
+
* behavior now follows whatever `baseBranch` resolves to, default `"main"`.)
|
|
536
577
|
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
578
|
+
* Handles both checkout states:
|
|
579
|
+
*
|
|
580
|
+
* - `<baseBranch>` IS checked out in a worktree → `git merge --ff-only` inside
|
|
581
|
+
* that worktree, so its index/working tree stay consistent (git forbids
|
|
539
582
|
* force-moving a checked-out branch ref).
|
|
540
|
-
* -
|
|
541
|
-
* feature/chore branch) → fast-forward the ref directly with
|
|
583
|
+
* - `<baseBranch>` is NOT checked out anywhere (e.g. the primary checkout is
|
|
584
|
+
* on a feature/chore branch) → fast-forward the ref directly with
|
|
542
585
|
* `git branch --force`, since no working tree depends on it. This is guarded
|
|
543
|
-
* by an ancestry check so a diverged local
|
|
544
|
-
* creates
|
|
586
|
+
* by an ancestry check so a diverged local base is never clobbered, and it
|
|
587
|
+
* creates the local base ref from origin when no local ref exists yet.
|
|
545
588
|
*
|
|
546
589
|
* Returns a structured failure for any expected problem (fetch failure, diverged
|
|
547
|
-
*
|
|
590
|
+
* base branch, or a failed ref update).
|
|
548
591
|
*/
|
|
549
|
-
export async function
|
|
592
|
+
export async function refreshBaseBranch(deps, options) {
|
|
550
593
|
if (!options.refreshMain)
|
|
551
594
|
return { ok: true };
|
|
552
|
-
const
|
|
595
|
+
const baseBranch = options.baseBranch;
|
|
596
|
+
const originRef = `origin/${baseBranch}`;
|
|
597
|
+
const fetch = await deps.runCommand("git", ["fetch", "origin", baseBranch], {
|
|
553
598
|
cwd: deps.cwd,
|
|
554
599
|
});
|
|
555
600
|
if (!commandSucceeded(fetch)) {
|
|
556
601
|
return {
|
|
557
602
|
ok: false,
|
|
558
|
-
error:
|
|
603
|
+
error: `git fetch origin ${baseBranch} failed. Check your network and 'git remote get-url origin', or pass --no-refresh-main to skip.`,
|
|
559
604
|
};
|
|
560
605
|
}
|
|
561
606
|
const list = await deps.runCommand("git", ["worktree", "list", "--porcelain"], { cwd: deps.cwd });
|
|
562
607
|
if (!commandSucceeded(list)) {
|
|
563
608
|
return {
|
|
564
609
|
ok: false,
|
|
565
|
-
error:
|
|
610
|
+
error: `git worktree list --porcelain failed; cannot locate the ${baseBranch} worktree.`,
|
|
566
611
|
};
|
|
567
612
|
}
|
|
568
|
-
const
|
|
569
|
-
//
|
|
613
|
+
const basePath = findBaseWorktreePath(parseGitWorktreeList(list.stdout), baseBranch);
|
|
614
|
+
// `<baseBranch>` is checked out somewhere: fast-forward it in place. git refuses to
|
|
570
615
|
// force-move a checked-out branch ref, so we must go through merge.
|
|
571
|
-
if (
|
|
572
|
-
const merge = await deps.runCommand("git", ["merge", "--ff-only",
|
|
616
|
+
if (basePath) {
|
|
617
|
+
const merge = await deps.runCommand("git", ["merge", "--ff-only", originRef], { cwd: basePath });
|
|
573
618
|
if (!commandSucceeded(merge)) {
|
|
574
619
|
return {
|
|
575
620
|
ok: false,
|
|
576
|
-
error: `Local
|
|
621
|
+
error: `Local ${baseBranch} has diverged from ${originRef} (checked out at ${basePath}). Resolve the divergence manually, or rerun with --no-refresh-main.`,
|
|
577
622
|
};
|
|
578
623
|
}
|
|
579
624
|
return { ok: true };
|
|
580
625
|
}
|
|
581
|
-
//
|
|
582
|
-
// ref, so fast-forward it directly — but only when it is a true
|
|
583
|
-
// never clobbering local-only commits. When local
|
|
584
|
-
// create it from origin
|
|
585
|
-
if (await branchExists(deps,
|
|
586
|
-
const ancestor = await deps.runCommand("git", ["merge-base", "--is-ancestor",
|
|
626
|
+
// `<baseBranch>` is not checked out in any worktree. No working tree depends
|
|
627
|
+
// on the ref, so fast-forward it directly — but only when it is a true
|
|
628
|
+
// fast-forward, never clobbering local-only commits. When the local base ref
|
|
629
|
+
// does not exist yet, create it from origin.
|
|
630
|
+
if (await branchExists(deps, baseBranch)) {
|
|
631
|
+
const ancestor = await deps.runCommand("git", ["merge-base", "--is-ancestor", baseBranch, originRef], { cwd: deps.cwd });
|
|
587
632
|
if (!commandSucceeded(ancestor)) {
|
|
588
633
|
return {
|
|
589
634
|
ok: false,
|
|
590
|
-
error:
|
|
635
|
+
error: `Local ${baseBranch} has diverged from ${originRef}. Resolve the divergence manually, or rerun with --no-refresh-main.`,
|
|
591
636
|
};
|
|
592
637
|
}
|
|
593
638
|
}
|
|
594
|
-
const update = await deps.runCommand("git", ["branch", "--force",
|
|
639
|
+
const update = await deps.runCommand("git", ["branch", "--force", baseBranch, originRef], { cwd: deps.cwd });
|
|
595
640
|
if (!commandSucceeded(update)) {
|
|
596
641
|
return {
|
|
597
642
|
ok: false,
|
|
598
|
-
error:
|
|
643
|
+
error: `Failed to fast-forward local ${baseBranch} to ${originRef}. Resolve manually, or rerun with --no-refresh-main.`,
|
|
599
644
|
};
|
|
600
645
|
}
|
|
601
646
|
return { ok: true };
|
|
602
647
|
}
|
|
648
|
+
/**
|
|
649
|
+
* Compatibility wrapper around {@link refreshBaseBranch} that preserves the
|
|
650
|
+
* historical `refreshMainBranch(deps, { refreshMain })` signature for callers
|
|
651
|
+
* that target `main` specifically.
|
|
652
|
+
*/
|
|
653
|
+
export async function refreshMainBranch(deps, options) {
|
|
654
|
+
return refreshBaseBranch(deps, { refreshMain: options.refreshMain, baseBranch: "main" });
|
|
655
|
+
}
|
|
603
656
|
// ---------------------------------------------------------------------------
|
|
604
657
|
// Concurrency + worktree creation
|
|
605
658
|
// ---------------------------------------------------------------------------
|
|
@@ -643,11 +696,11 @@ export async function branchExists(deps, branch) {
|
|
|
643
696
|
* tab spawning separately. The args are platform-agnostic; only the binary
|
|
644
697
|
* differs (`wt` vs `git-wt`).
|
|
645
698
|
*/
|
|
646
|
-
export function buildWtSwitchArgs(branch, exists) {
|
|
699
|
+
export function buildWtSwitchArgs(branch, exists, baseBranch = "main") {
|
|
647
700
|
if (exists) {
|
|
648
701
|
return ["switch", "-y", branch, "--format=json"];
|
|
649
702
|
}
|
|
650
|
-
return ["switch", "--create", "-y", branch, "--format=json"];
|
|
703
|
+
return ["switch", "--create", "-y", branch, "-b", baseBranch, "--format=json"];
|
|
651
704
|
}
|
|
652
705
|
/** Return the Node `path` API matching a platform (`win32` vs POSIX). */
|
|
653
706
|
export function pathApiForPlatform(platform) {
|
|
@@ -698,11 +751,11 @@ function pickWorktreePathField(parsed) {
|
|
|
698
751
|
* success (with key, branch, path) or a `create-failed` row on any expected
|
|
699
752
|
* failure — never throws for per-ticket problems.
|
|
700
753
|
*/
|
|
701
|
-
export async function createWorktreeForTicket(deps, key, branchOverrides, worktrunkBinary) {
|
|
754
|
+
export async function createWorktreeForTicket(deps, key, branchOverrides, worktrunkBinary, baseBranch = "main") {
|
|
702
755
|
const branch = resolveBranchForTicket(key, branchOverrides);
|
|
703
756
|
try {
|
|
704
757
|
const exists = await branchExists(deps, branch);
|
|
705
|
-
const args = buildWtSwitchArgs(branch, exists);
|
|
758
|
+
const args = buildWtSwitchArgs(branch, exists, baseBranch);
|
|
706
759
|
const result = await deps.runCommand(worktrunkBinary, args, { cwd: deps.cwd });
|
|
707
760
|
if (!commandSucceeded(result)) {
|
|
708
761
|
const reason = (result.stderr || result.stdout || "").trim();
|
|
@@ -728,14 +781,18 @@ export async function createWorktreeForTicket(deps, key, branchOverrides, worktr
|
|
|
728
781
|
* aborting the run.
|
|
729
782
|
*/
|
|
730
783
|
export async function createWorktrees(deps, options, worktrunkBinary) {
|
|
731
|
-
return runWithConcurrency(options.keys, options.maxParallel, (key) => createWorktreeForTicket(deps, key, options.branchOverrides, worktrunkBinary));
|
|
784
|
+
return runWithConcurrency(options.keys, options.maxParallel, (key) => createWorktreeForTicket(deps, key, options.branchOverrides, worktrunkBinary, options.baseBranch));
|
|
732
785
|
}
|
|
733
786
|
// ---------------------------------------------------------------------------
|
|
734
787
|
// Per-platform shell-command construction
|
|
735
788
|
// ---------------------------------------------------------------------------
|
|
736
|
-
/**
|
|
737
|
-
|
|
738
|
-
|
|
789
|
+
/**
|
|
790
|
+
* The starter prompt handed to the selected agent. Identical for every agent.
|
|
791
|
+
* When `autoApprove` is set, the implementation agent runs hands-off
|
|
792
|
+
* (`/implement-ticket <KEY> --auto-approve`) — used by full-automation chains.
|
|
793
|
+
*/
|
|
794
|
+
export function buildAgentPrompt(key, opts = {}) {
|
|
795
|
+
return `/implement-ticket ${key}${opts.autoApprove ? " --auto-approve" : ""}`;
|
|
739
796
|
}
|
|
740
797
|
/**
|
|
741
798
|
* Build the agent invocation (`<command> <quotedPrompt>`) for the agent's prompt
|
|
@@ -754,13 +811,13 @@ export function buildAgentInvocation(agent, prompt, quote) {
|
|
|
754
811
|
}
|
|
755
812
|
}
|
|
756
813
|
/** POSIX agent shell command: `cd '<path>' && <agent> '<prompt>'`. */
|
|
757
|
-
export function buildPosixAgentShellCommand(agent, key, worktreePath) {
|
|
758
|
-
const invocation = buildAgentInvocation(agent, buildAgentPrompt(key), (p) => `'${shSquoteInner(p)}'`);
|
|
814
|
+
export function buildPosixAgentShellCommand(agent, key, worktreePath, autoApprove = false) {
|
|
815
|
+
const invocation = buildAgentInvocation(agent, buildAgentPrompt(key, { autoApprove }), (p) => `'${shSquoteInner(p)}'`);
|
|
759
816
|
return `cd '${shSquoteInner(worktreePath)}' && ${invocation}`;
|
|
760
817
|
}
|
|
761
818
|
/** PowerShell agent shell command: `Set-Location -LiteralPath '<path>'; <agent> '<prompt>'`. */
|
|
762
|
-
export function buildPowerShellAgentShellCommand(agent, key, worktreePath) {
|
|
763
|
-
const invocation = buildAgentInvocation(agent, buildAgentPrompt(key), powershellSquote);
|
|
819
|
+
export function buildPowerShellAgentShellCommand(agent, key, worktreePath, autoApprove = false) {
|
|
820
|
+
const invocation = buildAgentInvocation(agent, buildAgentPrompt(key, { autoApprove }), powershellSquote);
|
|
764
821
|
return `Set-Location -LiteralPath ${powershellSquote(worktreePath)}; ${invocation}`;
|
|
765
822
|
}
|
|
766
823
|
/**
|
|
@@ -769,10 +826,10 @@ export function buildPowerShellAgentShellCommand(agent, key, worktreePath) {
|
|
|
769
826
|
* dry-run fallback). The selected `agent` (never a module-level constant)
|
|
770
827
|
* determines the launched command.
|
|
771
828
|
*/
|
|
772
|
-
export function buildAgentShellCommand(agent, key, worktreePath, platform = "darwin") {
|
|
829
|
+
export function buildAgentShellCommand(agent, key, worktreePath, platform = "darwin", autoApprove = false) {
|
|
773
830
|
if (platform === "win32")
|
|
774
|
-
return buildPowerShellAgentShellCommand(agent, key, worktreePath);
|
|
775
|
-
return buildPosixAgentShellCommand(agent, key, worktreePath);
|
|
831
|
+
return buildPowerShellAgentShellCommand(agent, key, worktreePath, autoApprove);
|
|
832
|
+
return buildPosixAgentShellCommand(agent, key, worktreePath, autoApprove);
|
|
776
833
|
}
|
|
777
834
|
// ---------------------------------------------------------------------------
|
|
778
835
|
// macOS terminal spawning (behind the injected boundary)
|
|
@@ -1048,10 +1105,10 @@ export function buildDryRunResults(keys, overrides) {
|
|
|
1048
1105
|
* PowerShell on Windows, `wt` + POSIX on macOS/Linux, and a non-throwing `wt` +
|
|
1049
1106
|
* POSIX fallback for unsupported platforms.
|
|
1050
1107
|
*/
|
|
1051
|
-
export function getDryRunPlatformDetails(agent, platform = process.platform, env = process.env) {
|
|
1108
|
+
export function getDryRunPlatformDetails(agent, platform = process.platform, env = process.env, autoApprove = false) {
|
|
1052
1109
|
return {
|
|
1053
1110
|
worktrunkBinary: resolveWorktrunkBinary(platform, env),
|
|
1054
|
-
buildAgentShellCommand: (key, worktreePath) => buildAgentShellCommand(agent, key, worktreePath, platform),
|
|
1111
|
+
buildAgentShellCommand: (key, worktreePath) => buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove),
|
|
1055
1112
|
};
|
|
1056
1113
|
}
|
|
1057
1114
|
/**
|
|
@@ -1059,9 +1116,9 @@ export function getDryRunPlatformDetails(agent, platform = process.platform, env
|
|
|
1059
1116
|
* platform-correct Worktrunk binary and the selected agent's shell command. Pure
|
|
1060
1117
|
* platform formatting only — no preflight, no routing failures.
|
|
1061
1118
|
*/
|
|
1062
|
-
export function buildDryRunDetailLines(agent, key, branch, platform = process.platform, env = process.env) {
|
|
1063
|
-
const { worktrunkBinary, buildAgentShellCommand: build } = getDryRunPlatformDetails(agent, platform, env);
|
|
1064
|
-
const wtArgs = buildWtSwitchArgs(branch, false);
|
|
1119
|
+
export function buildDryRunDetailLines(agent, key, branch, platform = process.platform, env = process.env, baseBranch = "main", autoApprove = false) {
|
|
1120
|
+
const { worktrunkBinary, buildAgentShellCommand: build } = getDryRunPlatformDetails(agent, platform, env, autoApprove);
|
|
1121
|
+
const wtArgs = buildWtSwitchArgs(branch, false, baseBranch);
|
|
1065
1122
|
const agentInvocation = build(key, "<worktree-path>");
|
|
1066
1123
|
return [
|
|
1067
1124
|
`DRY-RUN: ${key} -> branch=${branch}`,
|
|
@@ -1117,10 +1174,13 @@ export async function orchestrateStartTickets(deps, options) {
|
|
|
1117
1174
|
const preflight = await runPreflight(deps, options);
|
|
1118
1175
|
if (!preflight.ok)
|
|
1119
1176
|
return { ok: false, error: preflight.error };
|
|
1120
|
-
const platformConfig = resolveStartTicketsPlatformConfig(deps, agent);
|
|
1177
|
+
const platformConfig = resolveStartTicketsPlatformConfig(deps, agent, options.autoApprove);
|
|
1121
1178
|
if (!platformConfig.ok)
|
|
1122
1179
|
return { ok: false, error: platformConfig.error };
|
|
1123
|
-
const refresh = await
|
|
1180
|
+
const refresh = await refreshBaseBranch(deps, {
|
|
1181
|
+
refreshMain: options.refreshMain,
|
|
1182
|
+
baseBranch: options.baseBranch,
|
|
1183
|
+
});
|
|
1124
1184
|
if (!refresh.ok)
|
|
1125
1185
|
return { ok: false, error: refresh.error };
|
|
1126
1186
|
const created = await createWorktrees(deps, options, platformConfig.config.worktrunkBinary);
|
|
@@ -1179,7 +1239,7 @@ export async function runStartTicketsCli(argv, overrides = {}) {
|
|
|
1179
1239
|
if (options.dryRun) {
|
|
1180
1240
|
for (const key of options.keys) {
|
|
1181
1241
|
const branch = resolveBranchForTicket(key, options.branchOverrides);
|
|
1182
|
-
for (const line of buildDryRunDetailLines(agent, key, branch, deps.platform, deps.env)) {
|
|
1242
|
+
for (const line of buildDryRunDetailLines(agent, key, branch, deps.platform, deps.env, options.baseBranch, options.autoApprove)) {
|
|
1183
1243
|
log(line);
|
|
1184
1244
|
}
|
|
1185
1245
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
|
|
2
|
-
export const VERSION = "0.1.
|
|
2
|
+
export const VERSION = "0.1.17";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bridge_gpt/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"description": "Bridge API MCP server — exposes Jira endpoints as MCP tools for Claude Code agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"!build/**/*.test.js",
|
|
13
13
|
"!build/integration/**",
|
|
14
14
|
"pipelines/",
|
|
15
|
+
"smoke-test/",
|
|
15
16
|
"README.md",
|
|
16
17
|
"LICENSE"
|
|
17
18
|
],
|
|
@@ -19,18 +20,17 @@
|
|
|
19
20
|
"build": "node scripts/bundle-version.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && tsc",
|
|
20
21
|
"postbuild": "node scripts/prepend-shebang.cjs",
|
|
21
22
|
"start": "node build/index.js",
|
|
22
|
-
"test": "node --test build/pipeline-utils.test.js build/update-check.test.js build/cli-upgrade.test.js build/decision-page-schema.test.js build/decision-page-template.test.js build/bundle-pipelines.test.js build/instructions-contract.test.js build/pipeline-orchestrator-persistence.test.js build/pipeline-orchestrator-execution.test.js build/pipeline-orchestrator-integration.test.js build/index-static.test.js build/start-tickets.test.js build/agent-registry.test.js build/start-tickets-prereqs.test.js build/doctor.test.js build/package-static.test.js",
|
|
23
|
+
"test": "node --test build/pipeline-utils.test.js build/update-check.test.js build/cli-upgrade.test.js build/decision-page-schema.test.js build/decision-page-template.test.js build/bundle-pipelines.test.js build/instructions-contract.test.js build/pipeline-orchestrator-persistence.test.js build/pipeline-orchestrator-execution.test.js build/pipeline-orchestrator-integration.test.js build/index-static.test.js build/start-tickets.test.js build/start-tickets-base-branch.test.js build/agent-registry.test.js build/start-tickets-prereqs.test.js build/doctor.test.js build/package-static.test.js build/chain-utils.test.js build/chain-orchestrator.test.js build/scheduler-backends/types.test.js build/scheduler-backends/escaping.test.js build/scheduler-backends/launchd.test.js build/scheduler-backends/task-scheduler.test.js build/scheduler-backends/systemd-user.test.js build/scheduler-backends/at-fallback.test.js build/scheduler-backends/index.test.js build/agent-launchers/claude.test.js build/agent-launchers/index.test.js build/schedule-store.test.js build/schedule-run.test.js",
|
|
23
24
|
"test:integration": "node --test build/integration/refresh-main.integration.test.js build/integration/start-tickets.integration.test.js build/integration/doctor.integration.test.js",
|
|
24
25
|
"prepublishOnly": "npm run build && node scripts/verify-shebang.cjs"
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
28
|
-
"zod": "^
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
+
"zod": "^4.4.3"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@types/node": "^
|
|
32
|
-
"typescript": "^
|
|
33
|
-
"undici": "^6.25.0"
|
|
32
|
+
"@types/node": "^25.9.1",
|
|
33
|
+
"typescript": "^6.0.3"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=18.0.0"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "full-automation",
|
|
3
|
+
"description": "Drive an idea end-to-end: create ticket(s) (idea-to-ticket), review each ticket (review-ticket fan-out), then hand off to the /start-tickets CLI seam to spawn worktrees.",
|
|
4
|
+
"variables": [
|
|
5
|
+
"idea",
|
|
6
|
+
"auto_approve",
|
|
7
|
+
"scheduled_at",
|
|
8
|
+
"max_children",
|
|
9
|
+
"allow_duplicate",
|
|
10
|
+
"agent"
|
|
11
|
+
],
|
|
12
|
+
"stages": [
|
|
13
|
+
{
|
|
14
|
+
"pipeline_name": "idea-to-ticket",
|
|
15
|
+
"description": "Convert the idea into one or more Jira tickets.",
|
|
16
|
+
"variables": {
|
|
17
|
+
"idea": "{idea}",
|
|
18
|
+
"max_children": "{max_children}",
|
|
19
|
+
"allow_duplicate": "{allow_duplicate}",
|
|
20
|
+
"auto_approve_external": "{auto_approve}"
|
|
21
|
+
},
|
|
22
|
+
"outputs": {
|
|
23
|
+
"created_ticket_keys": "created_ticket_keys"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"pipeline_name": "review-ticket",
|
|
28
|
+
"description": "Review each created ticket (one child pipeline run per ticket).",
|
|
29
|
+
"fan_out_input": "created_ticket_keys",
|
|
30
|
+
"fan_out_variable": "ticket_key",
|
|
31
|
+
"variables": {
|
|
32
|
+
"ticket_key": "{ticket_key}"
|
|
33
|
+
},
|
|
34
|
+
"outputs": {
|
|
35
|
+
"reviewed_ticket_keys": "reviewed_ticket_keys"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"pipeline_name": "start-tickets",
|
|
40
|
+
"description": "Hand off the reviewed tickets to the /start-tickets CLI seam (agent-task; not a server pipeline).",
|
|
41
|
+
"fan_out_input": "reviewed_ticket_keys",
|
|
42
|
+
"outputs": {
|
|
43
|
+
"started_ticket_keys": "started_ticket_keys"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Idea to Ticket",
|
|
3
|
+
"description": "Convert a short human idea into either a single Jira Task/Spike or a Jira Epic plus decomposed child tickets.",
|
|
4
|
+
"variables": [
|
|
5
|
+
"idea",
|
|
6
|
+
"idea_hash",
|
|
7
|
+
"slug",
|
|
8
|
+
"run_id",
|
|
9
|
+
"docs_dir",
|
|
10
|
+
"allow_duplicate",
|
|
11
|
+
"auto_approve_external",
|
|
12
|
+
"max_children"
|
|
13
|
+
],
|
|
14
|
+
"steps": [
|
|
15
|
+
{
|
|
16
|
+
"type": "mcp_call",
|
|
17
|
+
"tool": "ping",
|
|
18
|
+
"params": {},
|
|
19
|
+
"description": "Verify Bridge API connectivity"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"type": "mcp_call",
|
|
23
|
+
"tool": "get_docs_dir",
|
|
24
|
+
"params": {},
|
|
25
|
+
"description": "Resolve the docs directory for run artifacts"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "mcp_call",
|
|
29
|
+
"tool": "get_project_standards",
|
|
30
|
+
"params": {},
|
|
31
|
+
"description": "Fetch project standards for screening (optional)",
|
|
32
|
+
"on_error": "warn_and_continue"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "agent_task",
|
|
36
|
+
"instruction_file": "preflight-and-readiness.md",
|
|
37
|
+
"description": "Initialize run directory, classify readiness and scope"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "agent_task",
|
|
41
|
+
"instruction_file": "research-decision.md",
|
|
42
|
+
"description": "Decide which research tools to run for this idea"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"type": "agent_task",
|
|
46
|
+
"instruction_file": "execute-research.md",
|
|
47
|
+
"description": "Execute the planned research and produce the research pack",
|
|
48
|
+
"on_error": "warn_and_continue"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "agent_task",
|
|
52
|
+
"instruction_file": "duplicate-and-context-scan.md",
|
|
53
|
+
"description": "Scan Jira for duplicate/related tickets"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "agent_task",
|
|
57
|
+
"instruction_file": "screen-and-resolve.md",
|
|
58
|
+
"description": "Build standards checklist and resolve open questions"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "agent_task",
|
|
62
|
+
"instruction_file": "draft-and-critique.md",
|
|
63
|
+
"description": "Draft the ticket(s) and run a hygiene/critique pass"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "agent_task",
|
|
67
|
+
"instruction_file": "upload-and-track.md",
|
|
68
|
+
"description": "Upload to Jira and track the new ticket(s) idempotently"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|