@anvil-works/anvil-cli 0.5.7 → 0.5.9
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 +280 -367
- package/dist/cli.js +65 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
# anvil-cli
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
### macOS/Linux
|
|
1
|
+
# anvil-cli
|
|
2
|
+
|
|
3
|
+
`anvil-cli` is the command-line tool for developing Anvil apps locally.
|
|
4
|
+
|
|
5
|
+
Use it to:
|
|
6
|
+
|
|
7
|
+
- check out an Anvil app into a local folder
|
|
8
|
+
- edit code in your own editor
|
|
9
|
+
- keep that local folder synced with Anvil while you work
|
|
10
|
+
- switch between local code editing and the Anvil designer in the same workflow
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
### macOS or Linux
|
|
17
15
|
|
|
18
16
|
```bash
|
|
19
17
|
curl -fsSL https://anvil.works/install-cli.sh | sh
|
|
@@ -31,433 +29,348 @@ irm https://anvil.works/install-cli.ps1 | iex
|
|
|
31
29
|
curl -fsSL https://anvil.works/install-cli.cmd -o install.cmd && install.cmd && del install.cmd
|
|
32
30
|
```
|
|
33
31
|
|
|
34
|
-
###
|
|
32
|
+
### npm fallback
|
|
35
33
|
|
|
36
34
|
```bash
|
|
37
35
|
npm install -g @anvil-works/anvil-cli@latest
|
|
38
36
|
```
|
|
39
|
-
|
|
40
|
-
## Quick Start
|
|
41
37
|
|
|
42
|
-
|
|
38
|
+
## Quickstart
|
|
39
|
+
|
|
40
|
+
This is the main happy path:
|
|
41
|
+
|
|
42
|
+
1. Install `anvil-cli`.
|
|
43
|
+
2. Run `anvil configure`.
|
|
44
|
+
3. Run `anvil checkout`.
|
|
45
|
+
4. Change into the app directory.
|
|
46
|
+
5. Run `anvil watch`.
|
|
47
|
+
|
|
48
|
+
### 1. Configure the CLI
|
|
43
49
|
|
|
44
|
-
|
|
50
|
+
Run:
|
|
45
51
|
|
|
46
52
|
```bash
|
|
47
53
|
anvil configure
|
|
48
54
|
```
|
|
49
55
|
|
|
50
|
-
|
|
51
|
-
running a dedicated enterprise/on-prem Anvil installation.
|
|
52
|
-
`anvil configure` does not run checkout automatically; it ends by suggesting `anvil checkout`.
|
|
56
|
+
This guided setup helps you:
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
- set your default Anvil server URL
|
|
59
|
+
- choose a preferred editor, if you want one
|
|
60
|
+
- log in to Anvil
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
If you use `anvil.works`, you can usually accept the default server when prompted.
|
|
63
|
+
|
|
64
|
+
### 2. Check out your app
|
|
65
|
+
|
|
66
|
+
Run:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
anvil checkout
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This opens an interactive app picker and creates the app directory for you.
|
|
73
|
+
|
|
74
|
+
If you already have the app URL from the Anvil editor, you can also run:
|
|
58
75
|
|
|
59
76
|
```bash
|
|
60
77
|
anvil checkout https://anvil.works/build/apps/W36XUTXGNPDK6VEA my-app
|
|
61
78
|
cd my-app
|
|
62
79
|
```
|
|
63
80
|
|
|
64
|
-
|
|
81
|
+
You can also check out by app ID:
|
|
65
82
|
|
|
66
|
-
|
|
83
|
+
```bash
|
|
84
|
+
anvil checkout W36XUTXGNPDK6VEA my-app --url anvil.works
|
|
85
|
+
cd my-app
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Start syncing
|
|
89
|
+
|
|
90
|
+
Inside the app directory, run:
|
|
67
91
|
|
|
68
92
|
```bash
|
|
69
93
|
anvil watch
|
|
70
94
|
```
|
|
71
95
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
│ Local Files │◄────►│ anvil-cli │◄────►│ Anvil Server │◄────►│ Anvil IDE │
|
|
91
|
-
│(your editor) │ │ (Node.js CLI)│ │(anvil.works) │ │ (Browser) │
|
|
92
|
-
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
The diagram shows bidirectional sync:
|
|
96
|
-
|
|
97
|
-
- **Local → Anvil**: Your local file changes are synced to Anvil via API calls through anvil-cli
|
|
98
|
-
- **Anvil → Local**: Changes made in the Anvil IDE are automatically detected and synced back to your local files via git fetch through anvil-cli
|
|
99
|
-
|
|
100
|
-
### CLI Commands
|
|
101
|
-
|
|
102
|
-
| Command | Description |
|
|
103
|
-
| -------------------------------------- | -------------------------------------------------------------------- |
|
|
104
|
-
| `anvil watch [path]` | Watch directory for changes and sync to Anvil |
|
|
105
|
-
| `anvil watch [path] -O` | Open watched path in preferred editor/default app |
|
|
106
|
-
| `anvil watch -V` or `--verbose` | Watch with verbose logging (detailed output) |
|
|
107
|
-
| `anvil w [path]` | Short form for watch |
|
|
108
|
-
| `anvil configure` | Guided setup for default URL and login |
|
|
109
|
-
| `anvil checkout [input] [directory]` | Check out an app by URL/app ID, or interactively with no input |
|
|
110
|
-
| `anvil login [anvil-server-url]` | Authenticate with Anvil using OAuth (supports smart URL handling) |
|
|
111
|
-
| `anvil l [anvil-server-url]` | Short form for login |
|
|
112
|
-
| `anvil logout [anvil-server-url]` | Logout from Anvil (optionally specify URL for specific installation) |
|
|
113
|
-
| `anvil config <action> [key] [value]` | Manage configuration (set, get, list) |
|
|
114
|
-
| `anvil c <action> [key] [value]` | Short form for config |
|
|
115
|
-
| `anvil version` | Show version information |
|
|
116
|
-
| `anvil -h, --help` | Show help message |
|
|
117
|
-
| `anvil -v, --version` | Show version number |
|
|
118
|
-
|
|
119
|
-
### App ID Detection
|
|
120
|
-
|
|
121
|
-
anvil-cli can auto-detect your app ID using multiple strategies:
|
|
122
|
-
|
|
123
|
-
1. **Git Remotes**: Checks for Anvil git remotes in the repository
|
|
124
|
-
|
|
125
|
-
2. **Commit Lookup**: Queries Anvil API with current commit ID and branch to find matching app
|
|
126
|
-
|
|
127
|
-
If auto-detection fails, you can specify the app ID explicitly:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
anvil watch -A YOUR_APP_ID
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Anvil URL Detection
|
|
134
|
-
|
|
135
|
-
anvil-cli automatically detects which Anvil server to use:
|
|
136
|
-
|
|
137
|
-
1. **Explicit URL**: If you specify `--url` or `-u` flag
|
|
138
|
-
2. **Git Remotes**: Automatically extracts URL from git remotes in your repository
|
|
139
|
-
3. **Logged-in URLs**:
|
|
140
|
-
- If one logged-in URL is available, uses it automatically
|
|
141
|
-
- If multiple logged-in URLs are available, prompts you to select one
|
|
142
|
-
4. **Global Config**: Falls back to `anvilUrl` in config file
|
|
143
|
-
5. **Default**: Uses `https://anvil.works` (or `http://localhost:3000` in dev mode)
|
|
144
|
-
|
|
145
|
-
**Examples:**
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
# Auto-detect from git remote
|
|
149
|
-
anvil watch
|
|
150
|
-
|
|
151
|
-
# Specify URL explicitly
|
|
152
|
-
anvil watch --url anvil.works
|
|
153
|
-
anvil watch --url localhost:3000
|
|
154
|
-
anvil watch --url anvil.mycompany.com
|
|
155
|
-
|
|
156
|
-
# If multiple logged-in URLs, you'll be prompted to select
|
|
157
|
-
anvil watch
|
|
158
|
-
# ? Multiple Anvil installations found. Which one would you like to use?
|
|
159
|
-
# ❯ https://anvil.works
|
|
160
|
-
# https://anvil.company.com
|
|
161
|
-
# Cancel
|
|
96
|
+
Leave this running while you work.
|
|
97
|
+
|
|
98
|
+
With `anvil watch` running:
|
|
99
|
+
|
|
100
|
+
- local code changes sync into Anvil
|
|
101
|
+
- compatible changes made in Anvil sync back into your local files
|
|
102
|
+
- you can keep using the Anvil designer when you need it
|
|
103
|
+
|
|
104
|
+
## Core Commands
|
|
105
|
+
|
|
106
|
+
These are the commands that matter most for normal local development:
|
|
107
|
+
|
|
108
|
+
### `anvil configure`
|
|
109
|
+
|
|
110
|
+
Guided setup for your default server URL, editor preference, and login.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
anvil configure
|
|
162
114
|
```
|
|
163
115
|
|
|
164
|
-
###
|
|
116
|
+
### `anvil checkout`
|
|
117
|
+
|
|
118
|
+
Create a local app folder from an editor URL, Git URL, app ID, or interactive picker.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
anvil checkout [input] [directory]
|
|
122
|
+
anvil co [input] [directory]
|
|
123
|
+
```
|
|
165
124
|
|
|
166
|
-
|
|
125
|
+
Common examples:
|
|
167
126
|
|
|
168
127
|
```bash
|
|
169
|
-
# Interactive search/select (ordered by most recently edited)
|
|
170
128
|
anvil checkout
|
|
129
|
+
anvil checkout https://anvil.works/build/apps/W36XUTXGNPDK6VEA my-app
|
|
130
|
+
anvil checkout W36XUTXGNPDK6VEA my-app --url anvil.works
|
|
131
|
+
anvil co -Q "dashboard"
|
|
171
132
|
```
|
|
172
133
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
134
|
+
Useful options:
|
|
135
|
+
|
|
136
|
+
- `-O, --open` open the app folder after checkout
|
|
137
|
+
- `-b, --branch <BRANCH>` check out a specific branch
|
|
138
|
+
- `-Q, --query <QUERY>` prefill the interactive search
|
|
139
|
+
- `-u, --url <ANVIL_URL>` choose the Anvil installation explicitly
|
|
140
|
+
- `-U, --user <USERNAME>` choose the logged-in account explicitly
|
|
141
|
+
- `-f, --force` override destination safety checks
|
|
177
142
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
143
|
+
### `anvil watch`
|
|
144
|
+
|
|
145
|
+
Keep your local app folder synced with Anvil while you work.
|
|
181
146
|
|
|
182
147
|
```bash
|
|
183
|
-
|
|
184
|
-
anvil
|
|
148
|
+
anvil watch [path]
|
|
149
|
+
anvil w [path]
|
|
150
|
+
```
|
|
185
151
|
|
|
186
|
-
|
|
187
|
-
anvil checkout https://anvil.works/git/MHVELZG5SZXK2POE.git
|
|
152
|
+
Common examples:
|
|
188
153
|
|
|
189
|
-
|
|
190
|
-
anvil
|
|
154
|
+
```bash
|
|
155
|
+
anvil watch
|
|
156
|
+
anvil watch -s
|
|
157
|
+
anvil watch -a
|
|
158
|
+
anvil watch -O
|
|
159
|
+
anvil watch --url anvil.company.com
|
|
160
|
+
```
|
|
191
161
|
|
|
192
|
-
|
|
193
|
-
anvil checkout MHVELZG5SZXK2POE my-local-app --url anvil.works
|
|
162
|
+
Useful options:
|
|
194
163
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
164
|
+
- `-A, --appid <APP_ID>` specify the app directly
|
|
165
|
+
- `-s, --staged-only` sync only staged files
|
|
166
|
+
- `-a, --auto` handle some branch and sync transitions automatically
|
|
167
|
+
- `-O, --open` open the watched path in your preferred editor
|
|
168
|
+
- `-u, --url <ANVIL_URL>` choose the Anvil installation explicitly
|
|
169
|
+
- `-U, --user <USERNAME>` choose the logged-in account explicitly
|
|
199
170
|
|
|
200
|
-
|
|
201
|
-
anvil checkout -Q "dashboard"
|
|
202
|
-
anvil checkout --query "dashboard"
|
|
171
|
+
### Other useful commands
|
|
203
172
|
|
|
204
|
-
|
|
205
|
-
anvil
|
|
206
|
-
anvil
|
|
173
|
+
```bash
|
|
174
|
+
anvil login
|
|
175
|
+
anvil logout
|
|
176
|
+
anvil config list
|
|
177
|
+
anvil config get <key>
|
|
178
|
+
anvil config set <key> <value>
|
|
179
|
+
anvil config reset
|
|
180
|
+
anvil version
|
|
181
|
+
anvil update
|
|
182
|
+
anvil --help
|
|
183
|
+
anvil <command> --help
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Global options:
|
|
187
|
+
|
|
188
|
+
- `-V, --verbose` show detailed output
|
|
189
|
+
- `--json` output NDJSON for scripting or LLM tooling
|
|
190
|
+
|
|
191
|
+
## Recommended Workflows
|
|
192
|
+
|
|
193
|
+
### Work between your editor and the Anvil designer
|
|
194
|
+
|
|
195
|
+
The basic loop is:
|
|
196
|
+
|
|
197
|
+
1. Run `anvil watch` in your app folder.
|
|
198
|
+
2. Edit Python locally in your editor.
|
|
199
|
+
3. Open the same app in Anvil when you need the designer.
|
|
200
|
+
4. Keep `anvil watch` running while you move between them.
|
|
201
|
+
|
|
202
|
+
### Use branches by default
|
|
203
|
+
|
|
204
|
+
Create or switch to a branch before you start watching:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
git checkout -b my-feature
|
|
208
|
+
anvil watch
|
|
207
209
|
```
|
|
208
210
|
|
|
209
|
-
|
|
211
|
+
If you switch branches while watching, `anvil watch` may prompt you to restart or resync. If you want the CLI to handle that automatically, use:
|
|
210
212
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
```bash
|
|
214
|
+
anvil watch --auto
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Use staged-only mode when experimenting
|
|
218
|
+
|
|
219
|
+
If you want tighter control over what syncs to Anvil, use:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
anvil watch --staged-only
|
|
223
|
+
git add server_code/MyModule.py
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Only staged files will sync.
|
|
213
227
|
|
|
214
|
-
|
|
228
|
+
### Work with AI assistants
|
|
215
229
|
|
|
216
|
-
|
|
217
|
-
- The helper retrieves short-lived access tokens from your logged-in account and refreshes them as needed.
|
|
218
|
-
- Per-app bindings are stored in local git config (`anvil.auth.<APPID>.url` and `anvil.auth.<APPID>.username`) so multi-account repos stay deterministic.
|
|
230
|
+
A simple pattern is:
|
|
219
231
|
|
|
220
|
-
|
|
232
|
+
1. Start `anvil watch`.
|
|
233
|
+
2. Open the app folder in Cursor, VS Code, or another editor.
|
|
234
|
+
3. Make or review AI-generated changes locally.
|
|
235
|
+
4. Test the synced result in Anvil.
|
|
221
236
|
|
|
222
|
-
|
|
223
|
-
- `-b, --branch <BRANCH>` - Checkout a specific branch
|
|
224
|
-
- `--depth <N>` - Shallow clone with `N` commits of history
|
|
225
|
-
- `--single-branch` - Clone only one branch
|
|
226
|
-
- `--origin <NAME>` - Use custom remote name instead of `origin`
|
|
227
|
-
- `--quiet` - Suppress git clone progress output
|
|
228
|
-
- `--verbose` - Verbose git clone output
|
|
229
|
-
- `-f, --force` - Override destination safety checks
|
|
230
|
-
- `-u, --url <ANVIL_URL>` - Override detected Anvil URL
|
|
231
|
-
- `-U, --user <USERNAME>` - Use a specific logged-in account
|
|
237
|
+
If you are iterating on messy changes, combine this with `--staged-only`.
|
|
232
238
|
|
|
233
|
-
|
|
234
|
-
prompt you to select one (interactive mode) or require `--user` in
|
|
235
|
-
non-interactive mode.
|
|
239
|
+
## Multiple Accounts and Enterprise Installs
|
|
236
240
|
|
|
237
|
-
|
|
241
|
+
Most users on `anvil.works` do not need to think about this.
|
|
238
242
|
|
|
239
|
-
|
|
243
|
+
If you work across multiple Anvil installations or multiple logged-in accounts, the CLI can usually infer the right choice. If it cannot, you can override it with:
|
|
240
244
|
|
|
241
|
-
|
|
245
|
+
- `--url` to choose the Anvil installation
|
|
246
|
+
- `--user` to choose the logged-in account
|
|
247
|
+
|
|
248
|
+
Examples:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
anvil login anvil.company.com
|
|
252
|
+
anvil checkout APPID my-app --url anvil.company.com
|
|
253
|
+
anvil watch --url anvil.company.com --user user@example.com
|
|
254
|
+
anvil logout --url anvil.company.com --user user@example.com
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
If you want to change the default server permanently:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
anvil config set anvilUrl https://anvil.company.com
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Troubleshooting
|
|
264
|
+
|
|
265
|
+
### `anvil` command not found
|
|
266
|
+
|
|
267
|
+
Try the install command again, then open a new terminal and run:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
anvil --help
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
If the install script fails, use the npm fallback.
|
|
274
|
+
|
|
275
|
+
### Login or account selection problems
|
|
276
|
+
|
|
277
|
+
Try:
|
|
242
278
|
|
|
243
279
|
```bash
|
|
244
280
|
anvil login
|
|
281
|
+
anvil config list
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
If you use a self-hosted installation:
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
anvil login anvil.company.com
|
|
245
288
|
```
|
|
246
289
|
|
|
247
|
-
|
|
290
|
+
### `anvil checkout` cannot find the app
|
|
248
291
|
|
|
249
|
-
|
|
250
|
-
2. Prompt you to authorize anvil-cli
|
|
251
|
-
3. Complete authentication automatically in the CLI
|
|
292
|
+
Try using the app URL directly from the Anvil editor, or pass `--url` and `--user` if the CLI is looking at the wrong installation or account.
|
|
252
293
|
|
|
253
|
-
|
|
254
|
-
- **macOS**: `~/Library/Preferences/anvil-cli/config.json`
|
|
255
|
-
- **Linux**: `~/.config/anvil-cli/config.json`
|
|
256
|
-
- **Windows**: `%APPDATA%\anvil-cli\Config\config.json`
|
|
294
|
+
### Local changes are not appearing in Anvil
|
|
257
295
|
|
|
258
|
-
|
|
296
|
+
Make sure you are in the correct app directory and restart:
|
|
259
297
|
|
|
260
298
|
```bash
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
299
|
+
anvil watch
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
If you are using `--staged-only`, remember that only staged files sync.
|
|
303
|
+
|
|
304
|
+
### Changes from Anvil are not appearing locally
|
|
264
305
|
|
|
265
|
-
|
|
266
|
-
anvil login localhost:3000
|
|
306
|
+
Make sure `anvil watch` is still running. If the watch session looks unhealthy or branch state changed underneath it, stop it and start it again from the correct branch and app folder.
|
|
267
307
|
|
|
268
|
-
|
|
269
|
-
|
|
308
|
+
### The CLI is using the wrong server
|
|
309
|
+
|
|
310
|
+
Check your current config:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
anvil config list
|
|
270
314
|
```
|
|
271
315
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
- **macOS**: `~/Library/Preferences/anvil-cli/config.json`
|
|
278
|
-
- **Linux**: `~/.config/anvil-cli/config.json`
|
|
279
|
-
- **Windows**: `%APPDATA%\anvil-cli\Config\config.json`
|
|
280
|
-
|
|
281
|
-
### Stored Configuration
|
|
282
|
-
|
|
283
|
-
`config.json` stores settings and auth metadata. OAuth secrets are stored in the
|
|
284
|
-
OS keychain when available.
|
|
285
|
-
|
|
286
|
-
```json
|
|
287
|
-
{
|
|
288
|
-
"anvilUrl": "https://anvil.works",
|
|
289
|
-
"verbose": false,
|
|
290
|
-
"preferredEditor": "cursor",
|
|
291
|
-
"authTokens": {
|
|
292
|
-
"https://anvil.works": {
|
|
293
|
-
"user@example.com": {
|
|
294
|
-
"authToken": null,
|
|
295
|
-
"refreshToken": null,
|
|
296
|
-
"authTokenExpiresAt": 1735689600
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
316
|
+
Set the default explicitly if needed:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
anvil config set anvilUrl https://anvil.company.com
|
|
301
320
|
```
|
|
302
321
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
322
|
+
## Config File
|
|
323
|
+
|
|
324
|
+
`anvil-cli` stores local settings in `config.json`.
|
|
325
|
+
|
|
326
|
+
Common locations:
|
|
327
|
+
|
|
328
|
+
- macOS: `~/Library/Preferences/anvil-cli/config.json`
|
|
329
|
+
- Linux: `~/.config/anvil-cli/config.json`
|
|
330
|
+
- Windows: `%APPDATA%\\anvil-cli\\Config\\config.json`
|
|
331
|
+
|
|
332
|
+
This includes settings such as:
|
|
333
|
+
|
|
334
|
+
- `anvilUrl`
|
|
335
|
+
- `preferredEditor`
|
|
336
|
+
- `verbose`
|
|
337
|
+
|
|
338
|
+
Authentication secrets are stored in the OS keychain when available.
|
|
339
|
+
|
|
340
|
+
## Developing `anvil-cli`
|
|
341
|
+
|
|
342
|
+
Build the CLI:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
pnpm build
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Run in watch mode:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
pnpm dev
|
|
320
352
|
```
|
|
321
353
|
|
|
322
|
-
|
|
354
|
+
Type-check:
|
|
323
355
|
|
|
324
|
-
|
|
356
|
+
```bash
|
|
357
|
+
pnpm tsc --noEmit
|
|
358
|
+
```
|
|
325
359
|
|
|
326
|
-
|
|
360
|
+
Run tests:
|
|
327
361
|
|
|
328
362
|
```bash
|
|
329
|
-
|
|
363
|
+
source tests/setup-test-env.sh
|
|
364
|
+
pnpm test
|
|
330
365
|
```
|
|
331
366
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
### Enterprise Configuration
|
|
338
|
-
|
|
339
|
-
If you're using an Anvil server other than `anvil.works` (e.g., enterprise/on-premise installation), you can work with multiple installations:
|
|
340
|
-
|
|
341
|
-
**Option 1: Login with URL** (recommended)
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
# Login to your enterprise installation
|
|
345
|
-
anvil login anvil.mycompany.com
|
|
346
|
-
|
|
347
|
-
# Or with full URL
|
|
348
|
-
anvil login https://anvil.mycompany.com
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
**Option 2: Specify URL when syncing**
|
|
352
|
-
|
|
353
|
-
```bash
|
|
354
|
-
# Sync with specific URL
|
|
355
|
-
anvil watch --url anvil.mycompany.com
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
**Option 3: Set global default**
|
|
359
|
-
|
|
360
|
-
```bash
|
|
361
|
-
anvil config set anvilUrl https://anvil.mycompany.com
|
|
362
|
-
anvil login
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
**Multiple Installations:**
|
|
366
|
-
|
|
367
|
-
anvil-cli supports multiple Anvil installations simultaneously. Each installation has its own authentication tokens:
|
|
368
|
-
|
|
369
|
-
```bash
|
|
370
|
-
# Login to multiple installations
|
|
371
|
-
anvil login anvil.works
|
|
372
|
-
anvil login anvil.company-a.com
|
|
373
|
-
anvil login anvil.company-b.com
|
|
374
|
-
|
|
375
|
-
# If URL is not resolved from git remotes and multiple logged-in URLs exist,
|
|
376
|
-
# you'll be prompted to select which one to use
|
|
377
|
-
# Or specify explicitly:
|
|
378
|
-
anvil watch --url anvil.company-a.com
|
|
367
|
+
Run one test file:
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
source tests/setup-test-env.sh
|
|
371
|
+
pnpm rstest tests/some.test.ts
|
|
379
372
|
```
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
1. Explicit `--url` flag
|
|
384
|
-
2. Git remote detection (from current repository)
|
|
385
|
-
3. Logged-in URL selection:
|
|
386
|
-
- One URL: auto-select
|
|
387
|
-
- Multiple URLs: prompt to select
|
|
388
|
-
4. `anvilUrl` in config file
|
|
389
|
-
5. Default based on `NODE_ENV`:
|
|
390
|
-
- Production: `https://anvil.works`
|
|
391
|
-
- Development: `http://localhost:3000`
|
|
392
|
-
|
|
393
|
-
View all configuration:
|
|
394
|
-
|
|
395
|
-
```bash
|
|
396
|
-
anvil config list
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
### Logout
|
|
400
|
-
|
|
401
|
-
Logout from Anvil installations:
|
|
402
|
-
|
|
403
|
-
**Logout from all accounts:**
|
|
404
|
-
|
|
405
|
-
```bash
|
|
406
|
-
anvil logout
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**Logout from specific installation:**
|
|
410
|
-
|
|
411
|
-
```bash
|
|
412
|
-
anvil logout anvil.works
|
|
413
|
-
anvil logout anvil.mycompany.com
|
|
414
|
-
anvil logout --url localhost:3000
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
**Without URL:** `anvil logout` uses total logged-in account count across all URLs:
|
|
418
|
-
|
|
419
|
-
- If you have **one account total**, it logs out immediately
|
|
420
|
-
- If you have **multiple accounts total**, you'll be prompted to:
|
|
421
|
-
|
|
422
|
-
- Logout from one account (then select which one)
|
|
423
|
-
- Logout from all accounts
|
|
424
|
-
- Cancel
|
|
425
|
-
|
|
426
|
-
## Troubleshooting
|
|
427
|
-
|
|
428
|
-
### "No app ID found"
|
|
429
|
-
|
|
430
|
-
- Ensure you're in an Anvil app directory with `anvil.yaml`
|
|
431
|
-
- Check git remotes: `git remote -v`
|
|
432
|
-
- Specify app ID explicitly: `anvil watch -A YOUR_APP_ID`
|
|
433
|
-
- Use `-f, --first` to auto-select the first detected app ID: `anvil watch -f`
|
|
434
|
-
|
|
435
|
-
### "Authentication failed" or "Not logged in to [URL]"
|
|
436
|
-
|
|
437
|
-
- Run `anvil login [url]` to authenticate with the specific Anvil installation
|
|
438
|
-
- If you see "Not logged in to [URL]", you need to login to that specific URL:
|
|
439
|
-
|
|
440
|
-
```bash
|
|
441
|
-
anvil login https://anvil.mycompany.com
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
- Your access token may have expired and refresh failed - re-login to get new tokens
|
|
445
|
-
- For multiple installations, make sure you're logged in to the correct one
|
|
446
|
-
|
|
447
|
-
### Switch back to hosted Anvil
|
|
448
|
-
|
|
449
|
-
- Reset the server URL to the default cloud host:
|
|
450
|
-
|
|
451
|
-
```bash
|
|
452
|
-
anvil config set anvilUrl https://anvil.works
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
- Or reset all config values (also clears custom URLs and logs out all accounts):
|
|
456
|
-
|
|
457
|
-
```bash
|
|
458
|
-
anvil config reset
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
## License
|
|
462
|
-
|
|
373
|
+
|
|
374
|
+
## License
|
|
375
|
+
|
|
463
376
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -33132,6 +33132,16 @@ function __webpack_require__(moduleId) {
|
|
|
33132
33132
|
(()=>{
|
|
33133
33133
|
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
33134
33134
|
})();
|
|
33135
|
+
(()=>{
|
|
33136
|
+
__webpack_require__.r = (exports1)=>{
|
|
33137
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
33138
|
+
value: 'Module'
|
|
33139
|
+
});
|
|
33140
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
33141
|
+
value: true
|
|
33142
|
+
});
|
|
33143
|
+
};
|
|
33144
|
+
})();
|
|
33135
33145
|
(()=>{
|
|
33136
33146
|
__webpack_require__.nmd = (module)=>{
|
|
33137
33147
|
module.paths = [];
|
|
@@ -33142,6 +33152,10 @@ function __webpack_require__(moduleId) {
|
|
|
33142
33152
|
var __webpack_exports__ = {};
|
|
33143
33153
|
(()=>{
|
|
33144
33154
|
"use strict";
|
|
33155
|
+
__webpack_require__.r(__webpack_exports__);
|
|
33156
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
33157
|
+
buildProgram: ()=>buildProgram
|
|
33158
|
+
});
|
|
33145
33159
|
const ANSI_BACKGROUND_OFFSET = 10;
|
|
33146
33160
|
const wrapAnsi16 = (offset = 0)=>(code)=>`\u001B[${code + offset}m`;
|
|
33147
33161
|
const wrapAnsi256 = (offset = 0)=>(code)=>`\u001B[${38 + offset};5;${code}m`;
|
|
@@ -51638,15 +51652,16 @@ var __webpack_exports__ = {};
|
|
|
51638
51652
|
}
|
|
51639
51653
|
}
|
|
51640
51654
|
function registerWatchCommand(program) {
|
|
51641
|
-
const watchCommand = program.command("watch [path]").description("Watch for file changes and sync to Anvil").alias("sync").alias("w").option("-A, --appid <APP_ID>", "Specify app ID directly").option("-f, --first", "Auto-select first detected app ID without confirmation").option("-s, --staged-only", "Only sync staged changes (use git add to stage files)").option("-a, --auto", "Auto mode: restart on branch changes and sync when behind").option("-
|
|
51642
|
-
|
|
51655
|
+
const watchCommand = program.command("watch [path]").description("Watch for file changes and sync to Anvil").alias("sync").alias("w").option("-A, --appid <APP_ID>", "Specify app ID directly").option("-f, --first", "Auto-select first detected app ID without confirmation").option("-s, --staged-only", "Only sync staged changes (use git add to stage files)").option("-a, --auto", "Auto mode: restart on branch changes and sync when behind").option("-O, --open", "Open watched path in preferred editor (or default app)").option("-u, --url <ANVIL_URL>", "Specify Anvil server URL (e.g., anvil.works, localhost)").option("-U, --user <USERNAME>", "Specify which user account to use").action(async (path, options, command)=>{
|
|
51656
|
+
const globalOptions = command.optsWithGlobals();
|
|
51657
|
+
if (void 0 !== globalOptions.verbose && logger_logger instanceof CLILogger) logger_logger.setVerbose(globalOptions.verbose);
|
|
51643
51658
|
await handleWatchCommand({
|
|
51644
51659
|
path,
|
|
51645
51660
|
appid: options.appid,
|
|
51646
51661
|
useFirst: options.first,
|
|
51647
51662
|
stagedOnly: options.stagedOnly,
|
|
51648
51663
|
autoMode: options.auto,
|
|
51649
|
-
verbose:
|
|
51664
|
+
verbose: globalOptions.verbose,
|
|
51650
51665
|
open: options.open,
|
|
51651
51666
|
url: options.url,
|
|
51652
51667
|
user: options.user
|
|
@@ -52574,8 +52589,9 @@ var __webpack_exports__ = {};
|
|
|
52574
52589
|
await openPathInEditorOrDefault(destinationPath, preferredEditorCommand, deps);
|
|
52575
52590
|
}
|
|
52576
52591
|
function registerCheckoutCommand(program) {
|
|
52577
|
-
const checkoutCommand = program.command("checkout [input] [directory]").description("Check out an Anvil app locally from editor URL, git URL, app ID, or interactive selection").alias("co").option("-O, --open", "Open destination after checkout").option("-b, --branch <BRANCH>", "Checkout a specific branch").option("--depth <N>", "Create a shallow clone with history truncated to N commits", (value)=>parseInt(value, 10)).option("--single-branch", "Clone only one branch").option("--origin <NAME>", "Use a custom remote name instead of origin").option("--quiet", "Suppress git clone progress output").option("--verbose", "Enable verbose git clone output").option("-u, --url <ANVIL_URL>", "Specify Anvil server URL").option("-U, --user <USERNAME>", "Specify which user account to use").option("-f, --force", "Override safety checks for destination path").option("-Q, --query <QUERY>", "Initial search query for interactive checkout picker").action(async (input, directory, options)=>{
|
|
52592
|
+
const checkoutCommand = program.command("checkout [input] [directory]").description("Check out an Anvil app locally from editor URL, git URL, app ID, or interactive selection").alias("co").option("-O, --open", "Open destination after checkout").option("-b, --branch <BRANCH>", "Checkout a specific branch").option("--depth <N>", "Create a shallow clone with history truncated to N commits", (value)=>parseInt(value, 10)).option("--single-branch", "Clone only one branch").option("--origin <NAME>", "Use a custom remote name instead of origin").option("--quiet", "Suppress git clone progress output").option("--verbose", "Enable verbose git clone output").option("-u, --url <ANVIL_URL>", "Specify Anvil server URL").option("-U, --user <USERNAME>", "Specify which user account to use").option("-f, --force", "Override safety checks for destination path").option("-Q, --query <QUERY>", "Initial search query for interactive checkout picker").action(async (input, directory, options, command)=>{
|
|
52578
52593
|
try {
|
|
52594
|
+
const globalOptions = command?.optsWithGlobals() || options || {};
|
|
52579
52595
|
if ("number" == typeof options?.depth && (!Number.isFinite(options.depth) || options.depth <= 0)) throw new Error("--depth must be a positive integer");
|
|
52580
52596
|
await executeCheckout({
|
|
52581
52597
|
input,
|
|
@@ -52586,7 +52602,7 @@ var __webpack_exports__ = {};
|
|
|
52586
52602
|
singleBranch: options?.singleBranch,
|
|
52587
52603
|
origin: options?.origin,
|
|
52588
52604
|
quiet: options?.quiet,
|
|
52589
|
-
verbose:
|
|
52605
|
+
verbose: globalOptions.verbose,
|
|
52590
52606
|
url: options?.url,
|
|
52591
52607
|
user: options?.user,
|
|
52592
52608
|
force: options?.force,
|
|
@@ -53054,39 +53070,51 @@ var __webpack_exports__ = {};
|
|
|
53054
53070
|
process.exit(1);
|
|
53055
53071
|
}
|
|
53056
53072
|
}
|
|
53057
|
-
|
|
53058
|
-
|
|
53059
|
-
|
|
53060
|
-
|
|
53061
|
-
|
|
53062
|
-
|
|
53063
|
-
|
|
53064
|
-
const
|
|
53065
|
-
|
|
53066
|
-
|
|
53067
|
-
|
|
53068
|
-
|
|
53069
|
-
|
|
53070
|
-
|
|
53071
|
-
|
|
53072
|
-
|
|
53073
|
-
|
|
53074
|
-
|
|
53075
|
-
|
|
53076
|
-
|
|
53077
|
-
|
|
53078
|
-
|
|
53079
|
-
|
|
53080
|
-
|
|
53081
|
-
|
|
53082
|
-
|
|
53083
|
-
|
|
53084
|
-
})
|
|
53085
|
-
if (
|
|
53086
|
-
|
|
53087
|
-
|
|
53073
|
+
function addGlobalOptionsHelp(command) {
|
|
53074
|
+
if ("help" !== command.name()) command.addHelpText("after", "\n" + chalk_source.bold("Global Options:") + "\n -V, --verbose Show detailed output\n");
|
|
53075
|
+
command.commands.forEach((subcommand)=>addGlobalOptionsHelp(subcommand));
|
|
53076
|
+
}
|
|
53077
|
+
function buildProgram() {
|
|
53078
|
+
const program = new Command();
|
|
53079
|
+
program.name("anvil").description("CLI tool for developing Anvil apps locally").version(VERSION, "-v, --version", "Output the version number").option("--json", "Output in JSON format (NDJSON) for scripting/LLM consumption").option("-V, --verbose", "Show detailed output").helpOption('-h, --help', 'Display help for anvil command').hook("preAction", async (_thisCommand, actionCommand)=>{
|
|
53080
|
+
const opts = actionCommand.optsWithGlobals();
|
|
53081
|
+
setGlobalOutputConfig({
|
|
53082
|
+
jsonMode: !!opts.json
|
|
53083
|
+
});
|
|
53084
|
+
if (logger_logger instanceof CLILogger) logger_logger.setVerbose(!!opts.verbose);
|
|
53085
|
+
if (!opts.json) {
|
|
53086
|
+
const commandName = actionCommand?.name();
|
|
53087
|
+
if ("update" !== commandName && "git-credential" !== commandName) checkVersionAndWarn();
|
|
53088
|
+
}
|
|
53089
|
+
});
|
|
53090
|
+
const watchCommand = registerWatchCommand(program);
|
|
53091
|
+
registerCheckoutCommand(program);
|
|
53092
|
+
registerGitCredentialCommand(program);
|
|
53093
|
+
registerLoginCommand(program);
|
|
53094
|
+
registerLogoutCommand(program);
|
|
53095
|
+
registerConfigCommand(program);
|
|
53096
|
+
registerVersionCommand(program, VERSION);
|
|
53097
|
+
registerConfigureCommand(program, VERSION);
|
|
53098
|
+
program.command("update").description("Update anvil to the latest version").alias("u").action(async ()=>{
|
|
53099
|
+
await handleUpdateCommand();
|
|
53100
|
+
});
|
|
53101
|
+
if (watchCommand) {
|
|
53102
|
+
const watchOptions = watchCommand.options.map((opt)=>{
|
|
53103
|
+
const flags = opt.flags;
|
|
53104
|
+
const description = opt.description || "";
|
|
53105
|
+
return ` ${flags.padEnd(30)} ${description}`;
|
|
53106
|
+
}).join("\n");
|
|
53107
|
+
if (watchOptions) program.addHelpText("after", "\n" + chalk_source.bold("Watch Command Options:") + "\n" + chalk_source.gray(" (These options apply to the 'watch' command)") + "\n" + watchOptions + "\n");
|
|
53108
|
+
}
|
|
53109
|
+
program.commands.forEach((command)=>addGlobalOptionsHelp(command));
|
|
53110
|
+
return program;
|
|
53111
|
+
}
|
|
53112
|
+
buildProgram().parse();
|
|
53088
53113
|
})();
|
|
53089
|
-
|
|
53114
|
+
exports.buildProgram = __webpack_exports__.buildProgram;
|
|
53115
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
53116
|
+
"buildProgram"
|
|
53117
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
53090
53118
|
Object.defineProperty(exports, '__esModule', {
|
|
53091
53119
|
value: true
|
|
53092
53120
|
});
|