fvtt-world-cli 1.1.0 → 1.1.2
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 +37 -36
- package/dist/index.js +12 -2
- package/docs/README.md +5 -61
- package/docs/architecture.md +53 -209
- package/docs/commands.md +166 -444
- package/docs/compatibility.md +13 -22
- package/docs/getting-started.md +76 -74
- package/docs/images/module-settings.png +0 -0
- package/docs/protocol.md +228 -187
- package/docs/security.md +149 -322
- package/docs/skill.md +25 -30
- package/package.json +17 -6
- package/skills/foundry-world-editor/SKILL.md +8 -0
- package/skills/foundry-world-editor/SKILL.md.sha256 +1 -1
- package/bin/sync-installed-skill.mjs +0 -89
- package/docs/images/icon.svg +0 -16
- package/docs/images/mark.svg +0 -15
package/docs/commands.md
CHANGED
|
@@ -1,340 +1,108 @@
|
|
|
1
1
|
# Commands
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
`fvtt-world-cli` and its short alias `worldctl` accept the same commands. World operations require
|
|
4
|
+
a running daemon and an open, paired GM session; see [Getting started](getting-started.md).
|
|
5
|
+
|
|
6
|
+
## Finding the right command
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
fvtt-world-cli commands
|
|
10
|
-
fvtt-world-cli schema
|
|
11
|
-
fvtt-world-cli
|
|
12
|
-
fvtt-world-cli docs [document]
|
|
9
|
+
fvtt-world-cli commands --json
|
|
10
|
+
fvtt-world-cli schema actor.update
|
|
11
|
+
fvtt-world-cli actor update --help
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
skill, managed with the `fvtt-world-cli skill install`, `skill update`, and `skill remove`
|
|
19
|
-
commands; [Agent skill](skill.md) covers the whole lifecycle.
|
|
14
|
+
`commands` lists available operations, `schema` shows accepted protocol parameters, and `--help`
|
|
15
|
+
shows CLI flags. Protocol names use dots; CLI commands use spaces. For example, `scene.token.get`
|
|
16
|
+
becomes `scene token get`. Nested commands require the parent IDs as well as the target's ID.
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
With a bridge connected, discovery omits denied commands and marks approval requirements with
|
|
19
|
+
`approval: true`. If the daemon or bridge is unavailable, it returns the static registry with
|
|
20
|
+
`policy.applied: false`. Authentication and protocol errors do not trigger that fallback.
|
|
21
|
+
`schema` and `--help` always describe the static registry, including denied commands.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
## Capability map
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
Use these families to narrow your search, then check their help for supported operations.
|
|
26
|
+
|
|
27
|
+
| Task | Command families |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Edit world content | `actor`, `item`, `journal`, `scene`, `macro`, `playlist`, `table`, `cards` |
|
|
30
|
+
| Edit embedded content | Nested families such as `actor.item`, `playlist.sound`, `table.result`, and `*.effect` |
|
|
31
|
+
| Edit scene placeables | `scene.token`, `scene.wall`, `scene.region`, and related families |
|
|
32
|
+
| Manage encounters | `combat`, `combat.combatant`, `combat.group` |
|
|
33
|
+
| Organize content and access | `folder`, `*.ownership.set`, `user` |
|
|
34
|
+
| Manage chat and settings | `chat`, `setting` |
|
|
35
|
+
| Find content or missing assets | `world.search`, `world.audit-files` |
|
|
36
|
+
| Read packs or import world documents | `compendium`, supported `*.import-from-compendium` commands |
|
|
37
|
+
| Manage assets | `file` |
|
|
38
|
+
| Control playback and gameplay | Actions within `playlist`, `table`, `cards`, `combat`, `scene`, and `game` |
|
|
39
|
+
| Show content to players | `scene pull-users`, `journal show`, `image show` |
|
|
40
|
+
| Inspect the connection | `system info`, `system ping` |
|
|
28
41
|
|
|
29
|
-
|
|
30
|
-
Authorization carries a Pair button, and one command in the terminal covers the rest: it waits for
|
|
31
|
-
the request, prints the Origin, world, GM, and browser label it carries, and asks for a yes or no.
|
|
42
|
+
## Common workflows
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
fvtt-world-cli auth
|
|
35
|
-
```
|
|
44
|
+
### Find, inspect, update, verify
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
immediately. Reading a request over before deciding, or approving from a script, is the two-step path
|
|
39
|
-
instead, where non-interactive approval requires `--yes`:
|
|
46
|
+
Check the connected world before making changes:
|
|
40
47
|
|
|
41
48
|
```bash
|
|
42
|
-
fvtt-world-cli
|
|
43
|
-
fvtt-world-cli
|
|
49
|
+
fvtt-world-cli system info --json
|
|
50
|
+
fvtt-world-cli actor list --name "Goblin" --json
|
|
51
|
+
fvtt-world-cli actor get --actor-id <id> --json
|
|
52
|
+
fvtt-world-cli --dry-run actor update --actor-id <id> --name "Goblin Scout" --json
|
|
53
|
+
fvtt-world-cli actor update --actor-id <id> --name "Goblin Scout" --json
|
|
54
|
+
fvtt-world-cli actor get --actor-id <id> --json
|
|
44
55
|
```
|
|
45
56
|
|
|
46
|
-
|
|
57
|
+
### Work with an embedded document
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
Supply the complete parent ID chain. Read the parent to find missing IDs:
|
|
49
60
|
|
|
50
61
|
```bash
|
|
51
|
-
fvtt-world-cli
|
|
62
|
+
fvtt-world-cli scene token list --scene-id <sceneId> --json
|
|
63
|
+
fvtt-world-cli scene token get --scene-id <sceneId> --token-id <tokenId> --json
|
|
52
64
|
```
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
the active slot can be cleared with `bridge release`. The daemon never prints a secret.
|
|
56
|
-
|
|
57
|
-
### Authorization commands
|
|
58
|
-
|
|
59
|
-
- `auth` with no subcommand waits for a pairing request and approves it on the spot. It prints an
|
|
60
|
-
instruction to click Pair in the module's Authorization window, and the request surfaces in the
|
|
61
|
-
terminal as soon as the daemon receives it, including one that was already pending when the command
|
|
62
|
-
started. Several live requests are not an obstacle to it as they are to `auth approve` with no code:
|
|
63
|
-
the wait renders the earliest one and asks about that, and a later request stays pending for another
|
|
64
|
-
run. The wait itself is indefinite: it ends on Ctrl+C, on an answer, or if the daemon connection
|
|
65
|
-
drops, which is reported as `DAEMON_UNAVAILABLE` rather than a silent stop and is safe to re-run once
|
|
66
|
-
the daemon is back. `y` or `yes` approves the displayed code and exits 0, any other answer denies that
|
|
67
|
-
code and exits 1 with `PAIRING_DECLINED`.
|
|
68
|
-
Interrupting the confirmation instead leaves the request untouched: after Ctrl+C or an ended
|
|
69
|
-
stdin it stays pending until it expires or another run answers for it. An ended stdin reports
|
|
70
|
-
`PAIRING_PROMPT_ABORTED` and exits 1, and Ctrl+C does the same while output goes to the terminal;
|
|
71
|
-
with output redirected the prompt does not read keystrokes itself, so Ctrl+C ends the run as an
|
|
72
|
-
ordinary interrupt instead.
|
|
73
|
-
Delivery is a long-poll control call the CLI re-issues on its own, and the daemon answers each call
|
|
74
|
-
inside its own park cap, so an ordinary wait does not end in a timeout; a daemon that stops answering
|
|
75
|
-
altogether still trips the client's request timeout and is reported as `DAEMON_UNAVAILABLE`. The
|
|
76
|
-
command is interactive-only: `--json`, and a stdin that is not a terminal, each fail
|
|
77
|
-
immediately and name `auth pending` plus `auth approve --yes` as the path for scripts.
|
|
78
|
-
`--timeout-ms` cannot cut the wait short either. For the long-poll call, a value below the
|
|
79
|
-
daemon's park cap plus five seconds is raised to it, because a smaller client wait would abandon
|
|
80
|
-
a parked response the daemon is still holding. That long poll is the only call the flag cannot
|
|
81
|
-
shorten. The approval or denial that follows the answer takes `--timeout-ms` as given for its
|
|
82
|
-
client wait, and so does the listing an interactive `auth approve` or `auth prune` reads before
|
|
83
|
-
its prompt, as the other `auth` verbs and `bridge release` do. Without the flag that wait is
|
|
84
|
-
60 seconds.
|
|
85
|
-
- `auth status` shows bridge state and public profile metadata.
|
|
86
|
-
- `auth pending` lists approval candidates with code, expiry, exact Origin, world, GM, browser client
|
|
87
|
-
id, browser label, and module version.
|
|
88
|
-
- `auth approve [code] [--yes]` approves one request. The code may be omitted only when exactly one
|
|
89
|
-
request is pending. Interactive use confirms the displayed identity, including the browser label and
|
|
90
|
-
client id, and then approves that exact request: one that expired or disappeared while the prompt
|
|
91
|
-
waited fails rather than approving whatever else is pending. When no single pending request can be
|
|
92
|
-
shown, because nothing is pending, the code is unknown, or several candidates exist, it names the
|
|
93
|
-
live pending codes and stops instead of asking. Answering anything but `y` or `yes` cancels the
|
|
94
|
-
approval, reports `PAIRING_DECLINED` and exits 1, the same code and exit the bare `auth` wait
|
|
95
|
-
reports for a declined request; the wait also denies the request outright, while this verb leaves
|
|
96
|
-
it pending. Interrupting the prompt also leaves the request pending, and reports
|
|
97
|
-
`PAIRING_PROMPT_ABORTED` with exit 1 on the same terms as the wait. Scripts must pass `--yes`.
|
|
98
|
-
The stored label is the one the browser sent; approval does not rename it.
|
|
99
|
-
- `auth deny <code>` rejects a pending request.
|
|
100
|
-
- `auth list` shows non-secret profile metadata, including each profile's `clientId` and `label`.
|
|
101
|
-
A label is set in the browser at pairing time and no control operation renames a stored record, so
|
|
102
|
-
a browser that needs a different label unpairs and pairs again. A browser that only forgot its local
|
|
103
|
-
credential keeps its record, and the next approval adopts the label that request carried. Labels are
|
|
104
|
-
not unique, so two browsers may share one. A profile's `lastSeenAt` is stamped when it is approved,
|
|
105
|
-
when its browser connects the bridge, when that connection ends, and when a hello is turned away
|
|
106
|
-
because another profile owns the slot, so the timestamp measures how long the profile has been idle
|
|
107
|
-
rather than how long ago it last connected. A second browser that is opened daily while the first
|
|
108
|
-
one holds the bridge therefore stays fresh and is never pruned out from under its owner.
|
|
109
|
-
- `auth prune [--older-than <days>] [--yes]` deletes the profiles that have gone unused. A profile is
|
|
110
|
-
a candidate when its `lastSeenAt` is older than the cutoff, which defaults to 30 days; the active
|
|
111
|
-
bridge profile and the holder of an abnormal-disconnect lease are never deleted, however idle their
|
|
112
|
-
stored timestamp looks. Interactive use lists the candidates it found, with label, client id,
|
|
113
|
-
world, GM, last-seen timestamp, and pairing id, and asks once for the whole set. The listing
|
|
114
|
-
skips the profile `auth list` reports as active, so a browser that has stayed connected past the
|
|
115
|
-
cutoff is neither shown nor counted in the prompt, matching what the daemon will do. Answering
|
|
116
|
-
anything but `y` or `yes` removes nothing, reports `PAIRING_DECLINED` and exits 1; interrupting the prompt reports
|
|
117
|
-
`PAIRING_PROMPT_ABORTED` and exits 1 on the same terms as `auth approve`. A listing that found no
|
|
118
|
-
candidate asks nothing and still runs the operation, so the command's output is the daemon's own empty
|
|
119
|
-
result rather than a local verdict. The listing is a preview only: the daemon recomputes the set,
|
|
120
|
-
against the cutoff as it stands when the command runs, and its own result is what the command prints.
|
|
121
|
-
The executed set can therefore be larger than the one the prompt counted, because a profile that
|
|
122
|
-
crossed the cutoff while the prompt waited is removed although it was never listed; it can equally be
|
|
123
|
-
smaller, because a profile that became active or was already removed between the two steps is
|
|
124
|
-
reported as the daemon left it. There is no dry-run mode, and `--older-than 0` treats every profile
|
|
125
|
-
as idle, which is the one case where a preview can name a lease holder the daemon then keeps.
|
|
126
|
-
`auth list` does not expose the lease, and a lease holder's last-seen timestamp is fresh by
|
|
127
|
-
definition, so no realistic threshold selects it. Scripts pass `--yes`, which skips both the preview
|
|
128
|
-
and the prompt; `--json` requires `--yes` as well, because the confirmation is never mixed into JSON
|
|
129
|
-
output, and without it the command stops with exit 2.
|
|
130
|
-
- `auth revoke <pairingId>` deletes one daemon profile and disconnects it if active.
|
|
131
|
-
- `auth rotate-client --yes` replaces the device-local CLI/Companion credential and closes existing
|
|
132
|
-
local-client sockets without invalidating browser pairings.
|
|
133
|
-
- `bridge release` clears the active slot or abnormal-disconnect lease without deleting a profile.
|
|
134
|
-
An active browser stopped by release stays stopped until its operator chooses Connect.
|
|
135
|
-
|
|
136
|
-
Every command in this section is answered by the daemon alone, with no Foundry browser involved, so
|
|
137
|
-
a daemon that is not running or not reachable ends any of them, the `auth` verbs and
|
|
138
|
-
`bridge release` alike, with `DAEMON_UNAVAILABLE` and exit 3 rather than a command-level failure.
|
|
139
|
-
|
|
140
|
-
In Foundry, Connect reuses the stored browser credential and Disconnect releases the slot without
|
|
141
|
-
touching it. Unpair waits for confirmed daemon revocation
|
|
142
|
-
before deleting that credential. If revocation cannot be confirmed, it retains the credential and
|
|
143
|
-
offers Forget local as the explicit recovery path; Forget local does not revoke the daemon profile.
|
|
144
|
-
`BRIDGE_BUSY` likewise preserves the credential: release the current bridge and choose Connect.
|
|
145
|
-
|
|
146
|
-
### Local configuration
|
|
147
|
-
|
|
148
|
-
- `config get` shows the config path and non-secret settings.
|
|
149
|
-
- `config set-upload-limit <size>` persists the raw upload-byte limit. The daemon preserves this
|
|
150
|
-
field across later pairing and bridge-session writes, but a running daemon must be restarted before
|
|
151
|
-
its WebSocket transport and the browser bridge advertise the new limit. JSON output includes
|
|
152
|
-
`daemonRestartRequired: true`.
|
|
153
|
-
|
|
154
|
-
## Finding the right command
|
|
155
|
-
|
|
156
|
-
Command names describe the document nesting. Dots are used in the protocol registry; spaces are used
|
|
157
|
-
on the CLI:
|
|
66
|
+
### Send a batch of commands
|
|
158
67
|
|
|
159
|
-
|
|
160
|
-
|---|---|---|
|
|
161
|
-
| World actors | `actor.*` | `fvtt-world-cli actor …` |
|
|
162
|
-
| Items embedded in an actor | `actor.item.*` | `fvtt-world-cli actor item …` |
|
|
163
|
-
| Effects on an actor item | `actor.item.effect.*` | `fvtt-world-cli actor item effect …` |
|
|
164
|
-
| Tokens embedded in a scene | `scene.token.*` | `fvtt-world-cli scene token …` |
|
|
165
|
-
| Effects on a placed token | `scene.token.effect.*` | `fvtt-world-cli scene token effect …` |
|
|
68
|
+
Save these lines as `requests.ndjson`:
|
|
166
69
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
## Capability map
|
|
173
|
-
|
|
174
|
-
### World content
|
|
175
|
-
|
|
176
|
-
- `actor`, `item`, `journal`, `scene`, `macro`, `playlist`, `table`, and `cards` manage world
|
|
177
|
-
documents.
|
|
178
|
-
- `chat` reads, creates, and deletes chat messages. `chat flush` erases the entire log at once and
|
|
179
|
-
asks for GM approval by default because nothing brings the messages back.
|
|
180
|
-
- `user` manages Foundry user accounts. `user update` edits harmless profile fields, `user create`
|
|
181
|
-
and `user delete` ask for approval by default, and `user role set` plus `user permissions set` are
|
|
182
|
-
[off by default](#commands-that-are-off-by-default). No command reads or writes a password, and
|
|
183
|
-
the account holding the bridge cannot demote or delete itself; see
|
|
184
|
-
[Security](security.md#users).
|
|
185
|
-
- `setting` lists registrations and reads values, including `setting get-many` for batch reads.
|
|
186
|
-
`setting set` and `setting set-many` write world, client, and user scopes but are
|
|
187
|
-
[off by default](#commands-that-are-off-by-default); they refuse this module's own namespace in
|
|
188
|
-
every mode, and a write to an already-stored value is reported as unchanged without touching
|
|
189
|
-
Foundry. The result's `value` is the value read back after the write, not the value requested: a
|
|
190
|
-
setting's registered type or `onChange` handler may normalize or clamp what was asked for, so
|
|
191
|
-
compare `value` against the requested input when the exact stored form matters. The write is
|
|
192
|
-
confirmed only in that Foundry no longer holds the `previous` value. A result carrying
|
|
193
|
-
`requiresReload: true` names the follow-up that Foundry expects, which `system reload` performs.
|
|
194
|
-
- `combat` manages encounters and exposes explicit encounter transitions.
|
|
195
|
-
- `folder` manages document organization.
|
|
196
|
-
- Dedicated `*.ownership.set` commands change supported document ownership.
|
|
197
|
-
|
|
198
|
-
Common world-document operations include `list`, `get`, `get-many`, `create`, `update`, `clone`, and
|
|
199
|
-
`delete`. The exact set varies by family.
|
|
200
|
-
|
|
201
|
-
### Embedded content
|
|
202
|
-
|
|
203
|
-
- `actor.item` manages an actor's embedded items.
|
|
204
|
-
- `*.effect` families manage ActiveEffects on actors, items, actor items, tokens, and token items.
|
|
205
|
-
- `journal.category` manages journal page categories.
|
|
206
|
-
- `playlist.sound` manages playlist tracks.
|
|
207
|
-
- `table.result` manages roll-table rows.
|
|
208
|
-
- `cards.card` manages cards inside a stack.
|
|
209
|
-
- `combat.combatant` and `combat.group` manage encounter membership.
|
|
210
|
-
- `scene.token`, `tile`, `sound`, `wall`, `note`, `drawing`, `light`, `template`, and `region` manage
|
|
211
|
-
scene placeables.
|
|
212
|
-
- `scene.region.behavior` manages region behaviors; writes that supply executable core behavior
|
|
213
|
-
types are rejected (see [Security](security.md#executable-content)). The separate
|
|
214
|
-
`scene.region.behavior.executable` family, [off by default](#commands-that-are-off-by-default),
|
|
215
|
-
authors `executeMacro` behaviors that reference an existing world macro; `executeScript` has no
|
|
216
|
-
command surface at all. Deleting an executable behavior uses the ordinary
|
|
217
|
-
`scene region behavior delete`.
|
|
218
|
-
|
|
219
|
-
Embedded commands require the complete parent ID chain; a read of the parent supplies those IDs when
|
|
220
|
-
they are not already known.
|
|
70
|
+
```jsonl
|
|
71
|
+
{"id":"check-bridge","command":"system.ping","params":{}}
|
|
72
|
+
{"id":"inspect-world","command":"system.info","params":{}}
|
|
73
|
+
```
|
|
221
74
|
|
|
222
|
-
|
|
75
|
+
```bash
|
|
76
|
+
fvtt-world-cli exec --stdin < requests.ndjson
|
|
77
|
+
```
|
|
223
78
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
- roll-table draw and reset;
|
|
228
|
-
- card shuffle, reset, deal, draw, and pass;
|
|
229
|
-
- combat start, activation, advancement, and initiative;
|
|
230
|
-
- scene thumbnail generation and fog reset;
|
|
231
|
-
- scene activation (`scene activate`) and pulling active users to a scene (`scene pull-users`);
|
|
232
|
-
- showing a journal entry (`journal show`) or an image (`image show`) to players;
|
|
233
|
-
- pausing or resuming the game clock for everyone (`game pause`);
|
|
234
|
-
- reloading the GM client (`system reload`), which asks for approval by default because it drops
|
|
235
|
-
the bridge until the client reconnects;
|
|
236
|
-
- macro execution (`macro execute`), [off by default](#commands-that-are-off-by-default).
|
|
237
|
-
|
|
238
|
-
`scene pull-users`, `journal show`, and `image show` reach every connected player when no
|
|
239
|
-
`--user-ids` list is given. A supplied list has to name at least one user: an empty one is
|
|
240
|
-
indistinguishable from "everyone" on the Foundry side, while the result would report that nobody was
|
|
241
|
-
addressed.
|
|
242
|
-
|
|
243
|
-
`macro execute` runs a world macro the GM can already execute, waits for it to finish up to a
|
|
244
|
-
bounded `--macro-timeout-ms`, and reports the returned value plus the chat messages it observed the
|
|
245
|
-
macro create. A macro that outlives the timeout keeps running in the GM browser and the command
|
|
246
|
-
returns the indeterminate `MACRO_TIMEOUT`, so the effect is verified by reads. A script macro that
|
|
247
|
-
throws fails the command and the error names what the macro raised; the outcome is partial, because
|
|
248
|
-
whatever the macro changed before it threw stays changed. A macro that catches its own errors still
|
|
249
|
-
reports a `null` return, and a macro is free to reload the page or navigate away, which ends the
|
|
250
|
-
bridge session the same way any disconnect does. Effects therefore deserve a read-back whenever the
|
|
251
|
-
return value alone does not prove them.
|
|
252
|
-
|
|
253
|
-
Each key of `--args-json` becomes a named variable Foundry splices into the compiled macro, so an
|
|
254
|
-
argument name must be a plain JavaScript identifier (letters, digits, `_` or `$`, not starting with
|
|
255
|
-
a digit) and cannot reuse a name Foundry already binds (`speaker`, `actor`, `token`, `character`,
|
|
256
|
-
`scope`). Any other name is refused before the macro runs.
|
|
257
|
-
|
|
258
|
-
The result's `chatCapture` field says how much of the chat the run observed: `captured` when every
|
|
259
|
-
message the macro was expected to create was seen, `not-created` when a chat macro created none,
|
|
260
|
-
`partial` when only some were seen, and `unknown` when this client could not watch the chat log at
|
|
261
|
-
all.
|
|
262
|
-
|
|
263
|
-
Actions can have Foundry, system, or module side effects. Their result describes what the bridge can
|
|
264
|
-
confirm, which may differ from a document post-state, so each action's schema and help are worth
|
|
265
|
-
reading before automating it.
|
|
266
|
-
|
|
267
|
-
### Discovery and maintenance
|
|
268
|
-
|
|
269
|
-
- `world.search` finds content across supported world and optional compendium indexes.
|
|
270
|
-
- `world.audit-files` finds document references to missing managed assets.
|
|
271
|
-
- `compendium.list`, `compendium.index`, and `compendium.get` read pack content.
|
|
272
|
-
- Supported `*.import-from-compendium` commands create world documents from pack sources.
|
|
273
|
-
- `user list`/`user get` and `setting list`/`setting get`/`setting get-many` are the discovery
|
|
274
|
-
side of the [user and setting families](#world-content).
|
|
275
|
-
|
|
276
|
-
### Managed files
|
|
277
|
-
|
|
278
|
-
`file` commands operate on Foundry's managed `data` source. Reads can inspect managed assets. Writes
|
|
279
|
-
are restricted to the active world's allowed tree and exclude its manifest, databases, and packs.
|
|
280
|
-
Document references are updated separately with an explicit document command.
|
|
281
|
-
|
|
282
|
-
See [Security](security.md#file-write-boundary) before automating file writes.
|
|
79
|
+
Requests run in order. Output is NDJSON, with the supplied `id` and zero-based line `index` on each
|
|
80
|
+
response. Failures do not stop later requests unless you pass `--stop-on-error`; any failure makes
|
|
81
|
+
the process exit non-zero.
|
|
283
82
|
|
|
284
83
|
## Shared command behavior
|
|
285
84
|
|
|
286
85
|
### Command permissions and approval
|
|
287
86
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
An approved command waits for the GM instead of failing. Foundry opens the Command Approval window.
|
|
294
|
-
It shows the command, its targets, and its parameters. The CLI writes one status line to stderr:
|
|
87
|
+
Set allow, approve, or deny under Configure Settings → Module Settings → World CLI → Command
|
|
88
|
+
permissions. The policy belongs to the browser profile holding the bridge. The window shows every
|
|
89
|
+
command, including those hidden from CLI discovery. See [Security](security.md#permissions-and-destructive-actions)
|
|
90
|
+
for default permissions and review limits.
|
|
295
91
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
92
|
+
When approval is required, the CLI waits for the GM to answer Foundry's Command Approval window.
|
|
93
|
+
Its waiting message goes to stderr, leaving stdout for JSON results.
|
|
94
|
+
The *Approval timeout (minutes)* setting controls the deadline.
|
|
299
95
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
success or error.
|
|
304
|
-
|
|
305
|
-
The wait tolerates short daemon outages, bridge reconnects, and poll timeouts while the approval
|
|
306
|
-
remains open. Other outcomes use structured errors:
|
|
307
|
-
|
|
308
|
-
| Code | Meaning | State |
|
|
309
|
-
|---|---|---|
|
|
310
|
-
| `COMMAND_DENIED` | The permission is deny, whether at the request or by the time an approved command runs | Not executed |
|
|
311
|
-
| `APPROVAL_DENIED` | The GM chose Deny | Not executed |
|
|
312
|
-
| `APPROVAL_TIMEOUT` | No decision was taken before the approval expired | Not executed |
|
|
313
|
-
| `APPROVAL_CANCELLED` | A cancellation the GM client confirmed won the decision | Not executed |
|
|
314
|
-
| `APPROVAL_QUEUE_FULL` | The module refused admission before showing the request | Not executed |
|
|
315
|
-
| `APPROVAL_UNKNOWN` | The module no longer holds the decision | Indeterminate |
|
|
316
|
-
|
|
317
|
-
`APPROVAL_UNKNOWN` means the client can no longer prove whether the command ran. Read the affected
|
|
318
|
-
world state before trying again. `APPROVAL_QUEUE_FULL` means the module refused the request before
|
|
319
|
-
execution. Retry after the GM clears earlier requests.
|
|
320
|
-
|
|
321
|
-
Ctrl+C asks the GM client to cancel a waiting decision. Only `APPROVAL_CANCELLED` proves that the
|
|
322
|
-
command will not run. If the command has started or the client cannot confirm cancellation, the CLI
|
|
323
|
-
reports an indeterminate result.
|
|
324
|
-
|
|
325
|
-
The default policy sorts commands into the three behaviors by what a mistake would cost. Commands
|
|
326
|
-
that can execute code, change who can do what, or persist outside the world's own data are denied
|
|
327
|
-
until a human enables them; the next section lists them. Commands that destroy world data ask for
|
|
328
|
-
approval, as do `system.reload` and `user.create`; the destructive set is the `delete` and
|
|
329
|
-
`delete-many` verbs, plus `file.move`, `scene.fog.reset`, and `chat.flush`. The remaining commands
|
|
330
|
-
run on their own unless they are exempt from the policy. The Command permissions window and
|
|
331
|
-
`fvtt-world-cli commands --json` show the current inventory.
|
|
96
|
+
Ctrl+C requests cancellation. Only `APPROVAL_CANCELLED` proves it succeeded. If execution has
|
|
97
|
+
started or cancellation cannot be confirmed, inspect world state before retrying.
|
|
98
|
+
[Protocol](protocol.md#delivery-states-and-retries) lists the outcomes and safe next actions.
|
|
332
99
|
|
|
333
100
|
#### Commands that are off by default
|
|
334
101
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
102
|
+
These commands ship with the deny behavior: hidden from discovery and refused, even as dry runs,
|
|
103
|
+
until a GM enables them in the Command permissions window. Each one executes code, changes who can
|
|
104
|
+
do what, or persists outside the world's own data. Approve is the middle ground: a GM who wants to
|
|
105
|
+
review every macro body before it runs sets `macro.execute` to approve rather than allow.
|
|
338
106
|
|
|
339
107
|
- `macro.execute`
|
|
340
108
|
- `setting.set`
|
|
@@ -345,184 +113,138 @@ them in the Command permissions window of the browser profile holding the bridge
|
|
|
345
113
|
- `scene.region.behavior.executable.update`
|
|
346
114
|
- `scene.region.behavior.executable.clone`
|
|
347
115
|
|
|
348
|
-
They are denied by default because each one executes code, changes who can do what, or persists
|
|
349
|
-
outside the world's own data. Enabling one is a per-browser-profile decision, and the approval
|
|
350
|
-
behavior remains available as a middle ground: a GM who wants to see every macro body before it
|
|
351
|
-
runs sets `macro.execute` to approve rather than allow. [Security](security.md) describes what each
|
|
352
|
-
of these surfaces can and cannot do.
|
|
353
|
-
|
|
354
|
-
`system.ping`, `system.info`, and the internal approval-wait commands always run. This keeps the
|
|
355
|
-
bridge able to report its state and finish an existing decision. The permissions window omits those
|
|
356
|
-
commands. Pairing and other `auth` operations run in the daemon, outside the command policy.
|
|
357
|
-
|
|
358
|
-
Foundry plays its standard interface notification when a request enters an empty queue. The `Play a
|
|
359
|
-
sound on approval requests` setting controls it. Browsers may delay the first sound until the GM
|
|
360
|
-
interacts with the page after a reload.
|
|
361
|
-
|
|
362
|
-
Set the approval deadline with `Approval timeout (minutes)` in the main Module Settings form. The
|
|
363
|
-
form and protocol enforce the supported range. Expiry refuses the command without running it.
|
|
364
|
-
|
|
365
|
-
Approval state lives in the GM client's memory. Reloading that client or ending its bridge session
|
|
366
|
-
can produce `BRIDGE_DISCONNECTED` or `APPROVAL_UNKNOWN`. Both are indeterminate. Read the affected
|
|
367
|
-
world state before another write, then use a fresh idempotency key if the command still needs to run.
|
|
368
|
-
The complete state and retry contract is in [Protocol](protocol.md#approval-flow).
|
|
369
|
-
|
|
370
|
-
### Discovery under a policy
|
|
371
|
-
|
|
372
|
-
With the bridge reachable, `commands` and `commands --json` describe what that GM client will
|
|
373
|
-
actually run. The listing omits denied commands. JSON marks approval waits with `"approval": true`;
|
|
374
|
-
plain output uses an `approval` tag. The JSON envelope also contains
|
|
375
|
-
`policy: { "applied": true, "source": "bridge" }`.
|
|
376
|
-
|
|
377
|
-
When no bridge answers, the listing falls back to the full static registry and says so:
|
|
378
|
-
`policy: { "applied": false, "source": "static", "reason": … }` in JSON, and a warning on stderr in
|
|
379
|
-
plain output. Only an unavailable daemon or bridge triggers fallback. Authentication, validation,
|
|
380
|
-
and protocol failures return errors.
|
|
381
|
-
|
|
382
|
-
`schema`, `--help`, and this documentation describe the whole static registry. If a caller sends a
|
|
383
|
-
denied command found there, the GM client returns `COMMAND_DENIED`. Discovery hides; the client
|
|
384
|
-
enforces.
|
|
385
|
-
|
|
386
116
|
### JSON output
|
|
387
117
|
|
|
388
|
-
Use `--json` for automation.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
{
|
|
392
|
-
"protocolVersion": "…",
|
|
393
|
-
"type": "command.response",
|
|
394
|
-
"id": "…",
|
|
395
|
-
"ok": true,
|
|
396
|
-
"result": {
|
|
397
|
-
"actor": {}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
```
|
|
118
|
+
Use `--json` for automation. World commands return `ok: true` with `result`, or `ok: false` with
|
|
119
|
+
an `error` containing a code, message, and optional details. Failures exit non-zero. Branch on
|
|
120
|
+
`error.code`, not the message text. See the [response examples](protocol.md#request-and-response-example).
|
|
401
121
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
against. Errors use `ok: false`, a stable code, a
|
|
405
|
-
message, and optional details; see [Protocol](protocol.md#error-model).
|
|
122
|
+
Results use command-specific keys such as `actor`, `items`, or `outcomes`. Use returned document
|
|
123
|
+
`id` fields to address later commands.
|
|
406
124
|
|
|
407
|
-
|
|
408
|
-
source `_id` mirror. Use the documented `id` fields for subsequent commands.
|
|
125
|
+
### Reading collections and documents
|
|
409
126
|
|
|
410
|
-
|
|
127
|
+
Paginated commands accept `--limit` and `--offset`. Continue until the response's `hasMore` is false;
|
|
128
|
+
`total` describes the matching collection. Supported filters apply before pagination.
|
|
411
129
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
extensible data.
|
|
130
|
+
List rows contain fewer fields than `get` results. Read the target with `get` before preparing an
|
|
131
|
+
update. Reads return authored state; some commands accept `include` options for derived or expensive
|
|
132
|
+
data. Check the command's help for available projections and filters.
|
|
416
133
|
|
|
417
|
-
|
|
418
|
-
values. The command schema is the definitive description of accepted keys.
|
|
134
|
+
### Updates and merge semantics
|
|
419
135
|
|
|
420
|
-
|
|
136
|
+
Use JSON flags such as `--data-json` and `--patch-json` for structured values. Updates are patches:
|
|
421
137
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
138
|
+
- Nested objects merge recursively.
|
|
139
|
+
- Ordinary arrays replace as a whole.
|
|
140
|
+
- Dotted paths target object properties where permitted; dotted writes inside arrays are refused.
|
|
141
|
+
- Foundry deletion syntax can remove permitted nested keys.
|
|
142
|
+
- Embedded collections follow their family's Foundry semantics.
|
|
425
143
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
144
|
+
Read arrays before editing and preserve unchanged values. For a wall's `c` field, send the complete
|
|
145
|
+
`[x1, y1, x2, y2]`, not `c.0`. Invalid or ambiguous patch shapes return `INVALID_PARAMS` before
|
|
146
|
+
mutation, including in bulk writes and dry runs. Correct the fields identified by the error.
|
|
429
147
|
|
|
430
|
-
|
|
148
|
+
Prefer dedicated commands for creating embedded documents. A parent update that adds entries
|
|
149
|
+
without `_id`, such as new `behaviors` in `scene.region.update`, can create them but return an
|
|
150
|
+
indeterminate error. Inspect the collection before retrying to avoid duplicates.
|
|
431
151
|
|
|
432
|
-
|
|
433
|
-
`include` values for derived or expensive data. Derived data is explicitly identified and can vary by
|
|
434
|
-
Foundry version and game system.
|
|
152
|
+
### Dry run
|
|
435
153
|
|
|
436
|
-
|
|
437
|
-
|
|
154
|
+
The global `--dry-run` flag validates and prepares a mutation without writing. Results include
|
|
155
|
+
`dryRun: true`. A preview cannot predict execution-dependent effects or reserve world state.
|
|
438
156
|
|
|
439
|
-
|
|
157
|
+
Previews skip approval and report `approvalRequired: true` if the real command would wait.
|
|
158
|
+
Denied commands remain denied in previews.
|
|
440
159
|
|
|
441
|
-
|
|
160
|
+
### Failures and retries
|
|
442
161
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
- Foundry deletion syntax can remove permitted nested keys;
|
|
447
|
-
- embedded-document collections follow their family-specific Foundry semantics.
|
|
162
|
+
A timeout or disconnect can happen after a write commits. An update error with `details.partial`
|
|
163
|
+
or `details.indeterminate` can also mean that some changes persisted. Read affected state before
|
|
164
|
+
retrying and send only what remains to be done.
|
|
448
165
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
166
|
+
An idempotency key identifies one logical request and can prevent duplicate effects while its
|
|
167
|
+
cached state survives. Reuse it only for the same request; a corrected or remaining patch is a
|
|
168
|
+
new operation and needs a fresh key. Follow the [delivery rules](protocol.md#delivery-states-and-retries)
|
|
169
|
+
when a connection fails, since some failures also lose the cached state.
|
|
452
170
|
|
|
453
|
-
|
|
171
|
+
Bulk writes are not transactions. Inspect `complete` and every entry in `outcomes` before deciding
|
|
172
|
+
what to retry.
|
|
454
173
|
|
|
455
|
-
|
|
174
|
+
### Actions
|
|
456
175
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
176
|
+
`scene pull-users`, `journal show`, and `image show` target every connected player when
|
|
177
|
+
`--user-ids` is omitted. Supply a non-empty list to select players. Their results confirm dispatch,
|
|
178
|
+
not that a player saw the content.
|
|
460
179
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
180
|
+
`macro execute` can leave effects behind after an error, and `MACRO_TIMEOUT` does not stop the
|
|
181
|
+
macro. Verify affected state before retrying. See [Executable content](security.md#executable-content)
|
|
182
|
+
before enabling macro execution or executable region behaviors.
|
|
464
183
|
|
|
465
|
-
|
|
466
|
-
GM, and its result carries `approvalRequired: true` so the caller knows the commit will wait. The GM
|
|
467
|
-
client returns `COMMAND_DENIED` for a denied preview.
|
|
184
|
+
### File paths
|
|
468
185
|
|
|
469
|
-
|
|
186
|
+
File commands use Foundry's managed `data` source. Writes belong under `worlds/<worldId>/` and
|
|
187
|
+
exclude the world's manifest, databases, and packs. Supply literal paths, without pre-encoding
|
|
188
|
+
filename characters. Change document references separately after a file operation.
|
|
189
|
+
See [File write boundary](security.md#file-write-boundary) for the exact restrictions.
|
|
470
190
|
|
|
471
|
-
|
|
472
|
-
key. An operation that timed out or disconnected may already have reached Foundry, so a blind retry
|
|
473
|
-
can apply it twice. Key semantics and delivery-state retry rules are defined in
|
|
474
|
-
[Protocol](protocol.md#idempotency) and
|
|
475
|
-
[Protocol](protocol.md#delivery-states-and-retries).
|
|
191
|
+
## Authorization commands
|
|
476
192
|
|
|
477
|
-
|
|
193
|
+
These commands require the daemon but no open Foundry browser. Prefix the commands below with
|
|
194
|
+
`fvtt-world-cli`.
|
|
478
195
|
|
|
479
|
-
|
|
480
|
-
connection while retaining an individual response for each request.
|
|
196
|
+
### Wait for pairing
|
|
481
197
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
198
|
+
`auth` waits for the earliest pending pairing request and displays its identity. Start it before
|
|
199
|
+
or after clicking *Pair* in Foundry. `y` or `yes` approves; any other answer denies that request.
|
|
200
|
+
Ctrl+C or ended input during the prompt leaves it pending.
|
|
485
201
|
|
|
486
|
-
|
|
202
|
+
The wait has no overall deadline; `--timeout-ms` does not set one. If the daemon becomes unavailable,
|
|
203
|
+
restart `auth` after restoring it. Bare `auth` requires an interactive terminal. Scripts should
|
|
204
|
+
inspect `auth pending`, then use `auth approve <code> --yes` for the selected request.
|
|
487
205
|
|
|
488
|
-
|
|
489
|
-
appropriate; callers should not pre-encode ordinary filename characters. URLs, virtual texture IDs,
|
|
490
|
-
and other special values follow the receiving field's schema.
|
|
206
|
+
### Manage pairings and connections
|
|
491
207
|
|
|
492
|
-
|
|
208
|
+
| Command | Effect |
|
|
209
|
+
|---|---|
|
|
210
|
+
| `auth status` | Show bridge state and public profile metadata |
|
|
211
|
+
| `auth pending` | List pending codes, expiry, and browser/world/GM identity |
|
|
212
|
+
| `auth approve [code] [--yes]` | Approve a selected request; omit the code only when exactly one is pending |
|
|
213
|
+
| `auth deny <code>` | Reject a pending request |
|
|
214
|
+
| `auth list` | List paired browsers and their last-seen times |
|
|
215
|
+
| `auth prune [--older-than <days>] [--yes]` | Remove idle pairings, defaulting to 30 days |
|
|
216
|
+
| `auth revoke <pairingId>` | Delete a pairing and disconnect it if active |
|
|
217
|
+
| `auth rotate-client --yes` | Replace the local CLI credential and close local-client sockets; browser pairings remain valid |
|
|
218
|
+
| `bridge release` | Free the active slot or reconnect lease without deleting its pairing |
|
|
493
219
|
|
|
494
|
-
|
|
220
|
+
Interactive `auth approve` always acts on the request it displayed. If that request expires,
|
|
221
|
+
it fails without choosing another. A negative answer leaves the request pending, unlike bare
|
|
222
|
+
`auth`, which denies it. Scripts must pass `--yes`.
|
|
495
223
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
fvtt-world-cli actor update --actor-id <id> --name "Goblin Scout" --json
|
|
501
|
-
fvtt-world-cli actor get --actor-id <id> --json
|
|
502
|
-
```
|
|
224
|
+
Browser labels need not be unique; use client ids to distinguish them. To rename a browser,
|
|
225
|
+
unpair and pair again. *Disconnect* preserves its pairing. *Unpair* revokes it, while *Forget local*
|
|
226
|
+
only deletes the browser's credential. After `bridge release`, the released browser stays stopped
|
|
227
|
+
until its operator chooses *Connect*.
|
|
503
228
|
|
|
504
|
-
###
|
|
229
|
+
### Pruning idle pairings
|
|
505
230
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
231
|
+
`auth prune` uses `lastSeenAt` to find idle pairings and protects the active bridge and any holder
|
|
232
|
+
of a reconnect lease. Interactive use lists candidates and asks once before removal. The daemon
|
|
233
|
+
recomputes candidates when the command runs, so a pairing that crosses the cutoff while the
|
|
234
|
+
prompt waits can be removed even if it was not listed. Use `auth revoke <pairingId>` to remove
|
|
235
|
+
only a specific profile.
|
|
511
236
|
|
|
512
|
-
|
|
237
|
+
There is no dry run. `--older-than 0` selects all idle pairings, subject to active-bridge and
|
|
238
|
+
lease protection. An empty initial listing skips the prompt but still runs the prune operation.
|
|
239
|
+
For scripts and JSON output, pass `--yes` to skip the listing and prompt.
|
|
513
240
|
|
|
514
|
-
|
|
515
|
-
fvtt-world-cli scene token list --scene-id <sceneId> --json
|
|
516
|
-
fvtt-world-cli scene token get --scene-id <sceneId> --token-id <tokenId> --json
|
|
517
|
-
```
|
|
241
|
+
## Local configuration
|
|
518
242
|
|
|
519
|
-
|
|
243
|
+
`config get` shows the config path and non-secret settings. `config set-upload-limit <size>`
|
|
244
|
+
changes the raw upload-byte limit; restart the daemon for it to take effect.
|
|
520
245
|
|
|
521
|
-
|
|
246
|
+
If set, `XDG_CONFIG_HOME` places configuration under `$XDG_CONFIG_HOME/fvtt-world-cli`. Otherwise:
|
|
522
247
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
default; when a GM keeps them on approve, the window shows a macro execution's own body and names
|
|
527
|
-
the macro a region behavior would run. [Security](security.md) describes the trust
|
|
528
|
-
boundary and [Foundry compatibility](compatibility.md) the version-dependent capabilities.
|
|
248
|
+
- Linux: `~/.config/fvtt-world-cli`.
|
|
249
|
+
- macOS: `~/Library/Application Support/fvtt-world-cli`.
|
|
250
|
+
- Windows: `%APPDATA%\fvtt-world-cli`.
|