slopcannon 0.1.6 → 0.1.8
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 +17 -8
- package/dist/cli.js +64 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
<img src="images/hero.png" width="512" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
Create a git worktree. Launch Claude Code. Ship slop.
|
|
7
|
+
Create a git worktree. Launch Claude Code or Codex. Ship slop.
|
|
8
8
|
|
|
9
9
|
## What it does
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
git worktree add -b <branch> ../repo-branch origin/main
|
|
13
|
-
|
|
13
|
+
pick a launcher:
|
|
14
|
+
- claude --dangerously-skip-permissions
|
|
15
|
+
- codex --yolo
|
|
14
16
|
```
|
|
15
17
|
|
|
16
18
|
That's it. Run it in any git repo.
|
|
@@ -27,12 +29,19 @@ Add to `~/.zshrc` so your shell cds into the worktree:
|
|
|
27
29
|
|
|
28
30
|
```bash
|
|
29
31
|
slopcannon() {
|
|
30
|
-
local
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
local pathfile=$(mktemp /tmp/slopcannon.path.XXXXXX)
|
|
33
|
+
local launcherfile=$(mktemp /tmp/slopcannon.launcher.XXXXXX)
|
|
34
|
+
bunx slopcannon --path-file "$pathfile" --launcher-file "$launcherfile" "$@"
|
|
35
|
+
local p=$(cat "$pathfile" 2>/dev/null)
|
|
36
|
+
local launcher=$(cat "$launcherfile" 2>/dev/null)
|
|
37
|
+
rm -f "$pathfile" "$launcherfile"
|
|
34
38
|
if [[ -n "$p" ]] && [[ -d "$p" ]]; then
|
|
35
|
-
cd "$p"
|
|
39
|
+
cd "$p" || return
|
|
40
|
+
if [[ "$launcher" == "codex" ]]; then
|
|
41
|
+
codex --yolo
|
|
42
|
+
else
|
|
43
|
+
claude --dangerously-skip-permissions
|
|
44
|
+
fi
|
|
36
45
|
fi
|
|
37
46
|
}
|
|
38
47
|
```
|
|
@@ -41,4 +50,4 @@ slopcannon() {
|
|
|
41
50
|
|
|
42
51
|
- [bun](https://bun.sh)
|
|
43
52
|
- [git](https://git-scm.com)
|
|
44
|
-
- [claude CLI](https://docs.anthropic.com/en/docs/claude-code)
|
|
53
|
+
- [claude CLI](https://docs.anthropic.com/en/docs/claude-code) or `codex`
|
package/dist/cli.js
CHANGED
|
@@ -1735,7 +1735,7 @@ async function typewriterActivation() {
|
|
|
1735
1735
|
process.stdout.write(`
|
|
1736
1736
|
`);
|
|
1737
1737
|
}
|
|
1738
|
-
async function runTui() {
|
|
1738
|
+
async function runTui(deps) {
|
|
1739
1739
|
We("slopcannon");
|
|
1740
1740
|
let info;
|
|
1741
1741
|
try {
|
|
@@ -1763,6 +1763,25 @@ async function runTui() {
|
|
|
1763
1763
|
return null;
|
|
1764
1764
|
}
|
|
1765
1765
|
const baseBranch = baseBranchEntry;
|
|
1766
|
+
const launcherOptions = [
|
|
1767
|
+
deps.claude ? {
|
|
1768
|
+
value: "claude",
|
|
1769
|
+
label: "claude --dangerously-skip-permissions"
|
|
1770
|
+
} : null,
|
|
1771
|
+
deps.codex ? {
|
|
1772
|
+
value: "codex",
|
|
1773
|
+
label: "codex --yolo"
|
|
1774
|
+
} : null
|
|
1775
|
+
].filter((option) => Boolean(option));
|
|
1776
|
+
const launcher = await Je({
|
|
1777
|
+
message: "Launcher",
|
|
1778
|
+
options: launcherOptions,
|
|
1779
|
+
initialValue: deps.claude ? "claude" : "codex"
|
|
1780
|
+
});
|
|
1781
|
+
if (Ct(launcher)) {
|
|
1782
|
+
Le("Cancelled.");
|
|
1783
|
+
return null;
|
|
1784
|
+
}
|
|
1766
1785
|
const defaultName = randomBranchName();
|
|
1767
1786
|
const newBranch = await Ze({
|
|
1768
1787
|
message: "New branch name",
|
|
@@ -1799,10 +1818,24 @@ async function runTui() {
|
|
|
1799
1818
|
return null;
|
|
1800
1819
|
}
|
|
1801
1820
|
try {
|
|
1802
|
-
|
|
1821
|
+
let walkForEnv = function(dir) {
|
|
1822
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
1823
|
+
if (entry.isDirectory()) {
|
|
1824
|
+
if (!SKIP_DIRS.has(entry.name))
|
|
1825
|
+
walkForEnv(path3.join(dir, entry.name));
|
|
1826
|
+
} else if (entry.name.startsWith(".env")) {
|
|
1827
|
+
envFiles.push(path3.relative(info.root, path3.join(dir, entry.name)));
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
const SKIP_DIRS = new Set(["node_modules", ".git", ".claude"]);
|
|
1832
|
+
const envFiles = [];
|
|
1833
|
+
walkForEnv(info.root);
|
|
1803
1834
|
if (envFiles.length > 0) {
|
|
1804
|
-
for (const
|
|
1805
|
-
|
|
1835
|
+
for (const rel of envFiles) {
|
|
1836
|
+
const destDir = path3.join(worktreePath, path3.dirname(rel));
|
|
1837
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
1838
|
+
fs.copyFileSync(path3.join(info.root, rel), path3.join(worktreePath, rel));
|
|
1806
1839
|
}
|
|
1807
1840
|
R2.info(`Copied ${envFiles.join(", ")}`);
|
|
1808
1841
|
}
|
|
@@ -1813,7 +1846,10 @@ async function runTui() {
|
|
|
1813
1846
|
else if (style === "typewriter")
|
|
1814
1847
|
await typewriterActivation();
|
|
1815
1848
|
Le(worktreePath);
|
|
1816
|
-
return
|
|
1849
|
+
return {
|
|
1850
|
+
worktreePath,
|
|
1851
|
+
launcher
|
|
1852
|
+
};
|
|
1817
1853
|
}
|
|
1818
1854
|
|
|
1819
1855
|
// src/cleanup.ts
|
|
@@ -1951,18 +1987,19 @@ Then run: bunx slopcannon`);
|
|
|
1951
1987
|
process.exit(1);
|
|
1952
1988
|
}
|
|
1953
1989
|
var HELP = `
|
|
1954
|
-
slopcannon - Create a git worktree. Launch Claude Code. Ship slop.
|
|
1990
|
+
slopcannon - Create a git worktree. Launch Claude Code or Codex. Ship slop.
|
|
1955
1991
|
|
|
1956
1992
|
Usage:
|
|
1957
1993
|
slopcannon Interactive TUI
|
|
1958
1994
|
slopcannon cleanup|clean Clean up merged/stale worktrees
|
|
1959
1995
|
slopcannon config Configure settings
|
|
1960
1996
|
slopcannon --path-file <path> Write worktree path to file (for shell function)
|
|
1997
|
+
slopcannon --launcher-file <path> Write selected launcher to file
|
|
1961
1998
|
slopcannon --help Show this help
|
|
1962
1999
|
|
|
1963
2000
|
What it does:
|
|
1964
2001
|
git worktree add -b <branch> ../repo-branch origin/main
|
|
1965
|
-
|
|
2002
|
+
then launches your selected CLI
|
|
1966
2003
|
`.trim();
|
|
1967
2004
|
function parseArgs() {
|
|
1968
2005
|
const args = process.argv.slice(2);
|
|
@@ -1974,6 +2011,8 @@ function parseArgs() {
|
|
|
1974
2011
|
result.version = true;
|
|
1975
2012
|
} else if (args[i] === "--path-file" && i + 1 < args.length) {
|
|
1976
2013
|
result.pathFile = args[++i];
|
|
2014
|
+
} else if (args[i] === "--launcher-file" && i + 1 < args.length) {
|
|
2015
|
+
result.launcherFile = args[++i];
|
|
1977
2016
|
} else if (args[i] === "config") {
|
|
1978
2017
|
result.config = true;
|
|
1979
2018
|
} else if (args[i] === "cleanup" || args[i] === "clean") {
|
|
@@ -1990,6 +2029,7 @@ function checkDeps() {
|
|
|
1990
2029
|
return {
|
|
1991
2030
|
git: Bun.which("git"),
|
|
1992
2031
|
claude: Bun.which("claude"),
|
|
2032
|
+
codex: Bun.which("codex"),
|
|
1993
2033
|
gh: Bun.which("gh"),
|
|
1994
2034
|
bun: Bun.which("bun")
|
|
1995
2035
|
};
|
|
@@ -2022,23 +2062,34 @@ async function main() {
|
|
|
2022
2062
|
process.exit(0);
|
|
2023
2063
|
}
|
|
2024
2064
|
requireGit(deps);
|
|
2025
|
-
if (!deps.claude) {
|
|
2026
|
-
console.error(`Error: claude CLI is
|
|
2027
|
-
Install
|
|
2065
|
+
if (!deps.claude && !deps.codex) {
|
|
2066
|
+
console.error(`Error: neither claude nor codex CLI is installed.
|
|
2067
|
+
Install one of them before running slopcannon.`);
|
|
2028
2068
|
process.exit(1);
|
|
2029
2069
|
}
|
|
2030
2070
|
if (!deps.gh) {
|
|
2031
2071
|
console.warn("Warning: gh CLI not found. Remote detection may be limited.");
|
|
2032
2072
|
}
|
|
2033
|
-
const
|
|
2034
|
-
|
|
2073
|
+
const tuiResult = await runTui({
|
|
2074
|
+
claude: deps.claude,
|
|
2075
|
+
codex: deps.codex
|
|
2076
|
+
});
|
|
2077
|
+
if (!tuiResult) {
|
|
2035
2078
|
process.exit(0);
|
|
2036
2079
|
}
|
|
2080
|
+
const { worktreePath, launcher } = tuiResult;
|
|
2037
2081
|
if (args.pathFile) {
|
|
2038
2082
|
await Bun.write(args.pathFile, worktreePath);
|
|
2083
|
+
}
|
|
2084
|
+
if (args.launcherFile) {
|
|
2085
|
+
await Bun.write(args.launcherFile, launcher + `
|
|
2086
|
+
`);
|
|
2087
|
+
}
|
|
2088
|
+
if (args.pathFile || args.launcherFile) {
|
|
2039
2089
|
process.exit(0);
|
|
2040
2090
|
}
|
|
2041
|
-
const
|
|
2091
|
+
const launchCommand = launcher === "codex" ? ["codex", "--yolo"] : ["claude", "--dangerously-skip-permissions"];
|
|
2092
|
+
const proc = Bun.spawn(launchCommand, {
|
|
2042
2093
|
cwd: worktreePath,
|
|
2043
2094
|
stdin: "inherit",
|
|
2044
2095
|
stdout: "inherit",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopcannon",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Create a git worktree. Launch Claude Code. Ship slop.",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Create a git worktree. Launch Claude Code or Codex. Ship slop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"slopcannon": "dist/cli.js"
|