rl-workspaces 0.5.0 → 0.7.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/README.md +234 -193
- package/bin/rl +2 -54
- package/dist/agent-launch.js +1 -1
- package/dist/agent-presets.js +42 -17
- package/dist/agent-resume.js +2 -2
- package/dist/agent-runner.js +20 -0
- package/dist/agent-workflows.js +60 -16
- package/dist/automation-config.js +144 -5
- package/dist/bootstrap.js +74 -0
- package/dist/cli.js +2 -0
- package/dist/command-context.js +1 -1
- package/dist/common.js +3 -2
- package/dist/dependencies.js +197 -0
- package/dist/doctor.js +1 -1
- package/dist/git-workflow.js +8 -102
- package/dist/help.js +113 -116
- package/dist/hooks.js +1 -1
- package/dist/install.js +143 -0
- package/dist/mcp-setup.js +171 -0
- package/dist/mcp.js +13 -16
- package/dist/picker.js +24 -7
- package/dist/pr-workflow.js +7 -28
- package/dist/repos.js +5 -1
- package/dist/session-workflows.js +122 -18
- package/dist/session.js +1 -1
- package/dist/state.js +4 -14
- package/dist/storage.js +2 -2
- package/dist/store.js +2 -2
- package/dist/summary.js +1 -1
- package/dist/workflow-collaboration.js +531 -0
- package/dist/workflow.js +24 -38
- package/lib/entry.zsh +54 -0
- package/lib/rl.zsh +37 -9
- package/node_modules/proper-lockfile/CHANGELOG.md +108 -0
- package/node_modules/smol-toml/LICENSE +24 -0
- package/node_modules/smol-toml/README.md +605 -0
- package/node_modules/smol-toml/dist/date.d.ts +41 -0
- package/node_modules/smol-toml/dist/date.js +156 -0
- package/node_modules/smol-toml/dist/error.d.ts +37 -0
- package/node_modules/smol-toml/dist/error.js +67 -0
- package/node_modules/smol-toml/dist/extract.js +293 -0
- package/node_modules/smol-toml/dist/index.cjs +771 -0
- package/node_modules/smol-toml/dist/index.d.ts +44 -0
- package/node_modules/smol-toml/dist/index.js +34 -0
- package/node_modules/smol-toml/dist/parse.d.ts +73 -0
- package/node_modules/smol-toml/dist/parse.js +164 -0
- package/node_modules/smol-toml/dist/primitive.js +151 -0
- package/node_modules/smol-toml/dist/stringify.d.ts +32 -0
- package/node_modules/smol-toml/dist/stringify.js +219 -0
- package/node_modules/smol-toml/dist/struct.js +156 -0
- package/node_modules/smol-toml/dist/util.d.ts +43 -0
- package/node_modules/smol-toml/dist/util.js +57 -0
- package/node_modules/smol-toml/package.json +68 -0
- package/package.json +6 -3
- package/shell/rl.zsh +1 -1
package/dist/common.js
CHANGED
|
@@ -6,6 +6,7 @@ import { spawnSync, spawn } from "node:child_process";
|
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
7
7
|
import lockfile from "proper-lockfile";
|
|
8
8
|
import { readJsonObject } from "./json.js";
|
|
9
|
+
import { executableError } from "./dependencies.js";
|
|
9
10
|
export const now = () => new Date().toISOString();
|
|
10
11
|
export const message = (error) => error instanceof Error ? error.message : String(error);
|
|
11
12
|
export const json = (data) => console.log(JSON.stringify(data, null, 2));
|
|
@@ -54,7 +55,7 @@ export function run(argv, cwd, raw = false) {
|
|
|
54
55
|
maxBuffer: 32 * 1024 * 1024,
|
|
55
56
|
});
|
|
56
57
|
if (result.error)
|
|
57
|
-
throw result.error;
|
|
58
|
+
throw executableError(result.error, argv[0], cwd);
|
|
58
59
|
if (result.status !== 0)
|
|
59
60
|
throw new Error(result.stderr.trim() || `Command failed: ${argv.join(" ")}`);
|
|
60
61
|
return raw ? result.stdout : result.stdout.trim();
|
|
@@ -130,7 +131,7 @@ export async function execute(argv, cwd, options = {}) {
|
|
|
130
131
|
};
|
|
131
132
|
child.on("error", (error) => {
|
|
132
133
|
cleanup();
|
|
133
|
-
reject(error);
|
|
134
|
+
reject(executableError(error, argv[0], cwd));
|
|
134
135
|
});
|
|
135
136
|
child.on("close", (code, signal) => {
|
|
136
137
|
cleanup();
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
export const TOOL_NAMES = ["git", "zsh", "fzf", "gh"];
|
|
7
|
+
export function findExecutable(name, env = process.env) {
|
|
8
|
+
for (const directory of (env.PATH ?? "").split(path.delimiter)) {
|
|
9
|
+
if (!directory)
|
|
10
|
+
continue;
|
|
11
|
+
const file = path.resolve(directory, name);
|
|
12
|
+
try {
|
|
13
|
+
fs.accessSync(file, fs.constants.X_OK);
|
|
14
|
+
if (fs.statSync(file).isFile())
|
|
15
|
+
return file;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
/* Try the next PATH entry. */
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
export function inspectDependencies(env = process.env) {
|
|
24
|
+
return TOOL_NAMES.map((name) => {
|
|
25
|
+
const executable = findExecutable(name, env);
|
|
26
|
+
const probe = executable
|
|
27
|
+
? spawnSync(executable, ["--version"], {
|
|
28
|
+
env,
|
|
29
|
+
encoding: "utf8",
|
|
30
|
+
timeout: 5000,
|
|
31
|
+
})
|
|
32
|
+
: undefined;
|
|
33
|
+
return {
|
|
34
|
+
name,
|
|
35
|
+
path: executable,
|
|
36
|
+
available: probe?.status === 0,
|
|
37
|
+
version: probe?.status === 0
|
|
38
|
+
? (probe.stdout.trim().split(/\r?\n/)[0]?.slice(0, 200) ?? null)
|
|
39
|
+
: null,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function installPlan(missing, host, interactive) {
|
|
44
|
+
const env = host.env ?? process.env;
|
|
45
|
+
const platform = host.platform ?? process.platform;
|
|
46
|
+
const brew = findExecutable("brew", env);
|
|
47
|
+
if (brew)
|
|
48
|
+
return [{ executable: brew, args: ["install", ...missing] }];
|
|
49
|
+
if (platform === "darwin")
|
|
50
|
+
throw new Error("Homebrew is required to install missing RL tools on macOS. Install it from https://brew.sh, then run 'rl setup dependencies'.");
|
|
51
|
+
if (platform !== "linux")
|
|
52
|
+
throw new Error("RL supports macOS and Linux");
|
|
53
|
+
const managers = [
|
|
54
|
+
{ name: "apt-get", args: ["install", "-y"], packages: missing },
|
|
55
|
+
{ name: "dnf", args: ["install", "-y"], packages: missing },
|
|
56
|
+
{ name: "yum", args: ["install", "-y"], packages: missing },
|
|
57
|
+
{
|
|
58
|
+
name: "pacman",
|
|
59
|
+
args: ["-S", "--needed", "--noconfirm"],
|
|
60
|
+
packages: missing.map((name) => (name === "gh" ? "github-cli" : name)),
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "apk",
|
|
64
|
+
args: ["add"],
|
|
65
|
+
packages: missing.map((name) => (name === "gh" ? "github-cli" : name)),
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
for (const manager of managers) {
|
|
69
|
+
const executable = findExecutable(manager.name, env);
|
|
70
|
+
if (!executable)
|
|
71
|
+
continue;
|
|
72
|
+
const commands = manager.name === "apt-get"
|
|
73
|
+
? [
|
|
74
|
+
{ executable, args: ["update"] },
|
|
75
|
+
{ executable, args: [...manager.args, ...manager.packages] },
|
|
76
|
+
]
|
|
77
|
+
: [{ executable, args: [...manager.args, ...manager.packages] }];
|
|
78
|
+
const uid = host.uid ?? process.getuid?.();
|
|
79
|
+
if (uid === 0)
|
|
80
|
+
return commands;
|
|
81
|
+
const sudo = findExecutable("sudo", env);
|
|
82
|
+
if (!sudo)
|
|
83
|
+
throw new Error(`Installing missing RL tools requires administrator access. Run: sudo ${manager.name} ${[...manager.args, ...manager.packages].join(" ")}`);
|
|
84
|
+
return commands.map((command) => ({
|
|
85
|
+
executable: sudo,
|
|
86
|
+
args: [
|
|
87
|
+
...(interactive ? [] : ["-n"]),
|
|
88
|
+
command.executable,
|
|
89
|
+
...command.args,
|
|
90
|
+
],
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
throw new Error("No supported package manager found. Install Git, zsh, fzf and gh, then run 'rl setup dependencies --check'.");
|
|
94
|
+
}
|
|
95
|
+
export async function setupDependencies(argv, host = {}) {
|
|
96
|
+
const { values, positionals } = parseArgs({
|
|
97
|
+
args: argv,
|
|
98
|
+
allowPositionals: true,
|
|
99
|
+
options: {
|
|
100
|
+
install: { type: "boolean" },
|
|
101
|
+
check: { type: "boolean" },
|
|
102
|
+
"dry-run": { type: "boolean" },
|
|
103
|
+
json: { type: "boolean" },
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
if (positionals.length ||
|
|
107
|
+
(values.check && (values.install || values["dry-run"])))
|
|
108
|
+
throw new Error("Usage: rl setup dependencies [--check | --dry-run] [--json]");
|
|
109
|
+
const env = host.env ?? process.env;
|
|
110
|
+
let tools = inspectDependencies(env);
|
|
111
|
+
const missing = tools
|
|
112
|
+
.filter((tool) => !tool.available)
|
|
113
|
+
.map((tool) => tool.name);
|
|
114
|
+
let commands = [];
|
|
115
|
+
let error;
|
|
116
|
+
const interactive = !!process.stdin.isTTY && !!process.stdout.isTTY && !values.json;
|
|
117
|
+
if (missing.length && !values.check) {
|
|
118
|
+
try {
|
|
119
|
+
commands = installPlan(missing, host, interactive);
|
|
120
|
+
if (!values["dry-run"]) {
|
|
121
|
+
console.error(`RL: installing missing tools: ${missing.join(", ")}`);
|
|
122
|
+
for (const command of commands) {
|
|
123
|
+
const result = spawnSync(command.executable, command.args, {
|
|
124
|
+
env: {
|
|
125
|
+
...env,
|
|
126
|
+
HOMEBREW_NO_AUTO_UPDATE: "1",
|
|
127
|
+
...(interactive ? {} : { NONINTERACTIVE: "1" }),
|
|
128
|
+
},
|
|
129
|
+
stdio: interactive ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
130
|
+
encoding: "utf8",
|
|
131
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
132
|
+
});
|
|
133
|
+
if (!interactive) {
|
|
134
|
+
if (result.stdout)
|
|
135
|
+
process.stderr.write(result.stdout);
|
|
136
|
+
if (result.stderr)
|
|
137
|
+
process.stderr.write(result.stderr);
|
|
138
|
+
}
|
|
139
|
+
if (result.error || result.status !== 0)
|
|
140
|
+
throw new Error(`Could not install RL tools. Run '${command.executable} ${command.args.filter((arg) => arg !== "-n").join(" ")}' in your terminal, then rerun 'rl setup dependencies'.`);
|
|
141
|
+
}
|
|
142
|
+
tools = inspectDependencies(env);
|
|
143
|
+
const remaining = tools
|
|
144
|
+
.filter((tool) => !tool.available)
|
|
145
|
+
.map((tool) => tool.name);
|
|
146
|
+
if (remaining.length)
|
|
147
|
+
throw new Error(`Tools still unavailable on PATH: ${remaining.join(", ")}. Add the package manager's bin directory to PATH, then rerun 'rl setup dependencies'.`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (failure) {
|
|
151
|
+
error = failure instanceof Error ? failure.message : String(failure);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const ready = tools.every((tool) => tool.available);
|
|
155
|
+
const report = {
|
|
156
|
+
ready,
|
|
157
|
+
dryRun: !!values["dry-run"],
|
|
158
|
+
tools,
|
|
159
|
+
commands,
|
|
160
|
+
...(error ? { error } : {}),
|
|
161
|
+
};
|
|
162
|
+
if (values.json)
|
|
163
|
+
console.log(JSON.stringify(report, null, 2));
|
|
164
|
+
else {
|
|
165
|
+
for (const tool of tools)
|
|
166
|
+
console.log(`${tool.name}: ${tool.available ? (tool.version ?? "installed") : "missing or not working"}`);
|
|
167
|
+
if (values["dry-run"])
|
|
168
|
+
for (const command of commands)
|
|
169
|
+
console.log(`Would run: ${command.executable} ${command.args.join(" ")}`);
|
|
170
|
+
if (error)
|
|
171
|
+
console.error(`RL: ${error}`);
|
|
172
|
+
else if (!ready && values.check)
|
|
173
|
+
console.error("Run 'rl setup dependencies' to install missing tools.");
|
|
174
|
+
}
|
|
175
|
+
return error ? 1 : values["dry-run"] || ready ? 0 : 1;
|
|
176
|
+
}
|
|
177
|
+
export function executableError(error, executable, cwd) {
|
|
178
|
+
if (error.code !== "ENOENT")
|
|
179
|
+
return error;
|
|
180
|
+
if (!fs.existsSync(cwd))
|
|
181
|
+
return new Error(`Working directory does not exist: ${cwd}`, {
|
|
182
|
+
cause: error,
|
|
183
|
+
});
|
|
184
|
+
if (TOOL_NAMES.includes(path.basename(executable)))
|
|
185
|
+
return new Error(`Missing required tool ${path.basename(executable)}. Run 'rl setup dependencies' to install Git, zsh, fzf and gh.`, { cause: error });
|
|
186
|
+
return error;
|
|
187
|
+
}
|
|
188
|
+
if (process.argv[1] &&
|
|
189
|
+
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
190
|
+
try {
|
|
191
|
+
process.exitCode = await setupDependencies(process.argv.slice(2));
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
console.error(`RL: ${error instanceof Error ? error.message : String(error)}`);
|
|
195
|
+
process.exitCode = 1;
|
|
196
|
+
}
|
|
197
|
+
}
|
package/dist/doctor.js
CHANGED
|
@@ -126,7 +126,7 @@ export async function doctor(store, selected, asJson = false) {
|
|
|
126
126
|
console.log(` CLI: ${item.executablePath ?? "not on PATH"}; launch flags: ${item.launchVerified ? "verified in installed help" : "unverified"}; hook trust: unknown`);
|
|
127
127
|
console.log(` Last received event: ${item.lastSuccess ? `${item.lastSuccess.event} at ${item.lastSuccess.at}` : "none"}`);
|
|
128
128
|
if (item.missingEvents.length)
|
|
129
|
-
console.log(` Missing hooks: ${item.missingEvents.join(", ")}. Run rl adopt.`);
|
|
129
|
+
console.log(` Missing hooks: ${item.missingEvents.join(", ")}. Run rl setup adopt.`);
|
|
130
130
|
if (item.configError)
|
|
131
131
|
console.log(` Configuration error: ${item.configError}`);
|
|
132
132
|
if (item.cliError)
|
package/dist/git-workflow.js
CHANGED
|
@@ -1,116 +1,22 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
import { args, arity, canonical, execute, git, gitRaw, locked, required, } from "./common.js";
|
|
2
|
+
import { args, arity, canonical, execute, git, locked, required, } from "./common.js";
|
|
4
3
|
import { commandContext, contextOptions, resolveWorkspace, } from "./command-context.js";
|
|
5
4
|
import { worktrees } from "./repos.js";
|
|
6
5
|
import { assertReady, GIT_WORKFLOW_DIRECTORY, GIT_WORKFLOW_LOCK, } from "./git-safety.js";
|
|
7
|
-
const BACKUP_PREFIX = "refs/rl/backups/";
|
|
8
|
-
const READ_OPTIONS = new Set([
|
|
9
|
-
"--stat",
|
|
10
|
-
"--name-only",
|
|
11
|
-
"--name-status",
|
|
12
|
-
"--numstat",
|
|
13
|
-
"--patch",
|
|
14
|
-
"--oneline",
|
|
15
|
-
"--graph",
|
|
16
|
-
"--decorate",
|
|
17
|
-
"--all",
|
|
18
|
-
]);
|
|
19
6
|
function revision(root, ref) {
|
|
20
7
|
return git(root, "rev-parse", "--verify", "--end-of-options", `${ref}^{commit}`);
|
|
21
8
|
}
|
|
22
9
|
export async function main(argv) {
|
|
23
|
-
const
|
|
24
|
-
const trailing = separator < 0 ? [] : argv.slice(separator + 1);
|
|
25
|
-
const { values, positionals } = args(separator < 0 ? argv : argv.slice(0, separator), [...contextOptions, "base", "message"], ["all", "squash", "cleanup", "dry-run"], { message: "m" });
|
|
26
|
-
const context = commandContext(values);
|
|
10
|
+
const { values, positionals } = args(argv, [...contextOptions, "message"], ["squash", "cleanup", "dry-run"], { message: "m" });
|
|
27
11
|
const [command, ...rest] = positionals;
|
|
12
|
+
if (command !== "merge")
|
|
13
|
+
throw new Error("Unknown Git workflow command");
|
|
14
|
+
arity(rest, 0, 1);
|
|
15
|
+
if (values.message && !values.squash)
|
|
16
|
+
throw new Error("Invalid merge options");
|
|
17
|
+
const context = commandContext(values);
|
|
28
18
|
const source = resolveWorkspace(context);
|
|
29
|
-
if (command === "diff" || command === "log") {
|
|
30
|
-
arity(rest, 0);
|
|
31
|
-
if (values.all ||
|
|
32
|
-
values.squash ||
|
|
33
|
-
values.cleanup ||
|
|
34
|
-
values.message ||
|
|
35
|
-
values["dry-run"])
|
|
36
|
-
throw new Error("Invalid display options");
|
|
37
|
-
const pathSeparator = trailing.indexOf("--");
|
|
38
|
-
const flags = pathSeparator < 0 ? trailing : trailing.slice(0, pathSeparator);
|
|
39
|
-
const paths = pathSeparator < 0 ? [] : trailing.slice(pathSeparator + 1);
|
|
40
|
-
for (const flag of flags)
|
|
41
|
-
if (!READ_OPTIONS.has(flag) && !/^(-\d+|--max-count=\d+)$/.test(flag))
|
|
42
|
-
throw new Error(`Unsupported display option: ${flag}`);
|
|
43
|
-
const base = revision(source.path, String(values.base ?? context.defaultBase));
|
|
44
|
-
const range = command === "diff"
|
|
45
|
-
? git(source.path, "merge-base", base, "HEAD")
|
|
46
|
-
: `${base}..HEAD`;
|
|
47
|
-
process.stdout.write(gitRaw(source.path, "--no-pager", command, "--no-ext-diff", "--no-textconv", ...(command === "log" ? ["--oneline"] : []), ...flags, range, "--", ...paths));
|
|
48
|
-
return 0;
|
|
49
|
-
}
|
|
50
|
-
if (trailing.length)
|
|
51
|
-
throw new Error("Extra arguments are only supported by diff and log");
|
|
52
19
|
return locked(path.join(context.store.root, GIT_WORKFLOW_DIRECTORY), GIT_WORKFLOW_LOCK, async () => {
|
|
53
|
-
if (command === "step") {
|
|
54
|
-
arity(rest, 1);
|
|
55
|
-
const [action] = rest;
|
|
56
|
-
if (!["commit", "rebase", "squash"].includes(action))
|
|
57
|
-
throw new Error("Usage: rl step commit|rebase|squash");
|
|
58
|
-
if (values.cleanup ||
|
|
59
|
-
values.squash ||
|
|
60
|
-
(values.all && action !== "commit"))
|
|
61
|
-
throw new Error("Invalid step options");
|
|
62
|
-
assertReady(source.path, action !== "commit", source.branch);
|
|
63
|
-
if (action === "commit") {
|
|
64
|
-
if (values.base)
|
|
65
|
-
throw new Error("commit does not accept --base");
|
|
66
|
-
const commitMessage = required(values, "message");
|
|
67
|
-
if (values["dry-run"]) {
|
|
68
|
-
const changes = git(source.path, "diff", "--name-only", ...(values.all ? ["HEAD"] : ["--cached"]));
|
|
69
|
-
if (!changes)
|
|
70
|
-
throw new Error("No changes to commit");
|
|
71
|
-
console.log(`Would commit ${values.all ? "tracked" : "staged"} changes in ${source.branch}: ${commitMessage}\n${changes}`);
|
|
72
|
-
return 0;
|
|
73
|
-
}
|
|
74
|
-
console.log(git(source.path, "commit", ...(values.all ? ["--all"] : []), "-m", required(values, "message")));
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
if (action === "rebase" && values.message)
|
|
78
|
-
throw new Error("rebase does not accept --message");
|
|
79
|
-
const base = revision(source.path, String(values.base ?? context.defaultBase));
|
|
80
|
-
if (action === "rebase") {
|
|
81
|
-
if (values["dry-run"]) {
|
|
82
|
-
console.log(`Would rebase ${source.branch} onto ${base}`);
|
|
83
|
-
return 0;
|
|
84
|
-
}
|
|
85
|
-
const result = await execute(["git", "-C", source.path, "rebase", base], source.path);
|
|
86
|
-
process.stdout.write(result.stdout);
|
|
87
|
-
if (result.code)
|
|
88
|
-
throw new Error(`${result.stderr.trim()}\nRebase did not complete. Resolve conflicts and run git rebase --continue, or git rebase --abort in ${source.path}`);
|
|
89
|
-
return 0;
|
|
90
|
-
}
|
|
91
|
-
const message = required(values, "message");
|
|
92
|
-
const head = revision(source.path, "HEAD");
|
|
93
|
-
const baseCommit = git(source.path, "merge-base", base, head);
|
|
94
|
-
if (baseCommit === head)
|
|
95
|
-
throw new Error("No feature commits to squash");
|
|
96
|
-
if (values["dry-run"]) {
|
|
97
|
-
console.log(`Would squash commits after ${baseCommit} in ${source.branch}: ${message}`);
|
|
98
|
-
return 0;
|
|
99
|
-
}
|
|
100
|
-
const tree = git(source.path, "rev-parse", `${head}^{tree}`);
|
|
101
|
-
const backup = BACKUP_PREFIX + randomUUID();
|
|
102
|
-
const squashed = git(source.path, "commit-tree", tree, "-p", baseCommit, "-m", message);
|
|
103
|
-
git(source.path, "update-ref", backup, head);
|
|
104
|
-
// CAS leaves concurrent branch changes untouched; the worktree and index never change.
|
|
105
|
-
git(source.path, "update-ref", "-m", "rl step squash", `refs/heads/${source.branch}`, squashed, head);
|
|
106
|
-
console.log(`Squashed feature commits. Original HEAD retained at ${backup}`);
|
|
107
|
-
return 0;
|
|
108
|
-
}
|
|
109
|
-
if (command !== "merge")
|
|
110
|
-
throw new Error("Unknown Git workflow command");
|
|
111
|
-
arity(rest, 0, 1);
|
|
112
|
-
if (values.all || values.base || (values.message && !values.squash))
|
|
113
|
-
throw new Error("Invalid merge options");
|
|
114
20
|
const selected = rest[0] ?? context.defaultBase.replace(/^origin\//, "");
|
|
115
21
|
const targetRecord = worktrees(context.repo).find((record) => record.branch === `refs/heads/${selected}`);
|
|
116
22
|
if (!targetRecord)
|