arashi 1.30.0 → 1.32.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 CHANGED
@@ -8,6 +8,8 @@ Arashi is a Git worktree manager for meta-repositories.
8
8
 
9
9
  It keeps related repositories aligned while you work on a feature branch across a shared workspace.
10
10
 
11
+ Arashi makes a polyrepo work like a monorepo during development, while every repository keeps its own history, CI, and pull requests.
12
+
11
13
  [Documentation](https://arashi.haphazard.dev)
12
14
 
13
15
  ## Installation
@@ -37,7 +39,9 @@ arashi --version
37
39
  ```
38
40
 
39
41
  By default, the installer places `arashi` in `~/.arashi/bin`, adds that path to your shell config, and in interactive installs offers to enable shell integration for `arashi switch --cd`.
40
- It also runs a quick `arashi --version` smoke test before declaring success.
42
+ Supported installations provide both canonical `arashi` and the first-class `aw` shorthand (“Arashi Workspace”). Both run the same implementation; product names, configuration, environment variables, help, and documentation remain canonical `arashi`.
43
+
44
+ The installer transaction verifies identical, non-empty `arashi --version` and `aw --version` output before declaring success.
41
45
 
42
46
  If curl installation fails, or if the smoke test reports a bad release artifact, use npm installation below or the manual release instructions in [`docs/INSTALLATION.md`](./docs/INSTALLATION.md).
43
47
 
@@ -49,7 +53,7 @@ PowerShell is the canonical Windows installer:
49
53
  powershell -c "irm https://arashi.haphazard.dev/install.ps1 | iex"
50
54
  ```
51
55
 
52
- It verifies and installs `arashi.bin.exe`, the extensionless `arashi` wrapper for Git Bash, `arashi.ps1`, and `arashi.bat` from the same release. The default directory is `%USERPROFILE%\.arashi\bin`; the installer adds it to the persistent user PATH. It does not create or modify `.bashrc` or another shell profile. Open a new Git Bash window before running `arashi --version` so it inherits the PATH change.
56
+ It verifies and installs one `arashi.bin.exe` plus `arashi`/`aw` wrappers for Git Bash, `arashi.ps1`/`aw.ps1`, and `arashi.bat`/`aw.bat` from the same release. The default directory is `%USERPROFILE%\.arashi\bin`; the installer adds it to the persistent user PATH. It does not create or modify `.bashrc` or another shell profile. Open a new Git Bash window before running `arashi --version` or `aw --version` so it inherits the PATH change.
53
57
 
54
58
  ### Option 3: Install with npm
55
59
 
@@ -57,7 +61,7 @@ It verifies and installs `arashi.bin.exe`, the extensionless `arashi` wrapper fo
57
61
  npm install -g arashi
58
62
  ```
59
63
 
60
- The npm package is script-free: it does not require package-manager lifecycle scripts or `postinstall` approval. It installs the lightweight JavaScript entrypoint and wrapper files first, then downloads the matching platform binary on first use.
64
+ The npm package is script-free: it does not require package-manager lifecycle scripts or `postinstall` approval. It maps both npm bins to the same lightweight JavaScript entrypoint, then downloads the matching platform binary on first use through either name.
61
65
 
62
66
  To preinstall the binary explicitly, run:
63
67
 
@@ -90,29 +94,34 @@ If you prefer not to use npm, download a platform binary from [GitHub Releases](
90
94
  macOS (Apple Silicon):
91
95
 
92
96
  ```bash
93
- curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi-macos-arm64 -o arashi
94
- chmod +x arashi
95
- sudo mv arashi /usr/local/bin/arashi
97
+ curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi-macos-arm64 -o arashi.bin
98
+ curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi -o arashi
99
+ curl -L https://github.com/corwinm/arashi/releases/latest/download/aw -o aw
100
+ chmod +x arashi.bin arashi aw
101
+ sudo install -m 0755 arashi.bin arashi aw /usr/local/bin/
96
102
  ```
97
103
 
98
104
  Linux (x64):
99
105
 
100
106
  ```bash
101
- curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi-linux-x64 -o arashi
102
- chmod +x arashi
103
- sudo mv arashi /usr/local/bin/arashi
107
+ curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi-linux-x64 -o arashi.bin
108
+ curl -L https://github.com/corwinm/arashi/releases/latest/download/arashi -o arashi
109
+ curl -L https://github.com/corwinm/arashi/releases/latest/download/aw -o aw
110
+ chmod +x arashi.bin arashi aw
111
+ sudo install -m 0755 arashi.bin arashi aw /usr/local/bin/
104
112
  ```
105
113
 
106
114
  Windows (PowerShell and Git Bash):
107
115
 
108
116
  ```powershell
109
117
  # Download arashi-windows-x64.exe, arashi, arashi.ps1, arashi.bat,
118
+ # aw, aw.ps1, aw.bat,
110
119
  # and arashi-checksums.txt from the same release.
111
- # Verify all four payload files against arashi-checksums.txt.
112
- # Rename arashi-windows-x64.exe to arashi.bin.exe and keep the four files together on PATH.
120
+ # Verify all seven payload files against arashi-checksums.txt.
121
+ # Rename arashi-windows-x64.exe to arashi.bin.exe and keep the seven files together on PATH.
113
122
  ```
114
123
 
115
- Windows manual installation requires `arashi-windows-x64.exe`, `arashi`, `arashi.ps1`, `arashi.bat`, and `arashi-checksums.txt` from the same release. Verify all four payload files, rename the executable to `arashi.bin.exe`, and keep the payload together on PATH.
124
+ Windows manual installation requires `arashi-windows-x64.exe`, `arashi`, `arashi.ps1`, `arashi.bat`, `aw`, `aw.ps1`, `aw.bat`, and `arashi-checksums.txt` from the same release. Verify all seven payload files, rename the executable to `arashi.bin.exe`, and keep the payload together on PATH. Manual release installations do not create the direct installer's ownership ledger; deliberately move or remove the manual payload before later using the direct installer.
116
125
 
117
126
  You can also build from source for local development. Development is pinned to Node.js 24.18.0, which satisfies pnpm 11's Node.js 22.13 minimum, and pnpm 11.20.0; nvm users can select the repository's development runtime with `nvm use`.
118
127
 
@@ -214,7 +223,7 @@ For contributors working on Arashi itself, the project planning workflow in the
214
223
 
215
224
  ## Shell Integration
216
225
 
217
- Use shell integration for parent-shell directory switching and native tab completion. Bash, Zsh, and Fish are supported.
226
+ Use shell integration for parent-shell directory switching and native tab completion. Bash, Zsh, and Fish are supported through both `arashi` and `aw`.
218
227
 
219
228
  The official curl installer can offer this automatically. If you skip it or use npm, install it for the active shell with:
220
229
 
@@ -240,7 +249,7 @@ command arashi shell init fish | source
240
249
  command arashi completion fish | source
241
250
  ```
242
251
 
243
- `arashi shell init <shell>` remains wrapper-only. `arashi completion <shell>` emits only deterministic sourceable shell code, including on npm first use when the platform binary must be installed.
252
+ `arashi shell init <shell>` remains wrapper-only and defines both parent-shell functions, unless an unrelated `aw` alias or function already owns that shell name. `arashi completion <shell>` registers the same completion model for both executable names and emits only deterministic sourceable shell code, including on npm first use when the platform binary must be installed.
244
253
 
245
254
  Completion covers commands, aliases, options, finite choices, conflicts, and positional boundaries. In an Arashi workspace it also resolves configured repository and group selector segments, switch/remove worktrees and paths, and move source/target references. Dynamic lookup is local and read-only, silent on unavailable or broken metadata, and limited to a 200 ms whole-query budget; it performs no network requests, hooks, prompts, workspace mutations, or child operations. Static completion remains available outside a workspace.
246
255
 
@@ -252,18 +261,23 @@ For automated installs, set `ARASHI_SHELL_INTEGRATION=yes` to enable it without
252
261
 
253
262
  ## Hooks
254
263
 
255
- Arashi can run lifecycle hooks during `arashi create` and `arashi remove`. Configured create uses
256
- workspace `pre-create`/`post-create` plus repository-specific `pre-create.<repo>` and
257
- `post-create.<repo>` files. Configured remove evaluates repository, workspace, user-global targeted,
258
- and user-global shared scopes once per target repository. Standalone mode activates only targeted
259
- and shared user-global hooks.
264
+ Arashi can run file-backed or configured inline lifecycle hooks during `arashi create` and
265
+ `arashi remove`. Inline workspace values live only at root `hooks.scripts.<lifecycle>`; repository
266
+ values live only at `repos.<name>.hooks.<lifecycle>`. Use inline config for short reviewable commands
267
+ and native files for substantial scripts. One inline/file source may own a logical location; a
268
+ same-location collision fails preflight instead of running both.
260
269
 
261
- POSIX uses executable `.sh` files. Windows uses one case-insensitive `.ps1`, `.cmd`, or `.bat`
262
- candidate per location and never runs `.sh` implicitly. Hook failures participate in create rollback
263
- or remove finalization, all hooks default to a 300000 ms timeout, and JSON results expose the ordered
264
- ledger at `data.hookOutcomes` on success or `error.details.hookOutcomes` on failure.
270
+ Configured create uses workspace `pre-create`/`post-create` plus repository-specific create locations.
271
+ Configured remove evaluates repository, workspace, user-global targeted, and user-global shared scopes
272
+ once per target repository. `--no-hooks` is create-only; `--no-hook-input` applies to both commands.
273
+ Standalone mode remains file-only and activates only targeted and shared user-global hooks.
265
274
 
266
- See [`docs/hooks.md`](./docs/hooks.md) for hook behavior, environment variables, and examples.
275
+ Hook failures participate in create rollback or remove finalization. Inline and file sources share the
276
+ configured timeout, input, JSON isolation, dry-run, and ordered outcome policies. Public records expose
277
+ source kind/owner metadata but never disclose configured snippet text.
278
+
279
+ See [`docs/configuration.md`](./docs/configuration.md#inline-lifecycle-hook-configuration) for values and
280
+ [`docs/hooks.md`](./docs/hooks.md) for exact lookup, lifecycle, environment, and automation behavior.
267
281
 
268
282
  ## Workflow Shortcuts
269
283
 
@@ -326,6 +340,12 @@ alias arashi-delete='arashi remove -f'
326
340
 
327
341
  ## Configuration Schema
328
342
 
343
+ ### Configured worktree files
344
+
345
+ Configured repositories can copy isolated files or create native symlinks for intentionally shared state when coordinated worktrees are created. See [Worktree file materialization](docs/configuration.md#worktree-file-materialization) for direct `copy`/`symlink` arrays, Git-primary sourcing, lifecycle order, safety rules, dry-run previews, and doctor diagnostics.
346
+
347
+ ## Configuration Schema
348
+
329
349
  Arashi publishes a JSON Schema for `.arashi/config.json` so editors can validate and autocomplete your config.
330
350
 
331
351
  - Stable URL: `https://unpkg.com/arashi/schema/config.schema.json`
package/bin/aw ADDED
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+ # arashi-managed-alias:aw:v1
3
+ # Arashi Workspace executable alias. Delegates to the one adjacent Arashi native binary.
4
+
5
+ SCRIPT_SOURCE="${BASH_SOURCE[0]}"
6
+ while [ -L "$SCRIPT_SOURCE" ]; do
7
+ SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_SOURCE")" && pwd)"
8
+ SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
9
+ [[ "$SCRIPT_SOURCE" != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
10
+ done
11
+ SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_SOURCE")" && pwd)"
12
+ BINARY="$SCRIPT_DIR/arashi.bin"
13
+
14
+ if [ ! -f "$BINARY" ]; then
15
+ PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]')
16
+ ARCH=$(uname -m)
17
+ WINDOWS_SHELL="false"
18
+ case "${MSYSTEM:-}" in MINGW*|MSYS*) WINDOWS_SHELL="true" ;; esac
19
+ case "$PLATFORM" in mingw*|msys*|cygwin*) WINDOWS_SHELL="true" ;; esac
20
+ if [ "$WINDOWS_SHELL" = "true" ]; then
21
+ BINARY="$SCRIPT_DIR/arashi.bin.exe"
22
+ else
23
+ case "$PLATFORM-$ARCH" in
24
+ darwin-arm64) BINARY="$SCRIPT_DIR/arashi-macos-arm64" ;;
25
+ linux-x86_64) BINARY="$SCRIPT_DIR/arashi-linux-x64" ;;
26
+ *) echo "Error: Unsupported platform $PLATFORM-$ARCH" >&2; exit 1 ;;
27
+ esac
28
+ fi
29
+ fi
30
+
31
+ if [ ! -f "$BINARY" ]; then
32
+ echo "Error: arashi binary not found at $BINARY" >&2
33
+ exit 1
34
+ fi
35
+
36
+ command=""
37
+ for arg in "$@"; do
38
+ case "$arg" in -*) continue ;; *) [ -n "$command" ] || command="$arg" ;; esac
39
+ done
40
+ if [ ! -t 1 ] && [ "$command" = "list" ]; then
41
+ exec "$BINARY" "$@" 0<&-
42
+ fi
43
+ exec "$BINARY" "$@"
package/bin/aw.bat ADDED
@@ -0,0 +1,11 @@
1
+ @echo off
2
+ REM arashi-managed-alias:aw:v1
3
+ REM Arashi Workspace executable alias. Delegate to the adjacent native binary.
4
+ set "SCRIPT_DIR=%~dp0"
5
+ set "BINARY=%SCRIPT_DIR%arashi.bin.exe"
6
+ if not exist "%BINARY%" set "BINARY=%SCRIPT_DIR%arashi-windows-x64.exe"
7
+ if not exist "%BINARY%" (
8
+ echo Error: arashi binary not found at %BINARY% 1>&2
9
+ exit /b 1
10
+ )
11
+ "%BINARY%" %*
package/bin/aw.ps1 ADDED
@@ -0,0 +1,9 @@
1
+ # arashi-managed-alias:aw:v1
2
+ # Arashi Workspace executable alias. Preserve stdin and delegate to the adjacent native binary.
3
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
4
+ $Binary = Join-Path $ScriptDir "arashi.bin.exe"
5
+ if (-not (Test-Path $Binary)) { $Binary = Join-Path $ScriptDir "arashi-windows-x64.exe" }
6
+ if (-not (Test-Path $Binary)) { Write-Error "Error: arashi binary not found at $Binary"; exit 1 }
7
+ & $Binary @args
8
+ if ($LASTEXITCODE -ne $null) { exit $LASTEXITCODE }
9
+ exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arashi",
3
- "version": "1.30.0",
3
+ "version": "1.32.0",
4
4
  "description": "Git worktree manager for meta-repositories - The eye of the storm for your development workflow",
