arashi 1.1.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/LICENSE +21 -0
- package/README.md +351 -0
- package/bin/arashi +42 -0
- package/bin/arashi.bat +22 -0
- package/bin/arashi.ps1 +21 -0
- package/package.json +75 -0
- package/scripts/postinstall.js +148 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arashi Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Arashi
|
|
2
|
+
|
|
3
|
+
> 嵐 - The eye of the storm for your development workflow
|
|
4
|
+
|
|
5
|
+
Arashi is a Git worktree manager for meta-repositories that automatically manages worktrees across multiple related repositories. When working on features that span multiple repositories, Arashi simplifies the workflow by ensuring all related repositories maintain synchronized worktrees.
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
📋 **For complete design documents, specifications, and planning, see the [Arashi Specifications Repository](https://github.com/corwinm/arashi-arashi).**
|
|
10
|
+
|
|
11
|
+
## Status
|
|
12
|
+
|
|
13
|
+
🚧 **Under Active Development** - Phase 1 Complete
|
|
14
|
+
|
|
15
|
+
This project is currently in early development. See the [Design Document](https://github.com/corwinm/arashi-arashi/tree/main/setup/.specify/memory/design.md) in the specs repository for the complete feature roadmap and implementation plan.
|
|
16
|
+
|
|
17
|
+
## Installation (Coming Soon)
|
|
18
|
+
|
|
19
|
+
### npm (Recommended)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g arashi
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The npm package includes everything you need for full fzf compatibility.
|
|
26
|
+
|
|
27
|
+
### Direct Binary Download
|
|
28
|
+
|
|
29
|
+
Download and extract the latest release for your platform from [GitHub Releases](https://github.com/corwinm/arashi/releases):
|
|
30
|
+
|
|
31
|
+
**macOS (Apple Silicon)**
|
|
32
|
+
```bash
|
|
33
|
+
curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi-macos-arm64.tar.gz -o arashi.tar.gz
|
|
34
|
+
tar xzf arashi.tar.gz
|
|
35
|
+
cd arashi-macos-arm64
|
|
36
|
+
sudo cp arashi arashi.bin /usr/local/bin/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Linux (x64)**
|
|
40
|
+
```bash
|
|
41
|
+
curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi-linux-x64.tar.gz -o arashi.tar.gz
|
|
42
|
+
tar xzf arashi.tar.gz
|
|
43
|
+
cd arashi-linux-x64
|
|
44
|
+
sudo cp arashi arashi.bin /usr/local/bin/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Windows (x64)**
|
|
48
|
+
- Windows support coming soon (wrapper script needs PowerShell equivalent)
|
|
49
|
+
|
|
50
|
+
## Vision
|
|
51
|
+
|
|
52
|
+
Arashi will enable developers to:
|
|
53
|
+
- Create coordinated worktrees across multiple repositories with a single command
|
|
54
|
+
- Automatically manage branch synchronization across related repos
|
|
55
|
+
- Simplify setup and teardown of development environments
|
|
56
|
+
- Maintain clean git state across meta-repository structures
|
|
57
|
+
|
|
58
|
+
## Quick Start (Coming Soon)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Initialize arashi in your meta-repository
|
|
62
|
+
arashi init
|
|
63
|
+
|
|
64
|
+
# Add repositories to manage
|
|
65
|
+
arashi add git@github.com:user/frontend.git
|
|
66
|
+
arashi add git@github.com:user/backend.git
|
|
67
|
+
|
|
68
|
+
# Create a new feature worktree across all repos
|
|
69
|
+
arashi create feature-new-api
|
|
70
|
+
|
|
71
|
+
# Check status across all repos
|
|
72
|
+
arashi status
|
|
73
|
+
|
|
74
|
+
# Remove worktree when done
|
|
75
|
+
arashi remove feature-new-api
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Planned Commands
|
|
79
|
+
|
|
80
|
+
- `arashi init` - Initialize arashi in current repository
|
|
81
|
+
- `arashi add <git-url>` - Add a repository to the repos folder
|
|
82
|
+
- `arashi create <branch>` - Create coordinated worktrees
|
|
83
|
+
- `arashi list` - List all worktrees
|
|
84
|
+
- `arashi remove <branch>` - Remove worktrees and branches
|
|
85
|
+
- `arashi setup` - Run setup scripts
|
|
86
|
+
- `arashi status` - Show status of all repositories
|
|
87
|
+
|
|
88
|
+
## Integration with fzf, tmux, and sesh
|
|
89
|
+
|
|
90
|
+
The `arashi list` command outputs clean, full paths perfect for piping to tools like fzf. Here are powerful workflow integrations:
|
|
91
|
+
|
|
92
|
+
### Basic: Change Directory with fzf
|
|
93
|
+
|
|
94
|
+
Navigate to any worktree interactively:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Interactive worktree selection
|
|
98
|
+
cd $(arashi list | fzf)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Add as a shell keybinding** for instant access:
|
|
102
|
+
|
|
103
|
+
#### Bash/Zsh
|
|
104
|
+
|
|
105
|
+
Add to your `~/.bashrc` or `~/.zshrc`:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Ctrl+G to select and navigate to worktree
|
|
109
|
+
bind '"\C-g":"cd \$(arashi list | fzf)\n"' # Bash
|
|
110
|
+
bindkey -s '^g' 'cd $(arashi list | fzf)\n' # Zsh
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Press `Ctrl+G` from anywhere to fuzzy-find and jump to a worktree.
|
|
114
|
+
|
|
115
|
+
#### Fish
|
|
116
|
+
|
|
117
|
+
Add to your `~/.config/fish/config.fish`:
|
|
118
|
+
|
|
119
|
+
```fish
|
|
120
|
+
# Ctrl+G to select and navigate to worktree
|
|
121
|
+
function __arashi_worktree_jump
|
|
122
|
+
set -l worktree (arashi list | fzf)
|
|
123
|
+
and cd $worktree
|
|
124
|
+
commandline -f repaint
|
|
125
|
+
end
|
|
126
|
+
bind \cg __arashi_worktree_jump
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Advanced: tmux Session Management
|
|
130
|
+
|
|
131
|
+
Create or switch to a tmux session for a worktree:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Function to create/attach tmux session for worktree
|
|
135
|
+
arashi-tmux() {
|
|
136
|
+
local worktree=$(arashi list | fzf)
|
|
137
|
+
if [ -n "$worktree" ]; then
|
|
138
|
+
# Create session name from last path component
|
|
139
|
+
local session_name=$(basename "$worktree")
|
|
140
|
+
|
|
141
|
+
# Create session if it doesn't exist
|
|
142
|
+
if ! tmux has-session -t "$session_name" 2>/dev/null; then
|
|
143
|
+
tmux new-session -d -s "$session_name" -c "$worktree"
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
# Switch to or attach session
|
|
147
|
+
if [ -n "$TMUX" ]; then
|
|
148
|
+
tmux switch-client -t "$session_name"
|
|
149
|
+
else
|
|
150
|
+
tmux attach-session -t "$session_name"
|
|
151
|
+
fi
|
|
152
|
+
fi
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Bind to Ctrl+G
|
|
156
|
+
bind '"\C-g":"arashi-tmux\n"' # Bash
|
|
157
|
+
bindkey -s '^g' 'arashi-tmux\n' # Zsh
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**What this does:**
|
|
161
|
+
1. Fuzzy-find a worktree with fzf
|
|
162
|
+
2. Create a named tmux session for that worktree (if needed)
|
|
163
|
+
3. Switch to the session, preserving your current context
|
|
164
|
+
|
|
165
|
+
### Simplified: Using sesh
|
|
166
|
+
|
|
167
|
+
[sesh](https://github.com/joshmedeski/sesh) is a smart session manager for tmux. Integrate arashi with sesh for the ultimate workflow:
|
|
168
|
+
|
|
169
|
+
#### Setup
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Install sesh
|
|
173
|
+
brew install joshmedeski/sesh/sesh
|
|
174
|
+
|
|
175
|
+
# Add arashi as a sesh source
|
|
176
|
+
# ~/.config/sesh/sesh.toml
|
|
177
|
+
[sources]
|
|
178
|
+
arashi = "arashi list"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### Usage
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Select from all sessions + arashi worktrees
|
|
185
|
+
sesh connect $(sesh list | fzf)
|
|
186
|
+
|
|
187
|
+
# Or create a keybinding (Ctrl+A)
|
|
188
|
+
bind '"\C-a":"sesh connect \$(sesh list | fzf)\n"'
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Benefits of sesh:**
|
|
192
|
+
- Unified list of existing tmux sessions + arashi worktrees
|
|
193
|
+
- Smart session naming and path handling
|
|
194
|
+
- Automatic tmux session creation
|
|
195
|
+
- Works seamlessly with zoxide and other tools
|
|
196
|
+
|
|
197
|
+
### Fish + tmux Integration
|
|
198
|
+
|
|
199
|
+
For Fish shell users, here's a complete solution:
|
|
200
|
+
|
|
201
|
+
```fish
|
|
202
|
+
# ~/.config/fish/functions/arashi_session.fish
|
|
203
|
+
function arashi_session
|
|
204
|
+
set -l worktree (arashi list | fzf \
|
|
205
|
+
--preview 'cd {} && git status' \
|
|
206
|
+
--preview-window=right:60% \
|
|
207
|
+
--height=80%)
|
|
208
|
+
|
|
209
|
+
if test -n "$worktree"
|
|
210
|
+
set -l session_name (basename $worktree)
|
|
211
|
+
|
|
212
|
+
if not tmux has-session -t $session_name 2>/dev/null
|
|
213
|
+
tmux new-session -d -s $session_name -c $worktree
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if set -q TMUX
|
|
217
|
+
tmux switch-client -t $session_name
|
|
218
|
+
else
|
|
219
|
+
tmux attach-session -t $session_name
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Bind to Ctrl+G
|
|
225
|
+
bind \cg arashi_session
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
This includes:
|
|
229
|
+
- Live git status preview in fzf
|
|
230
|
+
- Automatic session creation with smart naming
|
|
231
|
+
- Works both inside and outside tmux
|
|
232
|
+
|
|
233
|
+
### Comparison Table
|
|
234
|
+
|
|
235
|
+
| Method | Setup Complexity | Features | Best For |
|
|
236
|
+
|--------|-----------------|----------|----------|
|
|
237
|
+
| **Basic fzf** | Low | Quick navigation | Simple cd workflows |
|
|
238
|
+
| **tmux function** | Medium | Session management | Multi-project work |
|
|
239
|
+
| **sesh** | Low-Medium | Unified session list | Power users with multiple sources |
|
|
240
|
+
|
|
241
|
+
### Tips
|
|
242
|
+
|
|
243
|
+
- **Preview window:** Add `--preview 'cd {} && git status'` to fzf for live status
|
|
244
|
+
- **Layout:** Try `--preview-window=right:60%` for side-by-side preview
|
|
245
|
+
- **Height:** Use `--height=80%` to avoid fullscreen fzf
|
|
246
|
+
- **Multi-select:** Add `--multi` to fzf for batch operations
|
|
247
|
+
|
|
248
|
+
### Example Workflow
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Morning routine:
|
|
252
|
+
1. Press Ctrl+G
|
|
253
|
+
2. Type "feature" to filter worktrees
|
|
254
|
+
3. Select your feature branch worktree
|
|
255
|
+
4. tmux session is created/attached
|
|
256
|
+
5. Start coding immediately!
|
|
257
|
+
|
|
258
|
+
# No more:
|
|
259
|
+
cd ~/projects/repo
|
|
260
|
+
cd ../feature-worktree
|
|
261
|
+
tmux new -s feature-branch
|
|
262
|
+
cd ~/projects/repo/feature-worktree
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Development
|
|
266
|
+
|
|
267
|
+
### Prerequisites
|
|
268
|
+
|
|
269
|
+
- [Bun](https://bun.sh/) >= 1.3.0 (for development)
|
|
270
|
+
- Node.js >= 18.0.0 (for npm installation)
|
|
271
|
+
|
|
272
|
+
### Setup
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Clone the repository
|
|
276
|
+
git clone https://github.com/corwinm/arashi.git
|
|
277
|
+
cd arashi
|
|
278
|
+
|
|
279
|
+
# Install dependencies
|
|
280
|
+
bun install
|
|
281
|
+
|
|
282
|
+
# Run in development mode
|
|
283
|
+
bun run dev
|
|
284
|
+
|
|
285
|
+
# Build single-file executable
|
|
286
|
+
bun run build
|
|
287
|
+
|
|
288
|
+
# Build for all platforms
|
|
289
|
+
bun run build:all
|
|
290
|
+
|
|
291
|
+
# Run tests (coming soon)
|
|
292
|
+
bun test
|
|
293
|
+
|
|
294
|
+
# Type check
|
|
295
|
+
bun run lint
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Contributing
|
|
299
|
+
|
|
300
|
+
We welcome contributions! Please see our [Specifications Repository](https://github.com/corwinm/arashi-arashi) for:
|
|
301
|
+
- [Design Document](https://github.com/corwinm/arashi-arashi/tree/main/setup/.specify/memory/design.md) - Feature roadmap and technical design
|
|
302
|
+
- [Contributing Guide](https://github.com/corwinm/arashi-arashi/blob/main/setup/CONTRIBUTING.md) - Specs-first development workflow
|
|
303
|
+
|
|
304
|
+
**Quick Summary:**
|
|
305
|
+
1. Specs are created in the [arashi-arashi repository](https://github.com/corwinm/arashi-arashi) first
|
|
306
|
+
2. Implementation happens in this repository
|
|
307
|
+
3. Use conventional commits
|
|
308
|
+
4. All PRs require review
|
|
309
|
+
5. Squash merge with conventional commit message
|
|
310
|
+
|
|
311
|
+
**Commit Message Format:**
|
|
312
|
+
We use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
313
|
+
```
|
|
314
|
+
feat: add interactive mode for repo selection
|
|
315
|
+
fix: handle worktrees with uncommitted changes
|
|
316
|
+
docs: update installation instructions
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Architecture
|
|
320
|
+
|
|
321
|
+
Arashi is built with:
|
|
322
|
+
- **Runtime:** Bun (single-file executable)
|
|
323
|
+
- **Language:** TypeScript
|
|
324
|
+
- **CLI Framework:** Commander.js
|
|
325
|
+
- **User Prompts:** @inquirer/prompts
|
|
326
|
+
|
|
327
|
+
## Roadmap
|
|
328
|
+
|
|
329
|
+
See the [Design Document](https://github.com/corwinm/arashi-arashi/tree/main/setup/.specify/memory/design.md) in the specs repository for the complete feature roadmap organized by implementation phases.
|
|
330
|
+
|
|
331
|
+
### Current Phase: Foundation (Phase 1)
|
|
332
|
+
- [x] Project setup and structure
|
|
333
|
+
- [x] Type definitions
|
|
334
|
+
- [ ] Utility libraries (git, config, filesystem, logger, prompts)
|
|
335
|
+
|
|
336
|
+
### Next Phase: Core Commands (Phase 2)
|
|
337
|
+
- [ ] `init` command
|
|
338
|
+
- [ ] `add` command
|
|
339
|
+
- [ ] `create` command
|
|
340
|
+
|
|
341
|
+
## Why "Arashi"?
|
|
342
|
+
|
|
343
|
+
嵐 (Arashi) means "storm" in Japanese. This tool aims to be the calm center - the eye of the storm - that brings order to the chaos of managing multiple repositories and worktrees.
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
**Note:** This project is under active development. Features and APIs may change.
|
package/bin/arashi
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Wrapper for arashi to fix fzf compatibility
|
|
3
|
+
# Bun's compiled executables don't properly close stdin, which blocks fzf
|
|
4
|
+
# from accessing /dev/tty for keyboard input. This wrapper closes stdin (0<&-)
|
|
5
|
+
# before executing the binary.
|
|
6
|
+
|
|
7
|
+
# Resolve the actual script path, following symlinks
|
|
8
|
+
SCRIPT_SOURCE="${BASH_SOURCE[0]}"
|
|
9
|
+
while [ -L "$SCRIPT_SOURCE" ]; do
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_SOURCE")" && pwd)"
|
|
11
|
+
SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
|
|
12
|
+
[[ "$SCRIPT_SOURCE" != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
|
|
13
|
+
done
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_SOURCE")" && pwd)"
|
|
15
|
+
BINARY="$SCRIPT_DIR/arashi.bin"
|
|
16
|
+
|
|
17
|
+
# Use platform-specific binary if main binary doesn't exist
|
|
18
|
+
if [ ! -f "$BINARY" ]; then
|
|
19
|
+
PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
20
|
+
ARCH=$(uname -m)
|
|
21
|
+
|
|
22
|
+
case "$PLATFORM-$ARCH" in
|
|
23
|
+
darwin-arm64)
|
|
24
|
+
BINARY="$SCRIPT_DIR/arashi-macos-arm64"
|
|
25
|
+
;;
|
|
26
|
+
linux-x86_64)
|
|
27
|
+
BINARY="$SCRIPT_DIR/arashi-linux-x64"
|
|
28
|
+
;;
|
|
29
|
+
*)
|
|
30
|
+
echo "Error: Unsupported platform $PLATFORM-$ARCH" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
;;
|
|
33
|
+
esac
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
if [ ! -f "$BINARY" ]; then
|
|
37
|
+
echo "Error: arashi binary not found at $BINARY" >&2
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Execute with stdin closed (0<&-) for fzf compatibility
|
|
42
|
+
exec "$BINARY" "$@" 0<&-
|
package/bin/arashi.bat
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM Wrapper for arashi.exe to support piping to tools like fzf on Windows
|
|
3
|
+
REM This closes stdin before executing the binary
|
|
4
|
+
|
|
5
|
+
REM Get the directory where this script is located
|
|
6
|
+
set "SCRIPT_DIR=%~dp0"
|
|
7
|
+
set "BINARY=%SCRIPT_DIR%arashi.bin.exe"
|
|
8
|
+
|
|
9
|
+
REM Use platform-specific binary if main binary doesn't exist
|
|
10
|
+
if not exist "%BINARY%" (
|
|
11
|
+
set "BINARY=%SCRIPT_DIR%arashi-windows-x64.exe"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
REM Check if binary exists
|
|
15
|
+
if not exist "%BINARY%" (
|
|
16
|
+
echo Error: arashi binary not found at %BINARY% 1>&2
|
|
17
|
+
exit /b 1
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
REM Execute the binary with stdin closed
|
|
21
|
+
REM In Windows, we use <NUL to close/redirect stdin
|
|
22
|
+
"%BINARY%" %* <NUL
|
package/bin/arashi.ps1
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# PowerShell wrapper for arashi.exe to support piping to tools like fzf
|
|
2
|
+
# This closes stdin before executing the binary
|
|
3
|
+
|
|
4
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
5
|
+
$Binary = Join-Path $ScriptDir "arashi.bin.exe"
|
|
6
|
+
|
|
7
|
+
# Use platform-specific binary if main binary doesn't exist
|
|
8
|
+
if (-not (Test-Path $Binary)) {
|
|
9
|
+
$Binary = Join-Path $ScriptDir "arashi-windows-x64.exe"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# Check if binary exists
|
|
13
|
+
if (-not (Test-Path $Binary)) {
|
|
14
|
+
Write-Error "Error: arashi binary not found at $Binary"
|
|
15
|
+
exit 1
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# PowerShell way to close stdin and execute
|
|
19
|
+
# We redirect stdin from $null which effectively closes it
|
|
20
|
+
$process = Start-Process -FilePath $Binary -ArgumentList $args -NoNewWindow -Wait -PassThru -RedirectStandardInput $null
|
|
21
|
+
exit $process.ExitCode
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "arashi",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Git worktree manager for meta-repositories - The eye of the storm for your development workflow",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"arashi": "./bin/arashi"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/arashi",
|
|
11
|
+
"bin/arashi.bat",
|
|
12
|
+
"bin/arashi.ps1",
|
|
13
|
+
"scripts/postinstall.js",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"os": [
|
|
18
|
+
"darwin",
|
|
19
|
+
"linux",
|
|
20
|
+
"win32"
|
|
21
|
+
],
|
|
22
|
+
"cpu": [
|
|
23
|
+
"x64",
|
|
24
|
+
"arm64"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.0.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"dev": "bun run src/index.ts",
|
|
31
|
+
"build": "bun build src/index.ts --compile --minify --sourcemap --outfile bin/arashi.bin",
|
|
32
|
+
"build:all": "bun run build:mac && bun run build:linux && bun run build:windows",
|
|
33
|
+
"build:mac": "bun build src/index.ts --compile --target=bun-darwin-arm64 --outfile bin/arashi-macos-arm64",
|
|
34
|
+
"build:linux": "bun build src/index.ts --compile --target=bun-linux-x64 --outfile bin/arashi-linux-x64",
|
|
35
|
+
"build:windows": "bun build src/index.ts --compile --target=bun-windows-x64 --outfile bin/arashi-windows-x64.exe",
|
|
36
|
+
"test": "bun test",
|
|
37
|
+
"lint": "tsc --noEmit",
|
|
38
|
+
"postinstall": "node scripts/postinstall.js"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/corwinm/arashi.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/corwinm/arashi/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/corwinm/arashi#readme",
|
|
48
|
+
"keywords": [
|
|
49
|
+
"git",
|
|
50
|
+
"worktree",
|
|
51
|
+
"meta-repo",
|
|
52
|
+
"monorepo",
|
|
53
|
+
"cli",
|
|
54
|
+
"development",
|
|
55
|
+
"git-worktree",
|
|
56
|
+
"multi-repo",
|
|
57
|
+
"development-tools"
|
|
58
|
+
],
|
|
59
|
+
"author": "",
|
|
60
|
+
"license": "MIT",
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@inquirer/prompts": "^7.2.0",
|
|
63
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
64
|
+
"@semantic-release/git": "^10.0.1",
|
|
65
|
+
"@types/bun": "latest",
|
|
66
|
+
"bun-types": "latest",
|
|
67
|
+
"chalk": "^5.3.0",
|
|
68
|
+
"commander": "^12.1.0",
|
|
69
|
+
"conventional-changelog-conventionalcommits": "^8.0.0",
|
|
70
|
+
"js-yaml": "^4.1.1",
|
|
71
|
+
"ora": "^8.1.1",
|
|
72
|
+
"semantic-release": "^24.2.0",
|
|
73
|
+
"typescript": "^5.9.3"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-install script to download the platform-specific arashi binary from GitHub releases
|
|
5
|
+
* This keeps the npm package size small while providing pre-compiled binaries
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createWriteStream, chmodSync } from "node:fs";
|
|
9
|
+
import { mkdir, access, constants } from "node:fs/promises";
|
|
10
|
+
import { get } from "node:https";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = dirname(__filename);
|
|
16
|
+
|
|
17
|
+
const PACKAGE_NAME = "arashi";
|
|
18
|
+
const GITHUB_REPO = "corwinm/arashi";
|
|
19
|
+
|
|
20
|
+
// Determine platform and binary name
|
|
21
|
+
function getPlatformInfo() {
|
|
22
|
+
const platform = process.platform;
|
|
23
|
+
const arch = process.arch;
|
|
24
|
+
|
|
25
|
+
let binaryName;
|
|
26
|
+
if (platform === "darwin" && arch === "arm64") {
|
|
27
|
+
binaryName = `${PACKAGE_NAME}-macos-arm64`;
|
|
28
|
+
} else if (platform === "linux" && arch === "x64") {
|
|
29
|
+
binaryName = `${PACKAGE_NAME}-linux-x64`;
|
|
30
|
+
} else if (platform === "win32" && arch === "x64") {
|
|
31
|
+
binaryName = `${PACKAGE_NAME}-windows-x64.exe`;
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Unsupported platform: ${platform}-${arch}. Please build from source or file an issue at https://github.com/${GITHUB_REPO}/issues`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { binaryName, isWindows: platform === "win32" };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Download file from URL
|
|
42
|
+
function downloadFile(url, dest) {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
console.log(`Downloading ${url}...`);
|
|
45
|
+
|
|
46
|
+
const file = createWriteStream(dest);
|
|
47
|
+
const request = get(url, (response) => {
|
|
48
|
+
// Handle redirects
|
|
49
|
+
if (
|
|
50
|
+
response.statusCode === 301 ||
|
|
51
|
+
response.statusCode === 302 ||
|
|
52
|
+
response.statusCode === 307
|
|
53
|
+
) {
|
|
54
|
+
file.close();
|
|
55
|
+
downloadFile(response.headers.location, dest)
|
|
56
|
+
.then(resolve)
|
|
57
|
+
.catch(reject);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (response.statusCode !== 200) {
|
|
62
|
+
file.close();
|
|
63
|
+
reject(
|
|
64
|
+
new Error(
|
|
65
|
+
`Failed to download: ${response.statusCode} ${response.statusMessage}`
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
response.pipe(file);
|
|
72
|
+
|
|
73
|
+
file.on("finish", () => {
|
|
74
|
+
file.close(resolve);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
request.on("error", (err) => {
|
|
79
|
+
file.close();
|
|
80
|
+
reject(err);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
file.on("error", (err) => {
|
|
84
|
+
file.close();
|
|
85
|
+
reject(err);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Main installation logic
|
|
91
|
+
async function install() {
|
|
92
|
+
try {
|
|
93
|
+
// Skip postinstall in development (when installing from the repo)
|
|
94
|
+
// Check if we're in development by looking for src/ directory
|
|
95
|
+
const srcDir = join(__dirname, "..", "src");
|
|
96
|
+
try {
|
|
97
|
+
await access(srcDir, constants.F_OK);
|
|
98
|
+
console.log("✓ Development environment detected, skipping binary download");
|
|
99
|
+
console.log(" Run 'bun run build:all' to build binaries locally");
|
|
100
|
+
return;
|
|
101
|
+
} catch {
|
|
102
|
+
// Not in development, continue with download
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Get version from package.json
|
|
106
|
+
const packageJsonPath = join(__dirname, "..", "package.json");
|
|
107
|
+
const { readFile } = await import("node:fs/promises");
|
|
108
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
|
|
109
|
+
const { version } = packageJson;
|
|
110
|
+
|
|
111
|
+
const { binaryName, isWindows } = getPlatformInfo();
|
|
112
|
+
const binDir = join(__dirname, "..", "bin");
|
|
113
|
+
const binaryPath = join(binDir, binaryName);
|
|
114
|
+
|
|
115
|
+
// Check if binary already exists
|
|
116
|
+
try {
|
|
117
|
+
await access(binaryPath, constants.F_OK);
|
|
118
|
+
console.log(`✓ Binary already exists at ${binaryPath}`);
|
|
119
|
+
return;
|
|
120
|
+
} catch {
|
|
121
|
+
// Binary doesn't exist, continue with download
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Ensure bin directory exists
|
|
125
|
+
await mkdir(binDir, { recursive: true });
|
|
126
|
+
|
|
127
|
+
// Download binary from GitHub releases
|
|
128
|
+
const downloadUrl = `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${binaryName}`;
|
|
129
|
+
|
|
130
|
+
await downloadFile(downloadUrl, binaryPath);
|
|
131
|
+
|
|
132
|
+
// Make binary executable (Unix-like systems)
|
|
133
|
+
if (!isWindows) {
|
|
134
|
+
chmodSync(binaryPath, 0o755);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log(`✓ Successfully installed ${PACKAGE_NAME} v${version}`);
|
|
138
|
+
console.log(` Binary location: ${binaryPath}`);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(`✗ Failed to install ${PACKAGE_NAME}:`, error.message);
|
|
141
|
+
console.error(
|
|
142
|
+
`\nYou can manually download binaries from: https://github.com/${GITHUB_REPO}/releases`
|
|
143
|
+
);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
install();
|