@sven1103/opencode-worktree-workflow 0.6.0 → 0.6.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/package.json +1 -1
- package/src/cli.js +44 -1
- package/src/index.js +33 -3
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { promisify } from "node:util";
|
|
6
7
|
|
|
@@ -68,6 +69,31 @@ function printUsage() {
|
|
|
68
69
|
);
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
function printSubcommandUsage(command) {
|
|
73
|
+
if (command === "wt-new") {
|
|
74
|
+
process.stdout.write(
|
|
75
|
+
[
|
|
76
|
+
"Usage:",
|
|
77
|
+
" opencode-worktree-workflow wt-new <title> [--json]",
|
|
78
|
+
"",
|
|
79
|
+
"Create a synced worktree and branch from the configured base branch.",
|
|
80
|
+
].join("\n") + "\n",
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (command === "wt-clean") {
|
|
86
|
+
process.stdout.write(
|
|
87
|
+
[
|
|
88
|
+
"Usage:",
|
|
89
|
+
" opencode-worktree-workflow wt-clean [preview|apply] [selectors...] [--json]",
|
|
90
|
+
"",
|
|
91
|
+
"Preview connected worktrees or remove safe and explicitly selected review worktrees.",
|
|
92
|
+
].join("\n") + "\n",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
71
97
|
export function parseCliArgs(argv) {
|
|
72
98
|
const outputJson = argv.includes("--json");
|
|
73
99
|
const args = argv.filter((arg) => arg !== "--json");
|
|
@@ -84,6 +110,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
84
110
|
return;
|
|
85
111
|
}
|
|
86
112
|
|
|
113
|
+
if ((command === "wt-new" || command === "wt-clean") && rest.some((arg) => arg === "--help" || arg === "-h" || arg === "help")) {
|
|
114
|
+
printSubcommandUsage(command);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
87
118
|
const plugin = await WorktreeWorkflowPlugin({
|
|
88
119
|
$: createShell(process.cwd()),
|
|
89
120
|
directory: process.cwd(),
|
|
@@ -120,7 +151,19 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
120
151
|
process.stdout.write(`${result.message || JSON.stringify(result, null, 2)}\n`);
|
|
121
152
|
}
|
|
122
153
|
|
|
123
|
-
|
|
154
|
+
export function isInvokedAsScript(argvPath = process.argv[1]) {
|
|
155
|
+
if (!argvPath) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
return fs.realpathSync(argvPath) === fileURLToPath(import.meta.url);
|
|
161
|
+
} catch {
|
|
162
|
+
return fileURLToPath(import.meta.url) === argvPath;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const invokedAsScript = isInvokedAsScript();
|
|
124
167
|
|
|
125
168
|
if (invokedAsScript) {
|
|
126
169
|
run().catch((error) => {
|
package/src/index.js
CHANGED
|
@@ -24,6 +24,14 @@ async function pathExists(targetPath) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function isMissingGitRepositoryError(message) {
|
|
28
|
+
return /not a git repository/i.test(message);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isMissingRemoteError(message, remote) {
|
|
32
|
+
return new RegExp(`No such remote:?\s+${remote}|does not appear to be a git repository|Could not read from remote repository`, "i").test(message);
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
async function readJsonFile(filePath) {
|
|
28
36
|
if (!(await pathExists(filePath))) {
|
|
29
37
|
return null;
|
|
@@ -376,6 +384,8 @@ export const __internal = {
|
|
|
376
384
|
buildCleanupPreviewResult,
|
|
377
385
|
buildPrepareResult,
|
|
378
386
|
classifyEntry,
|
|
387
|
+
isMissingGitRepositoryError,
|
|
388
|
+
isMissingRemoteError,
|
|
379
389
|
parseCleanupRawArguments,
|
|
380
390
|
normalizeCleanupArgs,
|
|
381
391
|
toStructuredCleanupFailure,
|
|
@@ -470,8 +480,18 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
470
480
|
}
|
|
471
481
|
|
|
472
482
|
async function getRepoRoot() {
|
|
473
|
-
|
|
474
|
-
|
|
483
|
+
try {
|
|
484
|
+
const result = await git(["rev-parse", "--show-toplevel"]);
|
|
485
|
+
return result.stdout;
|
|
486
|
+
} catch (error) {
|
|
487
|
+
if (isMissingGitRepositoryError(error.message || "")) {
|
|
488
|
+
throw new Error(
|
|
489
|
+
"This command must run inside a git repository. Initialize a repository first or run it from an existing repo root.",
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
throw error;
|
|
494
|
+
}
|
|
475
495
|
}
|
|
476
496
|
|
|
477
497
|
async function loadWorkflowConfig(repoRoot) {
|
|
@@ -557,7 +577,17 @@ export const WorktreeWorkflowPlugin = async ({ $, directory }) => {
|
|
|
557
577
|
}
|
|
558
578
|
|
|
559
579
|
async function getBaseRef(repoRoot, remote, baseBranch) {
|
|
560
|
-
|
|
580
|
+
try {
|
|
581
|
+
await git(["fetch", "--prune", remote, baseBranch], { cwd: repoRoot });
|
|
582
|
+
} catch (error) {
|
|
583
|
+
if (isMissingRemoteError(error.message || "", remote)) {
|
|
584
|
+
throw new Error(
|
|
585
|
+
`Could not fetch base branch information from remote \"${remote}\". Configure the expected remote in .opencode/worktree-workflow.json or add that remote to this repository.`,
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
throw error;
|
|
590
|
+
}
|
|
561
591
|
|
|
562
592
|
const remoteRef = `refs/remotes/${remote}/${baseBranch}`;
|
|
563
593
|
const remoteExists = await git(["show-ref", "--verify", "--quiet", remoteRef], {
|