5
5
  "keywords": [
6
6
  "cli",
@@ -24,7 +24,8 @@
24
24
  "url": "git+https://github.com/corwinm/arashi.git"
25
25
  },
26
26
  "bin": {
27
- "arashi": "./bin/arashi.js"
27
+ "arashi": "./bin/arashi.js",
28
+ "aw": "./bin/arashi.js"
28
29
  },
29
30
  "files": [
30
31
  "bin/arashi",
@@ -35,6 +36,9 @@
35
36
  "bin/update-options.js",
36
37
  "bin/arashi.bat",
37
38
  "bin/arashi.ps1",
39
+ "bin/aw",
40
+ "bin/aw.bat",
41
+ "bin/aw.ps1",
38
42
  "schema/config.schema.json",
39
43
  "README.md",
40
44
  "LICENSE"
@@ -66,14 +70,17 @@
66
70
  "schema:generate": "ts-json-schema-generator --tsconfig tsconfig.schema.json --path src/lib/config.ts --type Config --expose export --jsDoc extended --out schema/config.schema.json",
67
71
  "schema:publish": "pnpm run schema:generate && oxfmt --config .oxfmtrc.json --write schema/config.schema.json",
68
72
  "schema:check": "pnpm run schema:publish && git diff --exit-code -- schema/config.schema.json",
69
- "contract:generate": "node scripts/contracts/cli-commands.ts",
70
- "contract:check": "node scripts/contracts/cli-commands.ts --check",
73
+ "contract:generate": "node scripts/contracts/cli-commands.ts && node scripts/contracts/inline-lifecycle-hooks.ts && node scripts/contracts/executable-distribution.ts",
74
+ "contract:check": "node scripts/contracts/cli-commands.ts --check && node scripts/contracts/inline-lifecycle-hooks.ts --check && node scripts/contracts/executable-distribution.ts --check",
75
+ "executable-contract:generate": "node scripts/contracts/executable-distribution.ts",
76
+ "executable-contract:check": "node scripts/contracts/executable-distribution.ts --check",
71
77
  "completion:generate": "node scripts/completions.ts",
72
78
  "completion:check": "node scripts/completions.ts --check",
73
79
  "format": "oxfmt --config .oxfmtrc.json --write .",
74
80
  "format:check": "oxfmt --config .oxfmtrc.json --check .",
75
81
  "quality:changed": "node scripts/quality/changed-files-quality.ts",
76
- "prepublishOnly": "pnpm run completion:check && pnpm run schema:publish",
82
+ "prepublishOnly": "pnpm run completion:check && pnpm run executable-contract:check && pnpm run schema:publish",
83
+ "release:verify-aw": "node scripts/release/verify-aw.ts",
77
84
  "prepare": "husky"
78
85
  },
