fvtt-world-cli 1.1.2 → 1.2.1
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/dist/index.js +554 -178
- package/docs/commands.md +43 -7
- package/docs/compatibility.md +3 -0
- package/docs/protocol.md +37 -12
- package/package.json +2 -2
- package/skills/foundry-world-editor/SKILL.md +24 -9
- package/skills/foundry-world-editor/SKILL.md.sha256 +1 -1
package/docs/commands.md
CHANGED
|
@@ -17,8 +17,9 @@ becomes `scene token get`. Nested commands require the parent IDs as well as the
|
|
|
17
17
|
|
|
18
18
|
With a bridge connected, discovery omits denied commands and marks approval requirements with
|
|
19
19
|
`approval: true`. If the daemon or bridge is unavailable, it returns the static registry with
|
|
20
|
-
`policy.applied: false
|
|
21
|
-
`schema` and `--help` always
|
|
20
|
+
`policy.applied: false`; `policy` sits at the top level of the response, beside `result`.
|
|
21
|
+
Authentication and protocol errors do not trigger that fallback. `schema` and `--help` always
|
|
22
|
+
describe the static registry, including denied commands.
|
|
22
23
|
|
|
23
24
|
## Capability map
|
|
24
25
|
|
|
@@ -29,6 +30,7 @@ Use these families to narrow your search, then check their help for supported op
|
|
|
29
30
|
| Edit world content | `actor`, `item`, `journal`, `scene`, `macro`, `playlist`, `table`, `cards` |
|
|
30
31
|
| Edit embedded content | Nested families such as `actor.item`, `playlist.sound`, `table.result`, and `*.effect` |
|
|
31
32
|
| Edit scene placeables | `scene.token`, `scene.wall`, `scene.region`, and related families |
|
|
33
|
+
| Edit scene levels (v14) | `scene.level` |
|
|
32
34
|
| Manage encounters | `combat`, `combat.combatant`, `combat.group` |
|
|
33
35
|
| Organize content and access | `folder`, `*.ownership.set`, `user` |
|
|
34
36
|
| Manage chat and settings | `chat`, `setting` |
|
|
@@ -63,6 +65,29 @@ fvtt-world-cli scene token list --scene-id <sceneId> --json
|
|
|
63
65
|
fvtt-world-cli scene token get --scene-id <sceneId> --token-id <tokenId> --json
|
|
64
66
|
```
|
|
65
67
|
|
|
68
|
+
### Build a scene with levels
|
|
69
|
+
|
|
70
|
+
On Foundry v14 a scene's maps live on its levels. Pass the levels when you create the scene:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
fvtt-world-cli scene create --name "Tower" --json \
|
|
74
|
+
--data-json '{"levels":[{"name":"Ground","background":{"src":"worlds/<worldId>/maps/ground.webp"}},
|
|
75
|
+
{"name":"Roof","elevation":{"bottom":20,"top":40}}]}'
|
|
76
|
+
fvtt-world-cli scene level list --scene-id <sceneId> --json
|
|
77
|
+
fvtt-world-cli scene level update --scene-id <sceneId> --level-id <levelId> \
|
|
78
|
+
--patch-json '{"foreground":{"src":"worlds/<worldId>/maps/roof.webp"}}' --json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The first supplied level becomes the initial one. To start players on another level, run `scene
|
|
82
|
+
update --scene-id <sceneId> --initial-level <levelId>`; `--patch-json '{"initialLevel":null}'` goes
|
|
83
|
+
back to the first level. A scene keeps at least one level, so `scene level delete` and `delete-many`
|
|
84
|
+
refuse to remove the last one.
|
|
85
|
+
|
|
86
|
+
Deleting a level also deletes its tokens and every placeable that exists only on that level. A dry
|
|
87
|
+
run does not list them, so read the scene's placeables before deleting a level.
|
|
88
|
+
|
|
89
|
+
[Compatibility](compatibility.md) lists the scene map fields each Foundry version accepts.
|
|
90
|
+
|
|
66
91
|
### Send a batch of commands
|
|
67
92
|
|
|
68
93
|
Save these lines as `requests.ndjson`:
|
|
@@ -131,19 +156,24 @@ List rows contain fewer fields than `get` results. Read the target with `get` be
|
|
|
131
156
|
update. Reads return authored state; some commands accept `include` options for derived or expensive
|
|
132
157
|
data. Check the command's help for available projections and filters.
|
|
133
158
|
|
|
159
|
+
Actor results carry `itemCount` in place of the owned items; `actor get` and `actor get-many`
|
|
160
|
+
return the items with `--include items`. `system info --include modules` lists installed modules.
|
|
161
|
+
|
|
134
162
|
### Updates and merge semantics
|
|
135
163
|
|
|
136
164
|
Use JSON flags such as `--data-json` and `--patch-json` for structured values. Updates are patches:
|
|
137
165
|
|
|
138
166
|
- Nested objects merge recursively.
|
|
139
167
|
- Ordinary arrays replace as a whole.
|
|
140
|
-
- Dotted paths target object properties where permitted; dotted
|
|
141
|
-
|
|
168
|
+
- Dotted paths target object properties where permitted; a top-level dotted write into an array
|
|
169
|
+
field, such as `c.0`, is refused.
|
|
170
|
+
- Foundry's operator keys work at any permitted nested level: `{"-=key": null}` deletes the key,
|
|
171
|
+
and `{"==key": value}` replaces the key's whole value instead of merging into it.
|
|
142
172
|
- Embedded collections follow their family's Foundry semantics.
|
|
143
173
|
|
|
144
174
|
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`.
|
|
146
|
-
mutation, including in bulk writes and dry runs. Correct the fields identified by the error.
|
|
175
|
+
`[x1, y1, x2, y2]`, not `c.0`. Array writes that Foundry would discard return `INVALID_PARAMS`
|
|
176
|
+
before mutation, including in bulk writes and dry runs. Correct the fields identified by the error.
|
|
147
177
|
|
|
148
178
|
Prefer dedicated commands for creating embedded documents. A parent update that adds entries
|
|
149
179
|
without `_id`, such as new `behaviors` in `scene.region.update`, can create them but return an
|
|
@@ -163,6 +193,12 @@ A timeout or disconnect can happen after a write commits. An update error with `
|
|
|
163
193
|
or `details.indeterminate` can also mean that some changes persisted. Read affected state before
|
|
164
194
|
retrying and send only what remains to be done.
|
|
165
195
|
|
|
196
|
+
An update whose stored state differs from the request fails with `INTERNAL_ERROR`, and
|
|
197
|
+
`details.paths` lists the differing paths with the requested and the stored value. Foundry core, the
|
|
198
|
+
game system or a module may have changed the value; Foundry stores a raw `&` in rich text as
|
|
199
|
+
`&`, for example. The bridge cannot tell which, so the caller judges from the values. Sending
|
|
200
|
+
the same patch again stores the same result.
|
|
201
|
+
|
|
166
202
|
An idempotency key identifies one logical request and can prevent duplicate effects while its
|
|
167
203
|
cached state survives. Reuse it only for the same request; a corrected or remaining patch is a
|
|
168
204
|
new operation and needs a fresh key. Follow the [delivery rules](protocol.md#delivery-states-and-retries)
|
|
@@ -207,7 +243,7 @@ inspect `auth pending`, then use `auth approve <code> --yes` for the selected re
|
|
|
207
243
|
|
|
208
244
|
| Command | Effect |
|
|
209
245
|
|---|---|
|
|
210
|
-
| `auth status` | Show bridge state and public profile metadata |
|
|
246
|
+
| `auth status` | Show bridge state, the commands the connected bridge advertised, and public profile metadata |
|
|
211
247
|
| `auth pending` | List pending codes, expiry, and browser/world/GM identity |
|
|
212
248
|
| `auth approve [code] [--yes]` | Approve a selected request; omit the code only when exactly one is pending |
|
|
213
249
|
| `auth deny <code>` | Reject a pending request |
|
package/docs/compatibility.md
CHANGED
|
@@ -6,9 +6,12 @@ The bridge supports Foundry VTT v13 and v14. Check your connected version with
|
|
|
6
6
|
| Area | v13 | v14 | What to do |
|
|
7
7
|
|---|---|---|---|
|
|
8
8
|
| Measured templates | Available | Removed from core | Use `scene.template` commands on v13. They are unavailable on v14. |
|
|
9
|
+
| Scene maps | One map per scene: `background`, `backgroundColor`, `foreground`, `foregroundElevation` and `fog.overlay` on the scene | Each level has its own map; the scene has `levels` and `initialLevel` | On v14, set maps through `levels` in `scene.create` or with `scene.level` commands. The scene-level map fields, including `fog.overlay`, are refused on v14, and `scene.level`, `levels` and `initialLevel` are refused on v13. |
|
|
10
|
+
| Placeable levels | Placeables have no level fields | A token sits on one `level`; tiles, walls, lights, sounds, notes, drawings and regions have a `levels` list, where an empty list means every level | On v14, read `level` or `levels` from placeable results to see what a level holds before deleting it. Placeable writes that set `level` or `levels` are refused on v13. |
|
|
9
11
|
| Scene thumbnail rendering | Renders the scene | Renders the scene's initial level by default | On v14, expect the initial level in the thumbnail. Check the returned dimensions and image. |
|
|
10
12
|
| Scene thumbnail files | Uses a stable scene-based filename | Uses a filename based on the image content | Use the returned path. On v14, a changed image can leave an older thumbnail file behind. |
|
|
11
13
|
| User permission names | `TEMPLATE_CREATE` | `REGION_CREATE` | Use the permission keys reported by the connected Foundry version when calling `user.permissions.set`. |
|
|
14
|
+
| Legacy update operators `-=key` (deletion) and `==key` (forced replacement) | Work without a warning | Work, and the GM browser console logs a deprecation warning for each such key, stating that support will be removed in Version 16 | Nothing changes for v13 or v14 writes. The bridge passes the operator keys through without translating them to Foundry 14's operator objects, so they will stop working once Foundry removes them. |
|
|
12
15
|
|
|
13
16
|
Scene placeable fields and available region behavior types also differ. Read the target document
|
|
14
17
|
before preparing a patch; valid data from one version is not automatically valid on the other.
|
package/docs/protocol.md
CHANGED
|
@@ -178,7 +178,11 @@ The protocol package exports `REQUEST_SCHEMA` and `COMMAND_RESPONSE_SCHEMA` for
|
|
|
178
178
|
Document results use type-named keys and expose `id` as the public identifier. A source `_id`
|
|
179
179
|
mirror may accompany it. List responses use smaller projections than single-document reads;
|
|
180
180
|
filters apply before pagination. Previewed documents have no persistent identity, so an id
|
|
181
|
-
observed during a preview must not be reused.
|
|
181
|
+
observed during a preview must not be reused. Some result fields depend on the connected Foundry
|
|
182
|
+
version; [Foundry compatibility](compatibility.md) lists them.
|
|
183
|
+
|
|
184
|
+
World document reads carry `compendiumSource` and `duplicateSource`, hoisted from Foundry's
|
|
185
|
+
`_stats` and `null` when absent.
|
|
182
186
|
|
|
183
187
|
Broadcast actions report `dispatched` and target users rather than a confirmed player-side result.
|
|
184
188
|
The active/inactive split is included where knowable.
|
|
@@ -195,10 +199,12 @@ world state when the return value does not establish the effect.
|
|
|
195
199
|
|
|
196
200
|
### Setting results
|
|
197
201
|
|
|
198
|
-
Setting writes return the observed `value` and its `previous` value
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
+
Setting writes return the observed `value` and its `previous` value, as `game.settings.get`
|
|
203
|
+
returns them after the registered type's cast. Confirmation compares the JSON Foundry stores with
|
|
204
|
+
the JSON of the validated request; a different stored value, for example one rewritten by an
|
|
205
|
+
`onChange` callback, is a mismatch error with a `paths` entry for `value`. Writing an
|
|
206
|
+
already-stored value succeeds as unchanged without calling Foundry. `requiresReload: true`
|
|
207
|
+
indicates that the GM client needs a reload.
|
|
202
208
|
|
|
203
209
|
## Write confirmation
|
|
204
210
|
|
|
@@ -206,11 +212,24 @@ Document writes report success only after confirmation. Foundry can resolve a ve
|
|
|
206
212
|
write without throwing, and hooks can remove or rewrite part of a patch. Single and bulk updates
|
|
207
213
|
pass Foundry a private copy, then compare stored state with the original request.
|
|
208
214
|
|
|
215
|
+
Confirmation compares each requested leaf path that survives Foundry's cleaning with the stored
|
|
216
|
+
source. Foundry drops a key the document's schema does not declare without an error before that
|
|
217
|
+
comparison, so a write made only of undeclared keys reports success with nothing stored. A deletion (`-=key` or
|
|
218
|
+
Foundry 14's `ForcedDeletion`) is confirmed when the key is absent. A forced replacement (`==key`
|
|
219
|
+
or Foundry 14's `ForcedReplacement`) is confirmed when the whole stored value at that path equals the requested
|
|
220
|
+
value after Foundry's cleaning.
|
|
221
|
+
|
|
209
222
|
A valid patch whose requested state is already stored remains a successful no-op. A validation
|
|
210
223
|
failure recovered after an unwritten update returns `INVALID_PARAMS`. Unconfirmed, partial, or
|
|
211
224
|
indeterminate updates can return `INTERNAL_ERROR` with these details:
|
|
212
225
|
|
|
213
|
-
- `fields`: requested fields whose state was not confirmed.
|
|
226
|
+
- `fields`: requested top-level fields whose state was not confirmed.
|
|
227
|
+
- `paths`: up to 20 entries `{ path, requested, stored }`, one per leaf path where the stored value
|
|
228
|
+
differs from the request. `absent: "stored"` replaces `stored` when the key is missing from the
|
|
229
|
+
stored source, and `absent: "requested"` replaces `requested` for a deletion that did not land.
|
|
230
|
+
A long string, or an object or array whose JSON is long, is shortened to a window around the
|
|
231
|
+
first differing character; `truncated` then carries `format` (`text` or `json`), `offset`, and
|
|
232
|
+
the full `requestedLength` and `storedLength`. `pathsTruncated` counts the entries beyond 20.
|
|
214
233
|
- `partial: true`: stored data changed in a requested field, but the full requested state was
|
|
215
234
|
not reached. A hook may have applied only part of a nested object or replaced a value.
|
|
216
235
|
- `changedFields`: requested top-level fields observed to change, including fields that changed
|
|
@@ -220,6 +239,12 @@ indeterminate updates can return `INTERNAL_ERROR` with these details:
|
|
|
220
239
|
- `indeterminate: true`: confirmation could not establish the outcome. Some or all of the write
|
|
221
240
|
may have persisted. `changedFields` is `null` when the before/after comparison was unavailable.
|
|
222
241
|
|
|
242
|
+
When stored differs from requested, the message says that the bridge cannot verify whether Foundry
|
|
243
|
+
core, the game system or a module normalized the value, or whether a hook rewrote, dropped or vetoed
|
|
244
|
+
the change. A blocking module is listed as one possible cause, never as the diagnosis. Resending the
|
|
245
|
+
same patch does not change the result. Every confirmed write that can report a mismatch carries the
|
|
246
|
+
same `paths`, and so does a `dropped` bulk outcome when the stored state was compared.
|
|
247
|
+
|
|
223
248
|
Parent patches that create embedded entries without `_id`, such as new `behaviors` in
|
|
224
249
|
`scene.region.update`, return an indeterminate error after writing because parent update results
|
|
225
250
|
cannot confirm those creations. A retry may duplicate them. Read the embedded collection first,
|
|
@@ -230,10 +255,10 @@ new operation with a fresh idempotency key if using one.
|
|
|
230
255
|
|
|
231
256
|
### Patch shape checks
|
|
232
257
|
|
|
233
|
-
Single updates, bulk updates, and dry runs reject
|
|
234
|
-
array
|
|
235
|
-
|
|
236
|
-
|
|
258
|
+
Single updates, bulk updates, and dry runs reject invalid or discarded array values, top-level
|
|
259
|
+
dotted writes into array fields, and writes to legacy fields the running core moved, with
|
|
260
|
+
`INVALID_PARAMS` before mutation. Send whole arrays; ordinary dotted object-property writes remain
|
|
261
|
+
supported where the schema permits them. Other key spellings reach Foundry as written.
|
|
237
262
|
|
|
238
263
|
Errors identify the `field` and may include `arrayField`, `requested`, `stored`, or migration
|
|
239
264
|
destination details. Bulk failures add the entry's `index` and `id`; single failures use document
|
|
@@ -341,8 +366,8 @@ The wait has two phases because the decision can outlast a normal request timeou
|
|
|
341
366
|
policy can change before dispatch.
|
|
342
367
|
|
|
343
368
|
The module supplies each opaque `approvalId`; callers do not construct one. Approval request schemas
|
|
344
|
-
are closed. `approval.await`, `approval.cancel`, and `policy.snapshot` do not appear in `commands
|
|
345
|
-
|
|
369
|
+
are closed. `approval.await`, `approval.cancel`, and `policy.snapshot` do not appear in `commands` or
|
|
370
|
+
bridge status. `schema <command>` still returns their schemas.
|
|
346
371
|
The bridge handshake advertises them because the daemon must forward them.
|
|
347
372
|
|
|
348
373
|
## Delivery states and retries
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fvtt-world-cli",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Safe local CLI and authenticated bridge for automating live Foundry VTT worlds.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"foundry-vtt",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"zod": "^3.24.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@fvtt-world-cli/protocol": "1.1
|
|
59
|
+
"@fvtt-world-cli/protocol": "1.2.1"
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -75,6 +75,14 @@ A macro that throws fails `macro.execute` with a partial outcome — read what i
|
|
|
75
75
|
retrying — while a macro that catches its own errors still returns `null`, which proves nothing;
|
|
76
76
|
verify effects with reads, and treat `MACRO_TIMEOUT` as indeterminate — the macro may still be
|
|
77
77
|
running.
|
|
78
|
+
On Foundry v14 maps live on levels: pass `levels` in `scene.create`, then use `scene.level.*`;
|
|
79
|
+
level ids in a preview are provisional.
|
|
80
|
+
Deleting a level also deletes its tokens and every placeable only on that level, and the dry run
|
|
81
|
+
does not list them: read the scene's placeables (token `level`, others' `levels`) and tell the user
|
|
82
|
+
what the delete removes before running it.
|
|
83
|
+
An unlinked token keeps its own overrides, which edits to its world actor never reach. Before
|
|
84
|
+
editing an actor that has placed tokens, read its tokens' overrides and tell the user which tokens
|
|
85
|
+
the edit will not change.
|
|
78
86
|
`setting.set` cannot touch this module's own namespace (`SETTING_PROTECTED` is final; never retry).
|
|
79
87
|
When a setting write returns `requiresReload: true`, the change needs a GM-client reload to take
|
|
80
88
|
effect; `system.reload` performs it, drops the bridge, and requires a reconnect wait before the
|
|
@@ -87,12 +95,13 @@ signal, not a failure — reconnect and continue rather than retrying the reload
|
|
|
87
95
|
Discover → inspect schema → locate → read → smallest patch → dry-run → commit → verify. Never
|
|
88
96
|
guess a command name or parameter.
|
|
89
97
|
|
|
90
|
-
1. Run `fvtt-world-cli commands --json`. Continue only when `policy.applied`
|
|
91
|
-
required command is present. A `false` value means no bridge
|
|
92
|
-
registry, not the client's permissions. Report an absent
|
|
93
|
-
to produce the same effect. Warn the user before a
|
|
94
|
-
one `*-many` command when it can replace several
|
|
95
|
-
CLI subcommands, such as `actor.item.update` to
|
|
98
|
+
1. Run `fvtt-world-cli commands --json`. Continue only when `policy.applied` (top level, beside
|
|
99
|
+
`result`) is `true` and the required command is present. A `false` value means no bridge
|
|
100
|
+
answered and the output is the static registry, not the client's permissions. Report an absent
|
|
101
|
+
command instead of seeking another way to produce the same effect. Warn the user before a
|
|
102
|
+
command marked `"approval": true`, and prefer one `*-many` command when it can replace several
|
|
103
|
+
approvals. Dotted protocol names map to spaced CLI subcommands, such as `actor.item.update` to
|
|
104
|
+
`actor item update`.
|
|
96
105
|
2. `fvtt-world-cli schema <command>` shows the exact request parameters, required fields, enums,
|
|
97
106
|
and whether unknown fields are accepted; `fvtt-world-cli <command path> --help` maps flags.
|
|
98
107
|
3. Locate targets with the narrowest query: a family `list --name <substring> --limit <n>` when
|
|
@@ -101,8 +110,9 @@ guess a command name or parameter.
|
|
|
101
110
|
never the basis of a write.
|
|
102
111
|
4. `get` the complete target before mutating and work from the returned ids.
|
|
103
112
|
5. Build the smallest valid patch. Nested objects merge recursively; plain arrays replace
|
|
104
|
-
wholesale; dotted paths reach permitted leaves;
|
|
105
|
-
`
|
|
113
|
+
wholesale; dotted paths reach permitted leaves; `{"-=key": null}` deletes a permitted key, and
|
|
114
|
+
`{"==key": value}` replaces its whole value instead of merging. A `get` result contains
|
|
115
|
+
read-only and derived fields, so build the patch from accepted fields only.
|
|
106
116
|
For arrays and extensible `system`/`flags` data: read, preserve everything that
|
|
107
117
|
stays, change only the intended part.
|
|
108
118
|
6. Dry-run every nontrivial mutation with the global `--dry-run` flag. It runs the same
|
|
@@ -135,7 +145,8 @@ details}}`, alongside `protocolVersion`, `type`, and the correlation `id` (echoi
|
|
|
135
145
|
Documents live under a type-named key inside `result` that varies between commands but is stable
|
|
136
146
|
for each one. `id` is the public identifier; a `_id` mirror may accompany it. Values requested
|
|
137
147
|
through `include` flags may be derived or version-dependent. Write them back only when the
|
|
138
|
-
update schema explicitly accepts them.
|
|
148
|
+
update schema explicitly accepts them. Actor reads return `itemCount` in place of owned items; add
|
|
149
|
+
`--include items` when the task needs them, or use `actor item list` and `actor item get`.
|
|
139
150
|
|
|
140
151
|
## Retry classification
|
|
141
152
|
|
|
@@ -165,6 +176,10 @@ Classify a failure before reacting:
|
|
|
165
176
|
observed to change, not fully applied nested values. An embedded creation without a requested
|
|
166
177
|
id may already exist despite an indeterminate error. Send only the remaining changes as a new
|
|
167
178
|
operation with a fresh idempotency key, if using one.
|
|
179
|
+
- An update `INTERNAL_ERROR` with `details.paths` is a stored-vs-requested mismatch. Compare
|
|
180
|
+
`requested` and `stored` for each path. A representation-only difference, such as HTML escaping (`&` stored as `&`) or
|
|
181
|
+
whitespace, can be accepted as done. Report any other difference to the user. The same patch
|
|
182
|
+
stores the same result, so the next request is either a different patch or none.
|
|
168
183
|
- Correct a structured Foundry rejection and submit the corrected content as a new operation.
|
|
169
184
|
|
|
170
185
|
## Bulk writes and actions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
5b4188ba39ed8f9f1c041cec9c5f0c3fb5d05db7910670d0ff2bb9c5d7d43dde
|