fvtt-world-cli 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +515 -145
- package/docs/commands.md +3 -3
- package/docs/compatibility.md +1 -0
- package/docs/protocol.md +12 -6
- package/package.json +2 -2
- package/skills/foundry-world-editor/SKILL.md +10 -6
- package/skills/foundry-world-editor/SKILL.md.sha256 +1 -1
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { readFileSync as readFileSync2 } from "node:fs";
|
|
|
10
10
|
import { createHash as createHash2, randomBytes as randomBytes2, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
|
|
11
11
|
|
|
12
12
|
// ../protocol/src/constants.js
|
|
13
|
-
var PROTOCOL_VERSION = "1.
|
|
13
|
+
var PROTOCOL_VERSION = "1.3.0";
|
|
14
14
|
var PROTOCOL_COMPONENTS = Object.freeze({
|
|
15
15
|
MODULE: "module",
|
|
16
16
|
CLI_DAEMON: "cli-daemon",
|
|
@@ -76,6 +76,9 @@ function resolveEffectiveLimits(uploadLimitBytes = DEFAULT_UPLOAD_SIZE_LIMIT_BYT
|
|
|
76
76
|
wsMaxPayloadBytes: Math.max(wsMaxPayloadForUploadLimit(uploadLimitBytes), DEFAULT_WS_MAX_PAYLOAD_BYTES)
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
+
var BROWSER_STRING_MAX_LENGTH = 536870888;
|
|
80
|
+
var READ_RESPONSE_ENVELOPE_RESERVE_CHARS = 1024 * 1024;
|
|
81
|
+
var READ_ENCODING_CEILING_BYTES = Math.floor((BROWSER_STRING_MAX_LENGTH - READ_RESPONSE_ENVELOPE_RESERVE_CHARS) / 4) * 3;
|
|
79
82
|
var BATCH_GET_MAX_IDS = 100;
|
|
80
83
|
var BATCH_WRITE_MAX_ITEMS = 100;
|
|
81
84
|
var BATCH_WRITE_STATUSES = Object.freeze([
|
|
@@ -102,6 +105,7 @@ var SCENE_THUMBNAIL_MAX_BYTES = 2 * 1024 * 1024;
|
|
|
102
105
|
var SCENE_THUMBNAIL_RESPONSE_MAX_BYTES = 1024 * 1024;
|
|
103
106
|
var TABLE_DRAW_MAX_COUNT = 100;
|
|
104
107
|
var SETTING_VALUE_MAX_BYTES = 256 * 1024;
|
|
108
|
+
var SERIALIZE_OMISSIONS_MAX = 100;
|
|
105
109
|
var MACRO_EXECUTE_TIMEOUT_DEFAULT_MS = 3e4;
|
|
106
110
|
var MACRO_EXECUTE_TIMEOUT_MAX_MS = 3e5;
|
|
107
111
|
var SEARCH_MODES = Object.freeze(["name", "full"]);
|
|
@@ -189,6 +193,7 @@ var ERROR_CODES = Object.freeze({
|
|
|
189
193
|
PLAYLIST_NOT_FOUND: "PLAYLIST_NOT_FOUND",
|
|
190
194
|
PLAYLIST_SOUND_NOT_FOUND: "PLAYLIST_SOUND_NOT_FOUND",
|
|
191
195
|
JOURNAL_CATEGORY_NOT_FOUND: "JOURNAL_CATEGORY_NOT_FOUND",
|
|
196
|
+
JOURNAL_PAGE_NOT_FOUND: "JOURNAL_PAGE_NOT_FOUND",
|
|
192
197
|
CHAT_MESSAGE_NOT_FOUND: "CHAT_MESSAGE_NOT_FOUND",
|
|
193
198
|
TABLE_NOT_FOUND: "TABLE_NOT_FOUND",
|
|
194
199
|
TABLE_RESULT_NOT_FOUND: "TABLE_RESULT_NOT_FOUND",
|
|
@@ -204,7 +209,6 @@ var ERROR_CODES = Object.freeze({
|
|
|
204
209
|
FOLDER_NOT_FOUND: "FOLDER_NOT_FOUND",
|
|
205
210
|
SETTING_NOT_FOUND: "SETTING_NOT_FOUND",
|
|
206
211
|
SETTING_READ_FAILED: "SETTING_READ_FAILED",
|
|
207
|
-
SETTING_VALUE_NOT_SERIALIZABLE: "SETTING_VALUE_NOT_SERIALIZABLE",
|
|
208
212
|
SETTING_PROTECTED: "SETTING_PROTECTED",
|
|
209
213
|
SETTING_UNREGISTERED: "SETTING_UNREGISTERED",
|
|
210
214
|
MACRO_TIMEOUT: "MACRO_TIMEOUT",
|
|
@@ -815,6 +819,11 @@ var actorCommands = {
|
|
|
815
819
|
},
|
|
816
820
|
{ mutation: true }
|
|
817
821
|
),
|
|
822
|
+
...batchWriteCommands("actor.item", {
|
|
823
|
+
scopeProperties: actorScopeProperties,
|
|
824
|
+
createSchema: embeddedItemDataSchema,
|
|
825
|
+
patchSchema: itemPatchSchema
|
|
826
|
+
}),
|
|
818
827
|
...batchWriteCommands("actor", {
|
|
819
828
|
scopeProperties: emptyScopeProperties,
|
|
820
829
|
patchSchema: actorPatchSchema,
|
|
@@ -1810,6 +1819,22 @@ var auditFilesSchema = {
|
|
|
1810
1819
|
},
|
|
1811
1820
|
additionalProperties: false
|
|
1812
1821
|
};
|
|
1822
|
+
var REFERENCE_SCOPES = deepFreeze([...AUDIT_FILE_SCOPES, "folder", "setting", "chat"]);
|
|
1823
|
+
var REFERENCE_DEFAULT_SCOPES = deepFreeze(REFERENCE_SCOPES.filter((scope) => scope !== "chat"));
|
|
1824
|
+
var worldReferencesSchema = {
|
|
1825
|
+
type: "object",
|
|
1826
|
+
required: ["uuid"],
|
|
1827
|
+
properties: {
|
|
1828
|
+
uuid: { type: "string", minLength: 1 },
|
|
1829
|
+
scope: {
|
|
1830
|
+
type: "array",
|
|
1831
|
+
minItems: 1,
|
|
1832
|
+
items: { type: "string", enum: [...REFERENCE_SCOPES] }
|
|
1833
|
+
},
|
|
1834
|
+
...paginationProperties
|
|
1835
|
+
},
|
|
1836
|
+
additionalProperties: false
|
|
1837
|
+
};
|
|
1813
1838
|
var fileCommands = {
|
|
1814
1839
|
"file.list": cmd({
|
|
1815
1840
|
type: "object",
|
|
@@ -1897,7 +1922,8 @@ var fileCommands = {
|
|
|
1897
1922
|
)
|
|
1898
1923
|
};
|
|
1899
1924
|
var worldAuditCommands = {
|
|
1900
|
-
"world.audit-files": cmd(auditFilesSchema)
|
|
1925
|
+
"world.audit-files": cmd(auditFilesSchema),
|
|
1926
|
+
"world.references": cmd(worldReferencesSchema)
|
|
1901
1927
|
};
|
|
1902
1928
|
|
|
1903
1929
|
// ../protocol/src/schemas/folder.js
|
|
@@ -2253,6 +2279,16 @@ var journalPageCreateSchema = {
|
|
|
2253
2279
|
var journalPagePatchSchema = patchFrom(journalPageCreateSchema, {
|
|
2254
2280
|
prepend: { id: { type: "string", minLength: 1 } }
|
|
2255
2281
|
});
|
|
2282
|
+
var journalPageOwnPatchSchema = patchFrom(journalPageCreateSchema);
|
|
2283
|
+
var journalPageIdSchema = {
|
|
2284
|
+
type: "object",
|
|
2285
|
+
required: ["journalId", "pageId"],
|
|
2286
|
+
properties: {
|
|
2287
|
+
journalId: { type: "string", minLength: 1 },
|
|
2288
|
+
pageId: { type: "string", minLength: 1 }
|
|
2289
|
+
},
|
|
2290
|
+
additionalProperties: false
|
|
2291
|
+
};
|
|
2256
2292
|
var journalDataSchema = {
|
|
2257
2293
|
type: "object",
|
|
2258
2294
|
required: ["name"],
|
|
@@ -2420,6 +2456,58 @@ var journalCommands = {
|
|
|
2420
2456
|
patchSchema: journalDocumentPatchSchema,
|
|
2421
2457
|
verbs: ["update-many", "delete-many"]
|
|
2422
2458
|
}),
|
|
2459
|
+
"journal.page.list": cmd({
|
|
2460
|
+
type: "object",
|
|
2461
|
+
required: ["journalId"],
|
|
2462
|
+
properties: {
|
|
2463
|
+
journalId: { type: "string", minLength: 1 },
|
|
2464
|
+
...nameFilterProperty,
|
|
2465
|
+
...paginationProperties
|
|
2466
|
+
},
|
|
2467
|
+
additionalProperties: false
|
|
2468
|
+
}),
|
|
2469
|
+
"journal.page.get": cmd(journalPageIdSchema),
|
|
2470
|
+
"journal.page.create": cmd(
|
|
2471
|
+
{
|
|
2472
|
+
type: "object",
|
|
2473
|
+
required: ["journalId", "data"],
|
|
2474
|
+
properties: {
|
|
2475
|
+
journalId: { type: "string", minLength: 1 },
|
|
2476
|
+
data: journalPageCreateSchema,
|
|
2477
|
+
...dryRunProperty,
|
|
2478
|
+
...idempotencyKeyProperty
|
|
2479
|
+
},
|
|
2480
|
+
additionalProperties: false
|
|
2481
|
+
},
|
|
2482
|
+
{ mutation: true }
|
|
2483
|
+
),
|
|
2484
|
+
"journal.page.update": cmd(
|
|
2485
|
+
{
|
|
2486
|
+
type: "object",
|
|
2487
|
+
required: ["journalId", "pageId", "patch"],
|
|
2488
|
+
properties: {
|
|
2489
|
+
journalId: { type: "string", minLength: 1 },
|
|
2490
|
+
pageId: { type: "string", minLength: 1 },
|
|
2491
|
+
patch: journalPageOwnPatchSchema,
|
|
2492
|
+
...dryRunProperty
|
|
2493
|
+
},
|
|
2494
|
+
additionalProperties: false
|
|
2495
|
+
},
|
|
2496
|
+
{ mutation: true }
|
|
2497
|
+
),
|
|
2498
|
+
"journal.page.delete": cmd(
|
|
2499
|
+
{
|
|
2500
|
+
type: "object",
|
|
2501
|
+
required: ["journalId", "pageId"],
|
|
2502
|
+
properties: {
|
|
2503
|
+
journalId: { type: "string", minLength: 1 },
|
|
2504
|
+
pageId: { type: "string", minLength: 1 },
|
|
2505
|
+
...dryRunProperty
|
|
2506
|
+
},
|
|
2507
|
+
additionalProperties: false
|
|
2508
|
+
},
|
|
2509
|
+
{ mutation: true }
|
|
2510
|
+
),
|
|
2423
2511
|
"journal.category.list": cmd({
|
|
2424
2512
|
type: "object",
|
|
2425
2513
|
required: ["journalId"],
|
|
@@ -5534,6 +5622,11 @@ var DEFAULT_COMMAND_PROFILE = deepFreeze({
|
|
|
5534
5622
|
"journal.ownership.set": "allow",
|
|
5535
5623
|
"journal.update-many": "allow",
|
|
5536
5624
|
"journal.delete-many": "approve",
|
|
5625
|
+
"journal.page.list": "allow",
|
|
5626
|
+
"journal.page.get": "allow",
|
|
5627
|
+
"journal.page.create": "allow",
|
|
5628
|
+
"journal.page.update": "allow",
|
|
5629
|
+
"journal.page.delete": "approve",
|
|
5537
5630
|
"journal.category.list": "allow",
|
|
5538
5631
|
"journal.category.get": "allow",
|
|
5539
5632
|
"journal.category.create": "allow",
|
|
@@ -5650,6 +5743,9 @@ var DEFAULT_COMMAND_PROFILE = deepFreeze({
|
|
|
5650
5743
|
"actor.item.delete": "approve",
|
|
5651
5744
|
"actor.item.clone": "allow",
|
|
5652
5745
|
"actor.item.import-from-compendium": "allow",
|
|
5746
|
+
"actor.item.create-many": "allow",
|
|
5747
|
+
"actor.item.update-many": "allow",
|
|
5748
|
+
"actor.item.delete-many": "approve",
|
|
5653
5749
|
"actor.update-many": "allow",
|
|
5654
5750
|
"actor.delete-many": "approve",
|
|
5655
5751
|
"actor.effect.list": "allow",
|
|
@@ -5703,6 +5799,7 @@ var DEFAULT_COMMAND_PROFILE = deepFreeze({
|
|
|
5703
5799
|
"setting.set-many": "deny",
|
|
5704
5800
|
"actor.import-from-compendium": "allow",
|
|
5705
5801
|
"world.audit-files": "allow",
|
|
5802
|
+
"world.references": "allow",
|
|
5706
5803
|
"world.search": "allow",
|
|
5707
5804
|
"approval.await": "allow",
|
|
5708
5805
|
"approval.cancel": "allow",
|
|
@@ -5781,6 +5878,17 @@ function editDistance(a, b) {
|
|
|
5781
5878
|
}
|
|
5782
5879
|
return previous[cols - 1];
|
|
5783
5880
|
}
|
|
5881
|
+
function childPath(path, key) {
|
|
5882
|
+
return key.includes(".") ? `${path}[${JSON.stringify(key)}]` : `${path}.${key}`;
|
|
5883
|
+
}
|
|
5884
|
+
function describeDottedKey(key, properties) {
|
|
5885
|
+
const root = key.split(".")[0];
|
|
5886
|
+
if (!key.includes(".") || !Object.hasOwn(properties, root)) {
|
|
5887
|
+
return "";
|
|
5888
|
+
}
|
|
5889
|
+
const nested = key.split(".").reduceRight((inner, segment) => `{${JSON.stringify(segment)}: ${inner}}`, "...");
|
|
5890
|
+
return `; a key at this level must be one of the listed field names, so nest the rest of the path inside "${root}": ${nested}`;
|
|
5891
|
+
}
|
|
5784
5892
|
function describeAllowedFields(key, allowedFields) {
|
|
5785
5893
|
if (allowedFields.length === 0) {
|
|
5786
5894
|
return "";
|
|
@@ -5830,7 +5938,7 @@ function validateObjectSchema(schema, value, path, errors) {
|
|
|
5830
5938
|
const additionalProperties = schema.additionalProperties ?? true;
|
|
5831
5939
|
for (const key of required) {
|
|
5832
5940
|
if (!Object.hasOwn(value, key)) {
|
|
5833
|
-
errors.push(`${path
|
|
5941
|
+
errors.push(`${childPath(path, key)} is required`);
|
|
5834
5942
|
}
|
|
5835
5943
|
}
|
|
5836
5944
|
const ownKeys = Object.keys(value);
|
|
@@ -5842,25 +5950,27 @@ function validateObjectSchema(schema, value, path, errors) {
|
|
|
5842
5950
|
for (const key of ownKeys) {
|
|
5843
5951
|
if (namePattern === null) {
|
|
5844
5952
|
errors.push(
|
|
5845
|
-
`${path
|
|
5953
|
+
`${childPath(path, key)} cannot be validated: ${schema.propertyNames.pattern} is not a valid unicode-mode pattern`
|
|
5846
5954
|
);
|
|
5847
5955
|
} else if (!namePattern.test(key)) {
|
|
5848
|
-
errors.push(`${path
|
|
5956
|
+
errors.push(`${childPath(path, key)} is not an allowed property name`);
|
|
5849
5957
|
}
|
|
5850
5958
|
}
|
|
5851
5959
|
}
|
|
5852
5960
|
for (const [key, propertyValue] of Object.entries(value)) {
|
|
5853
5961
|
const propertySchema = properties[key];
|
|
5854
5962
|
if (propertySchema) {
|
|
5855
|
-
validateSchema(propertySchema, propertyValue,
|
|
5963
|
+
validateSchema(propertySchema, propertyValue, childPath(path, key), errors);
|
|
5856
5964
|
continue;
|
|
5857
5965
|
}
|
|
5858
5966
|
if (additionalProperties === false) {
|
|
5859
|
-
errors.push(
|
|
5967
|
+
errors.push(
|
|
5968
|
+
`${childPath(path, key)} is not allowed${describeAllowedFields(key, Object.keys(properties))}` + describeDottedKey(key, properties)
|
|
5969
|
+
);
|
|
5860
5970
|
continue;
|
|
5861
5971
|
}
|
|
5862
5972
|
if (isPlainObject(additionalProperties)) {
|
|
5863
|
-
validateSchema(additionalProperties, propertyValue,
|
|
5973
|
+
validateSchema(additionalProperties, propertyValue, childPath(path, key), errors);
|
|
5864
5974
|
}
|
|
5865
5975
|
}
|
|
5866
5976
|
}
|
|
@@ -9027,7 +9137,10 @@ function createSceneCreateParams(options) {
|
|
|
9027
9137
|
function createSceneCloneParams(options) {
|
|
9028
9138
|
return {
|
|
9029
9139
|
sceneId: options.sceneId,
|
|
9030
|
-
...optionalPatch(
|
|
9140
|
+
...optionalPatch({
|
|
9141
|
+
...buildScenePatch(options),
|
|
9142
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9143
|
+
})
|
|
9031
9144
|
};
|
|
9032
9145
|
}
|
|
9033
9146
|
function createItemCloneParams(options) {
|
|
@@ -9036,7 +9149,8 @@ function createItemCloneParams(options) {
|
|
|
9036
9149
|
...stringField("img", options.img),
|
|
9037
9150
|
...folderField(options),
|
|
9038
9151
|
...numberField("sort", options.sort),
|
|
9039
|
-
...jsonObjectField("system", options.systemJson, "--system-json")
|
|
9152
|
+
...jsonObjectField("system", options.systemJson, "--system-json"),
|
|
9153
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9040
9154
|
};
|
|
9041
9155
|
return {
|
|
9042
9156
|
itemId: options.itemId,
|
|
@@ -9047,7 +9161,8 @@ function createJournalCloneParams(options) {
|
|
|
9047
9161
|
const patch = {
|
|
9048
9162
|
...stringField("name", options.name),
|
|
9049
9163
|
...folderField(options),
|
|
9050
|
-
...numberField("sort", options.sort)
|
|
9164
|
+
...numberField("sort", options.sort),
|
|
9165
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9051
9166
|
};
|
|
9052
9167
|
return {
|
|
9053
9168
|
journalId: options.journalId,
|
|
@@ -9133,7 +9248,8 @@ function createMacroCloneParams(options) {
|
|
|
9133
9248
|
...stringField("command", options.command),
|
|
9134
9249
|
...stringField("img", options.img),
|
|
9135
9250
|
...folderField(options),
|
|
9136
|
-
...stringField("scope", options.scope)
|
|
9251
|
+
...stringField("scope", options.scope),
|
|
9252
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9137
9253
|
};
|
|
9138
9254
|
return {
|
|
9139
9255
|
macroId: options.macroId,
|
|
@@ -9256,6 +9372,34 @@ function createJournalCategoryUpdateParams(options) {
|
|
|
9256
9372
|
})
|
|
9257
9373
|
};
|
|
9258
9374
|
}
|
|
9375
|
+
function buildJournalPageFields(options) {
|
|
9376
|
+
return {
|
|
9377
|
+
...stringField("name", options.name),
|
|
9378
|
+
...stringField("type", options.type),
|
|
9379
|
+
...numberField("sort", options.sort),
|
|
9380
|
+
...options.clearCategory ? { category: null } : stringField("category", options.category),
|
|
9381
|
+
...stringField("src", options.src)
|
|
9382
|
+
};
|
|
9383
|
+
}
|
|
9384
|
+
function createJournalPageCreateParams(options) {
|
|
9385
|
+
return {
|
|
9386
|
+
journalId: options.journalId,
|
|
9387
|
+
data: {
|
|
9388
|
+
...buildJournalPageFields(options),
|
|
9389
|
+
...optionalJsonObject(options.dataJson, "--data-json") ?? {}
|
|
9390
|
+
}
|
|
9391
|
+
};
|
|
9392
|
+
}
|
|
9393
|
+
function createJournalPageUpdateParams(options) {
|
|
9394
|
+
return {
|
|
9395
|
+
journalId: options.journalId,
|
|
9396
|
+
pageId: options.pageId,
|
|
9397
|
+
patch: assertNonEmptyPatch({
|
|
9398
|
+
...buildJournalPageFields(options),
|
|
9399
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9400
|
+
})
|
|
9401
|
+
};
|
|
9402
|
+
}
|
|
9259
9403
|
function buildTableFields(options) {
|
|
9260
9404
|
return {
|
|
9261
9405
|
...stringField("description", options.description),
|
|
@@ -9568,7 +9712,8 @@ function createActorItemCloneParams(options) {
|
|
|
9568
9712
|
...stringField("name", options.name),
|
|
9569
9713
|
...stringField("img", options.img),
|
|
9570
9714
|
...numberField("sort", options.sort),
|
|
9571
|
-
...jsonObjectField("system", options.systemJson, "--system-json")
|
|
9715
|
+
...jsonObjectField("system", options.systemJson, "--system-json"),
|
|
9716
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9572
9717
|
};
|
|
9573
9718
|
return {
|
|
9574
9719
|
actorId: options.actorId,
|
|
@@ -9647,7 +9792,10 @@ function createActorUpdateParams(options) {
|
|
|
9647
9792
|
function createActorCloneParams(options) {
|
|
9648
9793
|
return {
|
|
9649
9794
|
actorId: options.actorId,
|
|
9650
|
-
...optionalPatch(
|
|
9795
|
+
...optionalPatch({
|
|
9796
|
+
...buildActorPatch(options),
|
|
9797
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
9798
|
+
})
|
|
9651
9799
|
};
|
|
9652
9800
|
}
|
|
9653
9801
|
function createActorImportParams(options) {
|
|
@@ -11142,55 +11290,7 @@ function renderJournalDetails(journal) {
|
|
|
11142
11290
|
});
|
|
11143
11291
|
}
|
|
11144
11292
|
pages.forEach((page, index) => {
|
|
11145
|
-
|
|
11146
|
-
lines.push(`page ${pageNumber}: ${page?.id ?? ""} ${page?.name ?? ""} ${page?.type ?? ""}`);
|
|
11147
|
-
const type = page?.type;
|
|
11148
|
-
if (type === "image") {
|
|
11149
|
-
if (page?.src) {
|
|
11150
|
-
lines.push(`page ${pageNumber} src: ${page.src}`);
|
|
11151
|
-
}
|
|
11152
|
-
const caption = page?.image?.caption;
|
|
11153
|
-
if (typeof caption === "string" && caption.length > 0) {
|
|
11154
|
-
const shown = caption.length > 60 ? `${caption.slice(0, 60)}\u2026` : caption;
|
|
11155
|
-
lines.push(`page ${pageNumber} caption: ${shown}`);
|
|
11156
|
-
} else {
|
|
11157
|
-
lines.push(`page ${pageNumber} caption: (none)`);
|
|
11158
|
-
}
|
|
11159
|
-
} else if (type === "video") {
|
|
11160
|
-
if (page?.src) {
|
|
11161
|
-
lines.push(`page ${pageNumber} src: ${page.src}`);
|
|
11162
|
-
}
|
|
11163
|
-
} else if (type === "pdf") {
|
|
11164
|
-
if (page?.src) {
|
|
11165
|
-
lines.push(`page ${pageNumber} src: ${page.src}`);
|
|
11166
|
-
}
|
|
11167
|
-
} else {
|
|
11168
|
-
const format = page?.text?.format;
|
|
11169
|
-
if (format === 2) {
|
|
11170
|
-
lines.push(`page ${pageNumber} format: markdown`);
|
|
11171
|
-
} else if (format === 1) {
|
|
11172
|
-
lines.push(`page ${pageNumber} format: html`);
|
|
11173
|
-
}
|
|
11174
|
-
if (page?.text?.content) {
|
|
11175
|
-
lines.push(`page ${pageNumber} text: ${page.text.content}`);
|
|
11176
|
-
}
|
|
11177
|
-
if (page?.src) {
|
|
11178
|
-
lines.push(`page ${pageNumber} src: ${page.src}`);
|
|
11179
|
-
}
|
|
11180
|
-
}
|
|
11181
|
-
const title = page?.title;
|
|
11182
|
-
if (title && (title.show === false || typeof title.level === "number" && title.level !== 1)) {
|
|
11183
|
-
const bits = [];
|
|
11184
|
-
if (title.show === false) bits.push("show=false");
|
|
11185
|
-
if (typeof title.level === "number" && title.level !== 1) bits.push(`level=${title.level}`);
|
|
11186
|
-
lines.push(`page ${pageNumber} title: ${bits.join(" ")}`);
|
|
11187
|
-
}
|
|
11188
|
-
if (page?.category) {
|
|
11189
|
-
lines.push(`page ${pageNumber} category: ${page.category}`);
|
|
11190
|
-
}
|
|
11191
|
-
if (page && Object.hasOwn(page, "ownership")) {
|
|
11192
|
-
lines.push(...renderOwnershipLines(page.ownership).map((line) => `page ${pageNumber} ${line}`));
|
|
11193
|
-
}
|
|
11293
|
+
lines.push(...renderJournalPageLines(page, `page ${index + 1}`));
|
|
11194
11294
|
});
|
|
11195
11295
|
return lines.join("\n");
|
|
11196
11296
|
}
|
|
@@ -11203,6 +11303,143 @@ function renderJournalCategoryDetails(journalId, category) {
|
|
|
11203
11303
|
`sort: ${category?.sort ?? 0}`
|
|
11204
11304
|
].join("\n");
|
|
11205
11305
|
}
|
|
11306
|
+
function renderJournalPageLines(page, label) {
|
|
11307
|
+
const lines = [];
|
|
11308
|
+
lines.push(`${label}: ${page?.id ?? ""} ${page?.name ?? ""} ${page?.type ?? ""}`);
|
|
11309
|
+
const type = page?.type;
|
|
11310
|
+
if (type === "image") {
|
|
11311
|
+
if (page?.src) {
|
|
11312
|
+
lines.push(`${label} src: ${page.src}`);
|
|
11313
|
+
}
|
|
11314
|
+
const caption = page?.image?.caption;
|
|
11315
|
+
if (typeof caption === "string" && caption.length > 0) {
|
|
11316
|
+
const shown = caption.length > 60 ? `${caption.slice(0, 60)}\u2026` : caption;
|
|
11317
|
+
lines.push(`${label} caption: ${shown}`);
|
|
11318
|
+
} else {
|
|
11319
|
+
lines.push(`${label} caption: (none)`);
|
|
11320
|
+
}
|
|
11321
|
+
} else if (type === "video") {
|
|
11322
|
+
if (page?.src) {
|
|
11323
|
+
lines.push(`${label} src: ${page.src}`);
|
|
11324
|
+
}
|
|
11325
|
+
} else if (type === "pdf") {
|
|
11326
|
+
if (page?.src) {
|
|
11327
|
+
lines.push(`${label} src: ${page.src}`);
|
|
11328
|
+
}
|
|
11329
|
+
} else {
|
|
11330
|
+
const format = page?.text?.format;
|
|
11331
|
+
if (format === 2) {
|
|
11332
|
+
lines.push(`${label} format: markdown`);
|
|
11333
|
+
} else if (format === 1) {
|
|
11334
|
+
lines.push(`${label} format: html`);
|
|
11335
|
+
}
|
|
11336
|
+
if (page?.text?.content) {
|
|
11337
|
+
lines.push(`${label} text: ${page.text.content}`);
|
|
11338
|
+
}
|
|
11339
|
+
if (page?.src) {
|
|
11340
|
+
lines.push(`${label} src: ${page.src}`);
|
|
11341
|
+
}
|
|
11342
|
+
}
|
|
11343
|
+
const title = page?.title;
|
|
11344
|
+
if (title && (title.show === false || typeof title.level === "number" && title.level !== 1)) {
|
|
11345
|
+
const bits = [];
|
|
11346
|
+
if (title.show === false) bits.push("show=false");
|
|
11347
|
+
if (typeof title.level === "number" && title.level !== 1) bits.push(`level=${title.level}`);
|
|
11348
|
+
lines.push(`${label} title: ${bits.join(" ")}`);
|
|
11349
|
+
}
|
|
11350
|
+
if (page?.category) {
|
|
11351
|
+
lines.push(`${label} category: ${page.category}`);
|
|
11352
|
+
}
|
|
11353
|
+
if (page && Object.hasOwn(page, "ownership")) {
|
|
11354
|
+
lines.push(...renderOwnershipLines(page.ownership).map((line) => `${label} ${line}`));
|
|
11355
|
+
}
|
|
11356
|
+
return lines;
|
|
11357
|
+
}
|
|
11358
|
+
function renderJournalPageDetails(journalId, page) {
|
|
11359
|
+
return [`journal: ${journalId}`, ...renderJournalPageLines(page, "page")].join("\n");
|
|
11360
|
+
}
|
|
11361
|
+
|
|
11362
|
+
// src/render/settings.ts
|
|
11363
|
+
function renderSettingSummaryLine(setting) {
|
|
11364
|
+
const label = setting?.nameLocalized && setting.nameLocalized !== setting.name ? `${setting.nameLocalized} [${setting.name}]` : setting?.nameLocalized ?? setting?.name ?? "(unnamed)";
|
|
11365
|
+
return [
|
|
11366
|
+
setting?.id ?? `${setting?.namespace ?? "?"}.${setting?.key ?? "?"}`,
|
|
11367
|
+
label,
|
|
11368
|
+
`scope=${setting?.scope ?? "?"}`,
|
|
11369
|
+
`type=${setting?.type?.kind ?? "-"}`,
|
|
11370
|
+
`config=${Boolean(setting?.config)}`,
|
|
11371
|
+
`reload=${Boolean(setting?.requiresReload)}`,
|
|
11372
|
+
...setting?.metadataReadFailed ? ["metadata=UNREADABLE"] : [],
|
|
11373
|
+
...setting?.unaddressable ? ["address=UNADDRESSABLE"] : [],
|
|
11374
|
+
...setting?.valueRedacted ? ["value=REDACTED"] : []
|
|
11375
|
+
].join(" ");
|
|
11376
|
+
}
|
|
11377
|
+
function renderSettingValue(value) {
|
|
11378
|
+
return JSON.stringify(value ?? null, null, 2);
|
|
11379
|
+
}
|
|
11380
|
+
function renderOmissionLines(label, omissions, truncated) {
|
|
11381
|
+
if (!Array.isArray(omissions) || omissions.length === 0) return [];
|
|
11382
|
+
return [
|
|
11383
|
+
`${label} incomplete: ${omissions.length}${truncated ? "+" : ""} node(s) replaced by {"$unserializable": <reason>}`,
|
|
11384
|
+
...omissions.map((omission) => ` ${omission?.path ?? "?"} ${omission?.reason ?? "?"}`)
|
|
11385
|
+
];
|
|
11386
|
+
}
|
|
11387
|
+
function renderSettingWriteLines(row, dryRun) {
|
|
11388
|
+
const verb = dryRun ? "would write" : row?.changed ? "wrote" : "left unchanged";
|
|
11389
|
+
return [
|
|
11390
|
+
`${verb}: ${row?.id ?? `${row?.namespace}.${row?.key}`} (scope: ${row?.scope ?? "?"})`,
|
|
11391
|
+
`previous: ${renderSettingValue(row?.previous)}`,
|
|
11392
|
+
...renderOmissionLines("previous", row?.previousOmissions, row?.previousOmissionsTruncated),
|
|
11393
|
+
`${dryRun ? "requested" : "value"}: ${renderSettingValue(row?.value)}`,
|
|
11394
|
+
...renderOmissionLines("value", row?.valueOmissions, row?.valueOmissionsTruncated),
|
|
11395
|
+
`changed: ${Boolean(row?.changed)} / validated: ${Boolean(row?.validated)}`,
|
|
11396
|
+
...row?.requiresReload ? ["requiresReload: true \u2014 Foundry acts on this only after `system reload` or a manual browser reload"] : ["requiresReload: false"]
|
|
11397
|
+
];
|
|
11398
|
+
}
|
|
11399
|
+
function renderSettingWriteResult(result) {
|
|
11400
|
+
return renderSettingWriteLines(result, Boolean(result?.dryRun)).join("\n");
|
|
11401
|
+
}
|
|
11402
|
+
function renderSettingWriteOutcomes(result) {
|
|
11403
|
+
const outcomes = result?.outcomes ?? [];
|
|
11404
|
+
const dryRun = Boolean(result?.dryRun);
|
|
11405
|
+
const lines = [
|
|
11406
|
+
`${dryRun ? "Would write" : "Wrote"} settings (${outcomes.length}) \u2014 complete: ${Boolean(result?.complete)}`,
|
|
11407
|
+
...outcomes.flatMap(
|
|
11408
|
+
(outcome) => outcome?.status === "updated" || outcome?.status === "unchanged" ? [
|
|
11409
|
+
`[${outcome.index}] ${outcome.status}`,
|
|
11410
|
+
...renderSettingWriteLines(outcome, dryRun).map((line) => ` ${line}`)
|
|
11411
|
+
] : [`[${outcome?.index}] ${outcome?.status} ${outcome?.id ?? ""}`]
|
|
11412
|
+
)
|
|
11413
|
+
];
|
|
11414
|
+
if (result?.failure) {
|
|
11415
|
+
lines.push(`failure: ${result.failure.code} \u2014 ${result.failure.message}`);
|
|
11416
|
+
}
|
|
11417
|
+
return lines.join("\n");
|
|
11418
|
+
}
|
|
11419
|
+
function renderSettingBatchRows(setting) {
|
|
11420
|
+
return [
|
|
11421
|
+
renderSettingSummaryLine(setting),
|
|
11422
|
+
...setting?.error ? [` error: ${setting.error.code} \u2014 ${setting.error.message}`] : [
|
|
11423
|
+
` value: ${renderSettingValue(setting?.value)}`,
|
|
11424
|
+
...renderOmissionLines("value", setting?.valueOmissions, setting?.valueOmissionsTruncated).map(
|
|
11425
|
+
(line) => ` ${line}`
|
|
11426
|
+
)
|
|
11427
|
+
]
|
|
11428
|
+
];
|
|
11429
|
+
}
|
|
11430
|
+
function renderSettingDetails(setting) {
|
|
11431
|
+
return [
|
|
11432
|
+
`setting: ${setting?.id ?? `${setting?.namespace}.${setting?.key}`}`,
|
|
11433
|
+
`name: ${setting?.nameLocalized ?? "(none)"}${setting?.name && setting.name !== setting.nameLocalized ? ` (raw: ${setting.name})` : ""}`,
|
|
11434
|
+
`hint: ${setting?.hintLocalized ?? "(none)"}${setting?.hint && setting.hint !== setting.hintLocalized ? ` (raw: ${setting.hint})` : ""}`,
|
|
11435
|
+
`scope: ${setting?.scope ?? "?"}`,
|
|
11436
|
+
`type: ${setting?.type?.kind ?? "(untyped)"}`,
|
|
11437
|
+
`config: ${Boolean(setting?.config)} / requiresReload: ${Boolean(setting?.requiresReload)}`,
|
|
11438
|
+
...setting?.metadataReadFailed ? [`metadata: UNREADABLE (${setting.metadataReadError ?? "unknown error"})`] : [],
|
|
11439
|
+
setting?.valueRedacted ? "value: null (REDACTED \u2014 authorization settings are never exposed through setting commands)" : `value: ${JSON.stringify(setting?.value ?? null, null, 2)}`,
|
|
11440
|
+
...renderOmissionLines("value", setting?.valueOmissions, setting?.valueOmissionsTruncated)
|
|
11441
|
+
].join("\n");
|
|
11442
|
+
}
|
|
11206
11443
|
|
|
11207
11444
|
// src/render/macros.ts
|
|
11208
11445
|
var CHAT_CAPTURE_NOTES = {
|
|
@@ -11225,6 +11462,9 @@ function renderMacroExecuteResult(result) {
|
|
|
11225
11462
|
`type: ${result?.type ?? "(unknown)"}`,
|
|
11226
11463
|
`returned: ${JSON.stringify(result?.returned ?? null, null, 2)}`
|
|
11227
11464
|
];
|
|
11465
|
+
lines.push(
|
|
11466
|
+
...renderOmissionLines("returned", result?.returnedOmissions, result?.returnedOmissionsTruncated)
|
|
11467
|
+
);
|
|
11228
11468
|
if (result?.returnedOmitted) {
|
|
11229
11469
|
lines.push(`returned omitted: ${result.returnedOmitted.code} \u2014 ${result.returnedOmitted.message}`);
|
|
11230
11470
|
}
|
|
@@ -11578,73 +11818,6 @@ function renderRegionBehaviorDetails(sceneId, regionId, behavior) {
|
|
|
11578
11818
|
].join("\n");
|
|
11579
11819
|
}
|
|
11580
11820
|
|
|
11581
|
-
// src/render/settings.ts
|
|
11582
|
-
function renderSettingSummaryLine(setting) {
|
|
11583
|
-
const label = setting?.nameLocalized && setting.nameLocalized !== setting.name ? `${setting.nameLocalized} [${setting.name}]` : setting?.nameLocalized ?? setting?.name ?? "(unnamed)";
|
|
11584
|
-
return [
|
|
11585
|
-
setting?.id ?? `${setting?.namespace ?? "?"}.${setting?.key ?? "?"}`,
|
|
11586
|
-
label,
|
|
11587
|
-
`scope=${setting?.scope ?? "?"}`,
|
|
11588
|
-
`type=${setting?.type?.kind ?? "-"}`,
|
|
11589
|
-
`config=${Boolean(setting?.config)}`,
|
|
11590
|
-
`reload=${Boolean(setting?.requiresReload)}`,
|
|
11591
|
-
...setting?.metadataReadFailed ? ["metadata=UNREADABLE"] : [],
|
|
11592
|
-
...setting?.unaddressable ? ["address=UNADDRESSABLE"] : [],
|
|
11593
|
-
...setting?.valueRedacted ? ["value=REDACTED"] : []
|
|
11594
|
-
].join(" ");
|
|
11595
|
-
}
|
|
11596
|
-
function renderSettingValue(value) {
|
|
11597
|
-
return JSON.stringify(value ?? null, null, 2);
|
|
11598
|
-
}
|
|
11599
|
-
function renderSettingWriteLines(row, dryRun) {
|
|
11600
|
-
const verb = dryRun ? "would write" : row?.changed ? "wrote" : "left unchanged";
|
|
11601
|
-
return [
|
|
11602
|
-
`${verb}: ${row?.id ?? `${row?.namespace}.${row?.key}`} (scope: ${row?.scope ?? "?"})`,
|
|
11603
|
-
`previous: ${renderSettingValue(row?.previous)}`,
|
|
11604
|
-
`${dryRun ? "requested" : "value"}: ${renderSettingValue(row?.value)}`,
|
|
11605
|
-
`changed: ${Boolean(row?.changed)} / validated: ${Boolean(row?.validated)}`,
|
|
11606
|
-
...row?.requiresReload ? ["requiresReload: true \u2014 Foundry acts on this only after `system reload` or a manual browser reload"] : ["requiresReload: false"]
|
|
11607
|
-
];
|
|
11608
|
-
}
|
|
11609
|
-
function renderSettingWriteResult(result) {
|
|
11610
|
-
return renderSettingWriteLines(result, Boolean(result?.dryRun)).join("\n");
|
|
11611
|
-
}
|
|
11612
|
-
function renderSettingWriteOutcomes(result) {
|
|
11613
|
-
const outcomes = result?.outcomes ?? [];
|
|
11614
|
-
const dryRun = Boolean(result?.dryRun);
|
|
11615
|
-
const lines = [
|
|
11616
|
-
`${dryRun ? "Would write" : "Wrote"} settings (${outcomes.length}) \u2014 complete: ${Boolean(result?.complete)}`,
|
|
11617
|
-
...outcomes.flatMap(
|
|
11618
|
-
(outcome) => outcome?.status === "updated" || outcome?.status === "unchanged" ? [
|
|
11619
|
-
`[${outcome.index}] ${outcome.status}`,
|
|
11620
|
-
...renderSettingWriteLines(outcome, dryRun).map((line) => ` ${line}`)
|
|
11621
|
-
] : [`[${outcome?.index}] ${outcome?.status} ${outcome?.id ?? ""}`]
|
|
11622
|
-
)
|
|
11623
|
-
];
|
|
11624
|
-
if (result?.failure) {
|
|
11625
|
-
lines.push(`failure: ${result.failure.code} \u2014 ${result.failure.message}`);
|
|
11626
|
-
}
|
|
11627
|
-
return lines.join("\n");
|
|
11628
|
-
}
|
|
11629
|
-
function renderSettingBatchRows(setting) {
|
|
11630
|
-
return [
|
|
11631
|
-
renderSettingSummaryLine(setting),
|
|
11632
|
-
...setting?.error ? [` error: ${setting.error.code} \u2014 ${setting.error.message}`] : [` value: ${renderSettingValue(setting?.value)}`]
|
|
11633
|
-
];
|
|
11634
|
-
}
|
|
11635
|
-
function renderSettingDetails(setting) {
|
|
11636
|
-
return [
|
|
11637
|
-
`setting: ${setting?.id ?? `${setting?.namespace}.${setting?.key}`}`,
|
|
11638
|
-
`name: ${setting?.nameLocalized ?? "(none)"}${setting?.name && setting.name !== setting.nameLocalized ? ` (raw: ${setting.name})` : ""}`,
|
|
11639
|
-
`hint: ${setting?.hintLocalized ?? "(none)"}${setting?.hint && setting.hint !== setting.hintLocalized ? ` (raw: ${setting.hint})` : ""}`,
|
|
11640
|
-
`scope: ${setting?.scope ?? "?"}`,
|
|
11641
|
-
`type: ${setting?.type?.kind ?? "(untyped)"}`,
|
|
11642
|
-
`config: ${Boolean(setting?.config)} / requiresReload: ${Boolean(setting?.requiresReload)}`,
|
|
11643
|
-
...setting?.metadataReadFailed ? [`metadata: UNREADABLE (${setting.metadataReadError ?? "unknown error"})`] : [],
|
|
11644
|
-
setting?.valueRedacted ? "value: null (REDACTED \u2014 authorization settings are never exposed through setting commands)" : `value: ${JSON.stringify(setting?.value ?? null, null, 2)}`
|
|
11645
|
-
].join("\n");
|
|
11646
|
-
}
|
|
11647
|
-
|
|
11648
11821
|
// src/render/tables.ts
|
|
11649
11822
|
function renderTableResultLine(result, ownerColumns = []) {
|
|
11650
11823
|
const range = Array.isArray(result?.range) ? result.range.join("-") : "";
|
|
@@ -11950,6 +12123,28 @@ var RENDERERS = registerRenderers([
|
|
|
11950
12123
|
}
|
|
11951
12124
|
return lines.join("\n");
|
|
11952
12125
|
}),
|
|
12126
|
+
customRenderer("world.references", (result, offset) => {
|
|
12127
|
+
const references = result.references ?? [];
|
|
12128
|
+
const target = result.target ?? {};
|
|
12129
|
+
const lines = [
|
|
12130
|
+
`target: ${target.uuid ?? ""} ${humanCell(target.name)} exists=${target.exists === null ? "unknown" : String(target.exists)}`
|
|
12131
|
+
];
|
|
12132
|
+
if (references.length) {
|
|
12133
|
+
lines.push(
|
|
12134
|
+
`References (${references.length})`,
|
|
12135
|
+
...references.map(
|
|
12136
|
+
(ref) => `${ref.uuid} ${humanCell(ref.name)} ${ref.field} ${ref.match}${ref.matchedUuid ? ` ${ref.matchedUuid}` : ""}`
|
|
12137
|
+
)
|
|
12138
|
+
);
|
|
12139
|
+
} else {
|
|
12140
|
+
lines.push("No stored references found.");
|
|
12141
|
+
}
|
|
12142
|
+
lines.push(...listFooterLines(result, references.length, offset));
|
|
12143
|
+
lines.push(
|
|
12144
|
+
`summary: references=${result.total ?? references.length} scannedDocuments=${result.scannedDocuments ?? 0} selfReferences=${result.selfReferences ?? 0} scopes=${(result.scopes ?? []).join(",")}`
|
|
12145
|
+
);
|
|
12146
|
+
return lines.join("\n");
|
|
12147
|
+
}),
|
|
11953
12148
|
listRenderer("scene.list", {
|
|
11954
12149
|
key: "scenes",
|
|
11955
12150
|
empty: "No scenes found.",
|
|
@@ -12314,6 +12509,21 @@ var RENDERERS = registerRenderers([
|
|
|
12314
12509
|
}),
|
|
12315
12510
|
deleteRenderer("journal.delete", "journal"),
|
|
12316
12511
|
detailRenderer("journal.show", (result) => renderJournalShowResult(result)),
|
|
12512
|
+
listRenderer("journal.page.list", {
|
|
12513
|
+
key: "pages",
|
|
12514
|
+
empty: "No pages found.",
|
|
12515
|
+
heading: "Pages",
|
|
12516
|
+
prefix: (result) => [`journal: ${result.journalId}`],
|
|
12517
|
+
row: (page) => `${page.id} ${page.name ?? ""} ${page.type ?? ""} sort=${page.sort ?? 0}${page.textFormat === 2 ? " format=markdown" : page.textFormat === 1 ? " format=html" : ""}`
|
|
12518
|
+
}),
|
|
12519
|
+
detailRenderer(
|
|
12520
|
+
["journal.page.get", "journal.page.create", "journal.page.update"],
|
|
12521
|
+
(result) => renderJournalPageDetails(result.journalId, result.page)
|
|
12522
|
+
),
|
|
12523
|
+
detailRenderer(
|
|
12524
|
+
"journal.page.delete",
|
|
12525
|
+
(result) => result.deleted ? `Deleted journal page ${result.id} from journal ${result.journalId}` : `Would delete journal page ${result.id} from journal ${result.journalId}`
|
|
12526
|
+
),
|
|
12317
12527
|
listRenderer("journal.category.list", {
|
|
12318
12528
|
key: "categories",
|
|
12319
12529
|
empty: "No categories found.",
|
|
@@ -13454,6 +13664,28 @@ function addJournalCategoryFieldOptions(command, verb) {
|
|
|
13454
13664
|
const ordered = verb === "create" ? [JOURNAL_CATEGORY_SORT_FIELD] : [JOURNAL_CATEGORY_NAME_FIELD, JOURNAL_CATEGORY_SORT_FIELD];
|
|
13455
13665
|
return addFieldOptions(command, verb, ordered);
|
|
13456
13666
|
}
|
|
13667
|
+
var JOURNAL_PAGE_FIELDS = [
|
|
13668
|
+
{
|
|
13669
|
+
flag: "--sort <sort>",
|
|
13670
|
+
help: { create: "Page sort value", update: "New page sort value" },
|
|
13671
|
+
parser: parseNumber
|
|
13672
|
+
},
|
|
13673
|
+
{
|
|
13674
|
+
flag: "--category <categoryId>",
|
|
13675
|
+
help: {
|
|
13676
|
+
create: "Category id from journal category list",
|
|
13677
|
+
update: "New category id from journal category list"
|
|
13678
|
+
}
|
|
13679
|
+
},
|
|
13680
|
+
{ flag: "--clear-category", help: "Explicitly set category to null", conflicts: "category" },
|
|
13681
|
+
{
|
|
13682
|
+
flag: "--src <src>",
|
|
13683
|
+
help: { create: "Media path of an image, pdf or video page", update: "New media path" }
|
|
13684
|
+
}
|
|
13685
|
+
];
|
|
13686
|
+
function addJournalPageFieldOptions(command, verb) {
|
|
13687
|
+
return addFieldOptions(command, verb, JOURNAL_PAGE_FIELDS);
|
|
13688
|
+
}
|
|
13457
13689
|
var PLAYLIST_FIELDS = [
|
|
13458
13690
|
{
|
|
13459
13691
|
flag: "--description <description>",
|
|
@@ -14318,7 +14550,7 @@ function registerActor({ program, dependencies }) {
|
|
|
14318
14550
|
addActorFieldOptions(
|
|
14319
14551
|
addIdempotencyKeyOption(actor.command("clone")).requiredOption("--actor-id <actorId>", "Source actor id").option("--name <name>", "Name override for the clone"),
|
|
14320
14552
|
"clone"
|
|
14321
|
-
).action(async function cloneActorCommand(options) {
|
|
14553
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneActorCommand(options) {
|
|
14322
14554
|
await executeRemoteCommand({
|
|
14323
14555
|
commandName: "actor.clone",
|
|
14324
14556
|
params: createActorCloneParams(options),
|
|
@@ -14343,6 +14575,12 @@ function registerActor({ program, dependencies }) {
|
|
|
14343
14575
|
});
|
|
14344
14576
|
});
|
|
14345
14577
|
const actorItem = actor.command("item").description("Foundry actor embedded item commands");
|
|
14578
|
+
registerBatchWriteCommands(actorItem, {
|
|
14579
|
+
prefix: "actor.item",
|
|
14580
|
+
noun: "item",
|
|
14581
|
+
scope: "actor",
|
|
14582
|
+
dataHelp: "Item data as a JSON ARRAY of objects; each element takes what `actor item create --data-json` takes plus name and type"
|
|
14583
|
+
});
|
|
14346
14584
|
addNameFilterOption(
|
|
14347
14585
|
addPaginationOptions(actorItem.command("list").requiredOption("--actor-id <actorId>", "Actor id")).option(
|
|
14348
14586
|
"--include <fields>",
|
|
@@ -14408,7 +14646,7 @@ function registerActor({ program, dependencies }) {
|
|
|
14408
14646
|
addEmbeddedItemFieldOptions(
|
|
14409
14647
|
addIdempotencyKeyOption(actorItem.command("clone")).requiredOption("--actor-id <actorId>", "Actor id").requiredOption("--item-id <itemId>", "Source item id").option("--name <name>", "Name override for the clone"),
|
|
14410
14648
|
"clone"
|
|
14411
|
-
).action(async function cloneActorItem(options) {
|
|
14649
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneActorItem(options) {
|
|
14412
14650
|
await executeRemoteCommand({
|
|
14413
14651
|
commandName: "actor.item.clone",
|
|
14414
14652
|
params: createActorItemCloneParams(options),
|
|
@@ -15066,7 +15304,7 @@ function registerBridge({ program, dependencies }) {
|
|
|
15066
15304
|
});
|
|
15067
15305
|
bridge.command("serve").description("Start the local bridge daemon").option("--request-timeout-ms <ms>", "Response timeout for forwarded Foundry requests", parsePositiveInt).option(
|
|
15068
15306
|
"--upload-limit-bytes <size>",
|
|
15069
|
-
"Override the file.upload size limit as bytes or a size like 100MiB (max 512MiB)"
|
|
15307
|
+
"Override the file.upload and file.read size limit for this run, as bytes or a size like 100MiB (max 512MiB)"
|
|
15070
15308
|
).action(async function serveBridge(options) {
|
|
15071
15309
|
const bridgeConfig = getBridgeDaemonConfig(this, options, dependencies);
|
|
15072
15310
|
const flagUploadLimitBytes = typeof options.uploadLimitBytes === "string" ? parseUploadLimitBytes(options.uploadLimitBytes) : void 0;
|
|
@@ -15845,7 +16083,9 @@ function registerConfig({ program, dependencies }) {
|
|
|
15845
16083
|
write(dependencies.stdout, `${renderConfigGetHumanOutput(configPath, displayConfig)}
|
|
15846
16084
|
`);
|
|
15847
16085
|
});
|
|
15848
|
-
config.command("set-upload-limit").description(
|
|
16086
|
+
config.command("set-upload-limit").description(
|
|
16087
|
+
"Persist the file.upload and file.read size limit (raw bytes, pre-base64) for the daemon and CLI"
|
|
16088
|
+
).argument("<size>", "Upload size limit as bytes or a size like 100MiB (max 512MiB)").action(function setUploadLimit(size) {
|
|
15849
16089
|
const uploadLimitBytes = parseUploadLimitBytes(size);
|
|
15850
16090
|
writeCliConfigUpdate(dependencies.configStore, { uploadLimitBytes });
|
|
15851
16091
|
const payload = {
|
|
@@ -16116,8 +16356,13 @@ function registerFile({ program, dependencies }) {
|
|
|
16116
16356
|
dependencies
|
|
16117
16357
|
});
|
|
16118
16358
|
});
|
|
16119
|
-
file.command("read").
|
|
16359
|
+
file.command("read").description(
|
|
16360
|
+
`Read a file's content; a file over the upload limit (system info: limits.uploadBytes) or about ${Math.floor(READ_ENCODING_CEILING_BYTES / (1024 * 1024))} MiB returns PAYLOAD_TOO_LARGE`
|
|
16361
|
+
).requiredOption("--path <path>", "Data-relative file path").addOption(
|
|
16120
16362
|
new Option7("--encoding <encoding>", "Read encoding").choices(["text", "base64"]).makeOptionMandatory()
|
|
16363
|
+
).addHelpText(
|
|
16364
|
+
"after",
|
|
16365
|
+
"\nThe CLI's receive limit follows the persisted limit (config set-upload-limit), not bridge serve --upload-limit-bytes; a larger response closes this command's connection.\nText escapes control bytes in JSON; read a binary file as base64."
|
|
16121
16366
|
).action(async function readFileCommand(options) {
|
|
16122
16367
|
await executeRemoteCommand({
|
|
16123
16368
|
commandName: "file.read",
|
|
@@ -16392,7 +16637,7 @@ function registerItem({ program, dependencies }) {
|
|
|
16392
16637
|
addItemFieldOptions(
|
|
16393
16638
|
addIdempotencyKeyOption(item.command("clone")).requiredOption("--item-id <itemId>", "Source item id").option("--name <name>", "Name override for the clone"),
|
|
16394
16639
|
"clone"
|
|
16395
|
-
).action(async function cloneItem(options) {
|
|
16640
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneItem(options) {
|
|
16396
16641
|
await executeRemoteCommand({
|
|
16397
16642
|
commandName: "item.clone",
|
|
16398
16643
|
params: createItemCloneParams(options),
|
|
@@ -16563,7 +16808,7 @@ function registerJournal({ program, dependencies }) {
|
|
|
16563
16808
|
addJournalFieldOptions(
|
|
16564
16809
|
addIdempotencyKeyOption(journal.command("clone")).requiredOption("--journal-id <journalId>", "Source journal id").option("--name <name>", "Name override for the clone"),
|
|
16565
16810
|
"clone"
|
|
16566
|
-
).action(async function cloneJournal(options) {
|
|
16811
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneJournal(options) {
|
|
16567
16812
|
await executeRemoteCommand({
|
|
16568
16813
|
commandName: "journal.clone",
|
|
16569
16814
|
params: createJournalCloneParams(options),
|
|
@@ -16579,6 +16824,64 @@ function registerJournal({ program, dependencies }) {
|
|
|
16579
16824
|
dependencies
|
|
16580
16825
|
});
|
|
16581
16826
|
});
|
|
16827
|
+
const journalPage = journal.command("page").description("Journal-embedded page commands (one page at a time; journal update batches several)");
|
|
16828
|
+
journalPage.addHelpText(
|
|
16829
|
+
"after",
|
|
16830
|
+
`
|
|
16831
|
+
Result key (--json): .result.page (get and writes) / .result.pages[] (list), with .result.journalId.
|
|
16832
|
+
list returns summaries without text, system or flags, with textFormat (1 HTML, 2 Markdown, null on media pages); get returns the full page.
|
|
16833
|
+
Text fields belong to text pages, src to image, pdf and video pages, image.caption to image pages (schema journal.page.create).
|
|
16834
|
+
Text content goes through --data-json/--patch-json, e.g. --patch-json '{"text":{"content":"<p>\u2026</p>"}}'.
|
|
16835
|
+
Page ownership: journal ownership set --journal-id <id> --page-id <pageId>.`
|
|
16836
|
+
);
|
|
16837
|
+
addNameFilterOption(
|
|
16838
|
+
addPaginationOptions(journalPage.command("list").requiredOption("--journal-id <journalId>", "Journal id"))
|
|
16839
|
+
).action(async function listJournalPages(options) {
|
|
16840
|
+
await executeRemoteCommand({
|
|
16841
|
+
commandName: "journal.page.list",
|
|
16842
|
+
params: { journalId: options.journalId, ...nameFilterParams(options), ...paginationParams(options) },
|
|
16843
|
+
command: this,
|
|
16844
|
+
dependencies
|
|
16845
|
+
});
|
|
16846
|
+
});
|
|
16847
|
+
journalPage.command("get").requiredOption("--journal-id <journalId>", "Journal id").requiredOption("--page-id <pageId>", "Page id").action(async function getJournalPage(options) {
|
|
16848
|
+
await executeRemoteCommand({
|
|
16849
|
+
commandName: "journal.page.get",
|
|
16850
|
+
params: { journalId: options.journalId, pageId: options.pageId },
|
|
16851
|
+
command: this,
|
|
16852
|
+
dependencies
|
|
16853
|
+
});
|
|
16854
|
+
});
|
|
16855
|
+
addJournalPageFieldOptions(
|
|
16856
|
+
addIdempotencyKeyOption(journalPage.command("create")).requiredOption("--journal-id <journalId>", "Journal id").requiredOption("--name <name>", "Page name").requiredOption("--type <type>", "Page type (text, image, pdf, video, or a system page type)"),
|
|
16857
|
+
"create"
|
|
16858
|
+
).option("--data-json <json>", "Full/extra page data as a JSON object (merged last)").action(async function createJournalPage(options) {
|
|
16859
|
+
await executeRemoteCommand({
|
|
16860
|
+
commandName: "journal.page.create",
|
|
16861
|
+
params: createJournalPageCreateParams(options),
|
|
16862
|
+
command: this,
|
|
16863
|
+
dependencies
|
|
16864
|
+
});
|
|
16865
|
+
});
|
|
16866
|
+
addJournalPageFieldOptions(
|
|
16867
|
+
journalPage.command("update").requiredOption("--journal-id <journalId>", "Journal id").requiredOption("--page-id <pageId>", "Page id").option("--name <name>", "New page name").option("--type <type>", "New page type"),
|
|
16868
|
+
"update"
|
|
16869
|
+
).option("--patch-json <json>", "Full/extra page patch as a JSON object (merged last)").action(async function updateJournalPage(options) {
|
|
16870
|
+
await executeRemoteCommand({
|
|
16871
|
+
commandName: "journal.page.update",
|
|
16872
|
+
params: createJournalPageUpdateParams(options),
|
|
16873
|
+
command: this,
|
|
16874
|
+
dependencies
|
|
16875
|
+
});
|
|
16876
|
+
});
|
|
16877
|
+
journalPage.command("delete").requiredOption("--journal-id <journalId>", "Journal id").requiredOption("--page-id <pageId>", "Page id").action(async function deleteJournalPage(options) {
|
|
16878
|
+
await executeRemoteCommand({
|
|
16879
|
+
commandName: "journal.page.delete",
|
|
16880
|
+
params: { journalId: options.journalId, pageId: options.pageId },
|
|
16881
|
+
command: this,
|
|
16882
|
+
dependencies
|
|
16883
|
+
});
|
|
16884
|
+
});
|
|
16582
16885
|
const journalCategory = journal.command("category").description("Journal-embedded category commands (labels pages are grouped under)");
|
|
16583
16886
|
journalCategory.addHelpText(
|
|
16584
16887
|
"after",
|
|
@@ -16736,7 +17039,7 @@ function registerMacro({ program, dependencies }) {
|
|
|
16736
17039
|
addMacroFieldOptions(
|
|
16737
17040
|
addIdempotencyKeyOption(macro.command("clone")).requiredOption("--macro-id <macroId>", "Source macro id").option("--name <name>", "Name override for the clone"),
|
|
16738
17041
|
"clone"
|
|
16739
|
-
).action(async function cloneMacroCommand(options) {
|
|
17042
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneMacroCommand(options) {
|
|
16740
17043
|
const command = await resolveMacroCommandBody(options, dependencies);
|
|
16741
17044
|
await executeRemoteCommand({
|
|
16742
17045
|
commandName: "macro.clone",
|
|
@@ -16758,6 +17061,10 @@ function registerMacro({ program, dependencies }) {
|
|
|
16758
17061
|
"--macro-timeout-ms <ms>",
|
|
16759
17062
|
`How long the GM client waits for the macro, in ms (default ${MACRO_EXECUTE_TIMEOUT_DEFAULT_MS}, max ${MACRO_EXECUTE_TIMEOUT_MAX_MS}). Raise the global --timeout-ms above it, or the CLI stops waiting before MACRO_TIMEOUT can be reported.`
|
|
16760
17063
|
).argParser(parsePositiveInt)
|
|
17064
|
+
).addHelpText(
|
|
17065
|
+
"after",
|
|
17066
|
+
`
|
|
17067
|
+
A return value node with no JSON form (a function, an own accessor, a circular reference) comes back as {"$unserializable": "<reason>"} and is listed in .result.returnedOmissions (at most ${SERIALIZE_OMISSIONS_MAX} entries); a return value over the size limits is dropped and explained in .result.returnedOmitted.`
|
|
16761
17068
|
).action(async function executeMacroCommand(options) {
|
|
16762
17069
|
await executeRemoteCommand({
|
|
16763
17070
|
commandName: "macro.execute",
|
|
@@ -17043,7 +17350,7 @@ function registerScene({ program, dependencies }) {
|
|
|
17043
17350
|
addSceneFieldOptions(
|
|
17044
17351
|
addIdempotencyKeyOption(scene.command("clone")).requiredOption("--scene-id <sceneId>", "Source scene id").option("--name <name>", "Name override for the clone"),
|
|
17045
17352
|
"clone"
|
|
17046
|
-
).action(async function cloneScene(options) {
|
|
17353
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneScene(options) {
|
|
17047
17354
|
await executeRemoteCommand({
|
|
17048
17355
|
commandName: "scene.clone",
|
|
17049
17356
|
params: createSceneCloneParams(options),
|
|
@@ -17121,6 +17428,9 @@ function registerScene({ program, dependencies }) {
|
|
|
17121
17428
|
"--include <fields>",
|
|
17122
17429
|
"Comma-separated extra fields to include (allowed: delta \u2014 a derived per-token summary of the token-level overrides, null when there are none)",
|
|
17123
17430
|
parseTokenListIncludeFields
|
|
17431
|
+
).addHelpText(
|
|
17432
|
+
"after",
|
|
17433
|
+
"\nThe tokens of one actor across all scenes: world references --uuid Actor.<actorId> --scope scene"
|
|
17124
17434
|
).action(async function listSceneTokens(options) {
|
|
17125
17435
|
await executeRemoteCommand({
|
|
17126
17436
|
commandName: "scene.token.list",
|
|
@@ -17164,7 +17474,11 @@ function registerScene({ program, dependencies }) {
|
|
|
17164
17474
|
addTokenFieldOptions(
|
|
17165
17475
|
sceneToken.command("update").requiredOption("--scene-id <sceneId>", "Scene id").requiredOption("--token-id <tokenId>", "Token id"),
|
|
17166
17476
|
"update"
|
|
17167
|
-
).option("--patch-json <json>", "Full/extra token patch as a JSON object (merged last)").
|
|
17477
|
+
).option("--patch-json <json>", "Full/extra token patch as a JSON object (merged last)").addHelpText(
|
|
17478
|
+
"after",
|
|
17479
|
+
`
|
|
17480
|
+
A patch with "delta": {"items": []} keeps the token's item overrides. scene token restore-delta drops every token override; scene token item update/delete changes single items.`
|
|
17481
|
+
).action(async function updateSceneToken(options) {
|
|
17168
17482
|
await executeRemoteCommand({
|
|
17169
17483
|
commandName: "scene.token.update",
|
|
17170
17484
|
params: createSceneTokenUpdateParams(options),
|
|
@@ -17270,12 +17584,13 @@ function registerScene({ program, dependencies }) {
|
|
|
17270
17584
|
addEmbeddedItemFieldOptions(
|
|
17271
17585
|
addIdempotencyKeyOption(sceneTokenItem.command("clone")).requiredOption("--scene-id <sceneId>", "Scene id").requiredOption("--token-id <tokenId>", "Token id").requiredOption("--item-id <itemId>", "Source item id").option("--name <name>", "Name override for the clone"),
|
|
17272
17586
|
"clone"
|
|
17273
|
-
).action(async function cloneSceneTokenItem(options) {
|
|
17587
|
+
).option("--patch-json <json>", "Override fields for the clone as a JSON object (merged last)").action(async function cloneSceneTokenItem(options) {
|
|
17274
17588
|
const patch = {
|
|
17275
17589
|
...stringField("name", options.name),
|
|
17276
17590
|
...stringField("img", options.img),
|
|
17277
17591
|
...numberField("sort", options.sort),
|
|
17278
|
-
...jsonObjectField("system", options.systemJson, "--system-json")
|
|
17592
|
+
...jsonObjectField("system", options.systemJson, "--system-json"),
|
|
17593
|
+
...optionalJsonObject(options.patchJson, "--patch-json") ?? {}
|
|
17279
17594
|
};
|
|
17280
17595
|
await executeRemoteCommand({
|
|
17281
17596
|
commandName: "scene.token.item.clone",
|
|
@@ -18144,7 +18459,11 @@ function registerSetting({ program, dependencies }) {
|
|
|
18144
18459
|
});
|
|
18145
18460
|
}
|
|
18146
18461
|
);
|
|
18147
|
-
setting.command("get").requiredOption("--namespace <namespace>", 'Setting namespace (e.g. "core" or a module id)').requiredOption("--key <key>", "Setting key within the namespace").
|
|
18462
|
+
setting.command("get").requiredOption("--namespace <namespace>", 'Setting namespace (e.g. "core" or a module id)').requiredOption("--key <key>", "Setting key within the namespace").addHelpText(
|
|
18463
|
+
"after",
|
|
18464
|
+
`
|
|
18465
|
+
A value node with no JSON form (an accessor property, a function, a circular reference) comes back as {"$unserializable": "<reason>"} and is listed in .result.setting.valueOmissions (at most ${SERIALIZE_OMISSIONS_MAX} entries; valueOmissionsTruncated marks a longer list). Such a value is incomplete: writing it back with setting set stores the markers as data.`
|
|
18466
|
+
).action(async function getSetting(options) {
|
|
18148
18467
|
await executeRemoteCommand({
|
|
18149
18468
|
commandName: "setting.get",
|
|
18150
18469
|
params: { namespace: options.namespace, key: options.key },
|
|
@@ -18158,7 +18477,7 @@ function registerSetting({ program, dependencies }) {
|
|
|
18158
18477
|
"--ids <list>",
|
|
18159
18478
|
'Comma-separated setting ids in "namespace.key" form (e.g. core.chatBubbles,my-module.apiKey)',
|
|
18160
18479
|
parseIdList
|
|
18161
|
-
).action(async function getManySettings(options) {
|
|
18480
|
+
).addHelpText("after", "\nEach row reports omissions like setting get, in valueOmissions.").action(async function getManySettings(options) {
|
|
18162
18481
|
await executeRemoteCommand({
|
|
18163
18482
|
commandName: "setting.get-many",
|
|
18164
18483
|
params: { ids: options.ids },
|
|
@@ -18170,6 +18489,9 @@ function registerSetting({ program, dependencies }) {
|
|
|
18170
18489
|
"--value-json <json>",
|
|
18171
18490
|
'New value as a JSON literal \u2014 true, 42, "text", [..] or {..}; a quoted string stays distinct from a boolean or a number',
|
|
18172
18491
|
(value) => parseJsonValue(value, "--value-json")
|
|
18492
|
+
).addHelpText(
|
|
18493
|
+
"after",
|
|
18494
|
+
'\nprevious and value report omissions like setting get, in previousOmissions and valueOmissions. {"$unserializable": ...} markers in --value-json are stored as data.'
|
|
18173
18495
|
).action(async function setSetting(options) {
|
|
18174
18496
|
await executeRemoteCommand({
|
|
18175
18497
|
commandName: "setting.set",
|
|
@@ -18730,6 +19052,7 @@ function registerWorld({ program, dependencies }) {
|
|
|
18730
19052
|
"",
|
|
18731
19053
|
"Result key (--json): .result.broken[] (+ .result.checkedRefs / .result.checkedFiles / .result.skipped[], total/hasMore over broken) for audit-files.",
|
|
18732
19054
|
"Result key (--json): .result.results[] (+ .result.total / .result.hasMore / .result.index) for search.",
|
|
19055
|
+
"Result key (--json): .result.references[] (+ .result.target / .result.total / .result.hasMore / .result.scannedDocuments / .result.selfReferences / .result.scopes) for references.",
|
|
18733
19056
|
"",
|
|
18734
19057
|
"search: results are SECTIONED \u2014 world rows first, then pack rows, each ranked among itself.",
|
|
18735
19058
|
"`score` is comparable only WITHIN a section (the two corpora are separate indexes), so compare",
|
|
@@ -18761,6 +19084,53 @@ function registerWorld({ program, dependencies }) {
|
|
|
18761
19084
|
dependencies
|
|
18762
19085
|
});
|
|
18763
19086
|
});
|
|
19087
|
+
addPaginationOptions(
|
|
19088
|
+
world.command("references").description("Report where stored world data references a document, by its UUID").requiredOption(
|
|
19089
|
+
"--uuid <uuid>",
|
|
19090
|
+
"Target document UUID: Actor.<id>, Scene.<id>.Token.<id>, Compendium.<package>.<pack>.<Type>.<id>, \u2026"
|
|
19091
|
+
).option(
|
|
19092
|
+
"--scope <list>",
|
|
19093
|
+
`Comma-separated document families to scan: ${REFERENCE_SCOPES.join(",")} (default: ${REFERENCE_DEFAULT_SCOPES.join(",")}; chat only on request)`,
|
|
19094
|
+
parseScopeList
|
|
19095
|
+
).addHelpText(
|
|
19096
|
+
"after",
|
|
19097
|
+
[
|
|
19098
|
+
"",
|
|
19099
|
+
"Scans the stored data, flags and _stats included, of every world document in scope, its embedded",
|
|
19100
|
+
"documents, and every user. Each row names the owning document by UUID and the dotted field path in it;",
|
|
19101
|
+
"a match inside a token's delta is reported on the token (field delta.\u2026). An embedded target needs its",
|
|
19102
|
+
"full UUID (Scene.<s>.Token.<t>).",
|
|
19103
|
+
"match: uuid a field holds the target UUID",
|
|
19104
|
+
" link an @UUID[...] link or a legacy @Actor[<id>] / @Compendium[<pack>.<id>] link names the target",
|
|
19105
|
+
" embedded a field holds the UUID of a document embedded in the target (matchedUuid); deleting the",
|
|
19106
|
+
" target breaks it too",
|
|
19107
|
+
" key an object key names the target; a dotted key Foundry stored nested is reported at the",
|
|
19108
|
+
" target's id (flags.mod.Actor.<id>)",
|
|
19109
|
+
" relative a relative link (@UUID[.<id>], @Embed[.<id>]) in journal page text or a roll table or",
|
|
19110
|
+
" table result description resolves to the target or a document in it (matchedUuid)",
|
|
19111
|
+
" id a foreign-key field of the target's type (token actorId, note entryId, folder, setting user,",
|
|
19112
|
+
" chat speaker, \u2026) or a hotbar slot (hotbar.<slot>) holds the target's id; for an embedded",
|
|
19113
|
+
" target only where the record also names its parent or sits inside it, and never for a",
|
|
19114
|
+
" deeper target such as a token's actor",
|
|
19115
|
+
"setting: world and user settings, read as stored JSON (rows Setting.<id>, name = key, field value[.<path>]).",
|
|
19116
|
+
"Not found: compendium contents, client settings, bare ids outside foreign-key fields (system data, object",
|
|
19117
|
+
"keys, chat whisper lists) or in fields Foundry maintains itself (_stats.lastModifiedBy), name-based links",
|
|
19118
|
+
"(@Actor[Goblin]), relative links in other fields. References inside the target itself are counted in",
|
|
19119
|
+
"selfReferences. target.exists is null for a compendium target, whose pack is not loaded."
|
|
19120
|
+
].join("\n")
|
|
19121
|
+
)
|
|
19122
|
+
).action(async function findReferences(options) {
|
|
19123
|
+
await executeRemoteCommand({
|
|
19124
|
+
commandName: "world.references",
|
|
19125
|
+
params: {
|
|
19126
|
+
uuid: options.uuid,
|
|
19127
|
+
...options.scope ? { scope: options.scope } : {},
|
|
19128
|
+
...paginationParams(options)
|
|
19129
|
+
},
|
|
19130
|
+
command: this,
|
|
19131
|
+
dependencies
|
|
19132
|
+
});
|
|
19133
|
+
});
|
|
18764
19134
|
addPaginationOptions(
|
|
18765
19135
|
world.command("search").description("Search world (and optionally compendium) documents through the bridge index").requiredOption("--query <query>", "Search query (2-256 characters; terms are AND-combined)").addOption(
|
|
18766
19136
|
new Option15(
|
package/docs/commands.md
CHANGED
|
@@ -28,13 +28,13 @@ Use these families to narrow your search, then check their help for supported op
|
|
|
28
28
|
| Task | Command families |
|
|
29
29
|
|---|---|
|
|
30
30
|
| Edit world content | `actor`, `item`, `journal`, `scene`, `macro`, `playlist`, `table`, `cards` |
|
|
31
|
-
| Edit embedded content | Nested families such as `actor.item`, `playlist.sound`, `table.result`, and `*.effect` |
|
|
31
|
+
| Edit embedded content | Nested families such as `actor.item`, `journal.page`, `playlist.sound`, `table.result`, and `*.effect` |
|
|
32
32
|
| Edit scene placeables | `scene.token`, `scene.wall`, `scene.region`, and related families |
|
|
33
33
|
| Edit scene levels (v14) | `scene.level` |
|
|
34
34
|
| Manage encounters | `combat`, `combat.combatant`, `combat.group` |
|
|
35
35
|
| Organize content and access | `folder`, `*.ownership.set`, `user` |
|
|
36
36
|
| Manage chat and settings | `chat`, `setting` |
|
|
37
|
-
| Find content or missing assets | `world.search`, `world.audit-files` |
|
|
37
|
+
| Find content, references, or missing assets | `world.search`, `world.references`, `world.audit-files` |
|
|
38
38
|
| Read packs or import world documents | `compendium`, supported `*.import-from-compendium` commands |
|
|
39
39
|
| Manage assets | `file` |
|
|
40
40
|
| Control playback and gameplay | Actions within `playlist`, `table`, `cards`, `combat`, `scene`, and `game` |
|
|
@@ -277,7 +277,7 @@ For scripts and JSON output, pass `--yes` to skip the listing and prompt.
|
|
|
277
277
|
## Local configuration
|
|
278
278
|
|
|
279
279
|
`config get` shows the config path and non-secret settings. `config set-upload-limit <size>`
|
|
280
|
-
changes the raw
|
|
280
|
+
changes the raw byte limit for uploads and file reads; it takes effect after a daemon restart.
|
|
281
281
|
|
|
282
282
|
If set, `XDG_CONFIG_HOME` places configuration under `$XDG_CONFIG_HOME/fvtt-world-cli`. Otherwise:
|
|
283
283
|
|
package/docs/compatibility.md
CHANGED
|
@@ -11,6 +11,7 @@ The bridge supports Foundry VTT v13 and v14. Check your connected version with
|
|
|
11
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. |
|
|
12
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. |
|
|
13
13
|
| User permission names | `TEMPLATE_CREATE` | `REGION_CREATE` | Use the permission keys reported by the connected Foundry version when calling `user.permissions.set`. |
|
|
14
|
+
| Relative content links | `@UUID[..<id>]` points at nothing | `@UUID[..<id>]` names a document one parent up | `world.references` reports a `..` link only on v14. |
|
|
14
15
|
| 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. |
|
|
15
16
|
|
|
16
17
|
Scene placeable fields and available region behavior types also differ. Read the target document
|
package/docs/protocol.md
CHANGED
|
@@ -27,12 +27,13 @@ a correlated control-request error.
|
|
|
27
27
|
|
|
28
28
|
## Size limits
|
|
29
29
|
|
|
30
|
-
The upload limit and the transport frame limit are distinct: the first bounds raw upload content
|
|
31
|
-
the second accounts for encoding and envelope overhead and is
|
|
32
|
-
large read responses require. The daemon advertises its effective
|
|
33
|
-
the bridge checks response size before sending, so an oversized
|
|
34
|
-
`PAYLOAD_TOO_LARGE` instead of destroying the
|
|
35
|
-
applied to the transport only after the daemon
|
|
30
|
+
The upload limit and the transport frame limit are distinct: the first bounds raw upload content
|
|
31
|
+
and the raw size of a `file.read`, the second accounts for encoding and envelope overhead and is
|
|
32
|
+
never lower than what legitimate large read responses require. The daemon advertises its effective
|
|
33
|
+
limits during the handshake, and the bridge checks response size before sending, so an oversized
|
|
34
|
+
response, or one the browser cannot serialize, returns `PAYLOAD_TOO_LARGE` instead of destroying the
|
|
35
|
+
shared session. A persisted upload-limit change is applied to the transport only after the daemon
|
|
36
|
+
restarts.
|
|
36
37
|
|
|
37
38
|
## Pairing
|
|
38
39
|
|
|
@@ -187,6 +188,11 @@ World document reads carry `compendiumSource` and `duplicateSource`, hoisted fro
|
|
|
187
188
|
Broadcast actions report `dispatched` and target users rather than a confirmed player-side result.
|
|
188
189
|
The active/inactive split is included where knowable.
|
|
189
190
|
|
|
191
|
+
A setting value or macro return value node with no JSON form, such as a function, an own accessor
|
|
192
|
+
property or a circular reference, is replaced by `{"$unserializable": "<reason>"}` and listed with
|
|
193
|
+
its path in an `...Omissions` field. A value with omissions is incomplete; writing it back stores the
|
|
194
|
+
markers as data.
|
|
195
|
+
|
|
190
196
|
### Macro results
|
|
191
197
|
|
|
192
198
|
`macro.execute` returns the macro's value and observed chat messages. `chatCapture` describes the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fvtt-world-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
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.
|
|
59
|
+
"@fvtt-world-cli/protocol": "1.3.0"
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -19,10 +19,11 @@ fvtt-world-cli system info --json
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Proceed only when `.result.bridge.status` is `connected`, and verify the reported world and GM are
|
|
22
|
-
the intended targets. If
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
`fvtt-world-cli` module
|
|
22
|
+
the intended targets. If `system info` answers at all, a daemon is running; use it. Start
|
|
23
|
+
`fvtt-world-cli bridge serve` only when the daemon is unreachable, as a persistent background
|
|
24
|
+
process (it does not daemonize itself), and leave it running for the whole session. If no bridge
|
|
25
|
+
connects, a GM must have the target world open in a browser with the `fvtt-world-cli` module
|
|
26
|
+
enabled and paired.
|
|
26
27
|
|
|
27
28
|
Pairing is a first-run trust decision that needs the human: ask the GM to open Module Settings →
|
|
28
29
|
Authorization, name the browser in the `Browser label` field, and choose Pair; run
|
|
@@ -81,8 +82,11 @@ Deleting a level also deletes its tokens and every placeable only on that level,
|
|
|
81
82
|
does not list them: read the scene's placeables (token `level`, others' `levels`) and tell the user
|
|
82
83
|
what the delete removes before running it.
|
|
83
84
|
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
|
|
85
|
-
the edit will not
|
|
85
|
+
editing an actor that has placed tokens, read its tokens' overrides
|
|
86
|
+
(`scene token get --include delta,prepared`) and tell the user which tokens the edit will not
|
|
87
|
+
change.
|
|
88
|
+
Before deleting or relinking a document, run `world references --uuid <uuid>` and tell the user
|
|
89
|
+
which stored references will point at nothing.
|
|
86
90
|
`setting.set` cannot touch this module's own namespace (`SETTING_PROTECTED` is final; never retry).
|
|
87
91
|
When a setting write returns `requiresReload: true`, the change needs a GM-client reload to take
|
|
88
92
|
effect; `system.reload` performs it, drops the bridge, and requires a reconnect wait before the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
07f46d03812a74d1643f7483eb3eb926244dd1837b7afb11280c3072bfa3d5bd
|