79
86
  "devDependencies": {
@@ -33,6 +33,10 @@
33
33
  "additionalProperties": false,
34
34
  "description": "Optional workspace-level hooks settings",
35
35
  "properties": {
36
+ "scripts": {
37
+ "$ref": "#/definitions/InlineHookScripts",
38
+ "description": "Workspace inline lifecycle hooks"
39
+ },
36
40
  "timeout": {
37
41
  "description": "Lifecycle-hook timeout in milliseconds (default: 300000)",
38
42
  "maximum": 2147483647,
@@ -144,10 +148,77 @@
144
148
  },
145
149
  "type": "object"
146
150
  },
151
+ "InlineHookInterpreter": {
152
+ "enum": ["bash", "powershell", "cmd"],
153
+ "type": "string"
154
+ },
155
+ "InlineHookInterpreterMap": {
156
+ "additionalProperties": false,
157
+ "description": "Interpreter-specific alternatives for one inline lifecycle hook.",
158
+ "minProperties": 1,
159
+ "properties": {
160
+ "bash": {
161
+ "$ref": "#/definitions/InlineHookSnippet"
162
+ },
163
+ "cmd": {
164
+ "$ref": "#/definitions/InlineHookSnippet"
165
+ },
166
+ "powershell": {
167
+ "$ref": "#/definitions/InlineHookSnippet"
168
+ }
169
+ },
170
+ "type": "object"
171
+ },
172
+ "InlineHookScripts": {
173
+ "additionalProperties": false,
174
+ "description": "Closed set of supported inline lifecycle hooks.",
175
+ "properties": {
176
+ "post-create": {
177
+ "$ref": "#/definitions/InlineHookValue"
178
+ },
179
+ "post-remove": {
180
+ "$ref": "#/definitions/InlineHookValue"
181
+ },
182
+ "pre-create": {
183
+ "$ref": "#/definitions/InlineHookValue"
184
+ },
185
+ "pre-remove": {
186
+ "$ref": "#/definitions/InlineHookValue"
187
+ }
188
+ },
189
+ "type": "object"
190
+ },
191
+ "InlineHookSnippet": {
192
+ "description": "Non-empty inline hook snippet.",
193
+ "minLength": 1,
194
+ "pattern": "\\S",
195
+ "type": "string"
196
+ },
197
+ "InlineHookValue": {
198
+ "anyOf": [
199
+ {
200
+ "$ref": "#/definitions/InlineHookInterpreter"
201
+ },
202
+ {
203
+ "$ref": "#/definitions/InlineHookSnippet"
204
+ },
205
+ {
206
+ "$ref": "#/definitions/InlineHookInterpreterMap"
207
+ }
208
+ ],
209
+ "description": "Bash shorthand or interpreter-specific alternatives for one inline hook."
210
+ },
147
211
  "RepoConfig": {
148
212
  "additionalProperties": false,
149
213
  "description": "Configuration for a single repository",
150
214
  "properties": {
215
+ "copy": {
216
+ "description": "Repository-relative paths copied into new worktrees in declaration order",
217
+ "items": {
218
+ "type": "string"
219
+ },
220
+ "type": "array"
221
+ },
151
222
  "gitUrl": {
152
223
  "description": "Canonical git URL for cloning the repository",
153
224
  "type": "string"
@@ -159,9 +230,20 @@
159
230
  },
160
231
  "type": "array"
161
232
  },
233
+ "hooks": {
234
+ "$ref": "#/definitions/InlineHookScripts",
235
+ "description": "Optional repository-targeted inline lifecycle hooks"
236
+ },
162
237
  "path": {
163
238
  "description": "Path to the repository (relative or absolute)",
164
239
  "type": "string"
240
+ },
241
+ "symlink": {
242
+ "description": "Repository-relative paths symlinked into new worktrees in declaration order",
243
+ "items": {
244
+ "type": "string"
245
+ },
246
+ "type": "array"
165
247
  }
166
248
  },
167
249
  "required": ["path"],