narraeon 0.7.9 → 0.7.10
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.
|
@@ -286,8 +286,8 @@ const toolDescriptionsEn = (tabletop) => ({
|
|
|
286
286
|
search: "Search literal source text in world documents in the content package's current tree. within may be world, a world/ directory or path, or @ref.",
|
|
287
287
|
read: "Read a complete world document by world/ path or @ref, or read a complete opening/control file by exact path. Existing document selectors are projected to @refs. The result is never truncated or paginated.",
|
|
288
288
|
create: "Create one world/ .yaml or .md document. Supply a unique lowercase ASCII ref, title, summary, aliases, and body without a technical header; Runtime completes the storage envelope. The created document is already fully read.",
|
|
289
|
-
write_file: `Replace a completely read world/ .yaml or .md document body while preserving its identity and metadata, or create/replace opening.md, control/frame.yaml, control/player-views.yaml, ${tabletop ? "control/blocks/*.md, or control/gameplay.json (only a tabletop resolution scheme may change)" : "or control/blocks/*.md"}, plus control/followups.yaml and its referenced prompts/*.md, renderers/*.html, scripts/*.js, regex/*.yaml and assets/* text resources. To repair a damaged world document,
|
|
290
|
-
patch: 'Update a completely read YAML world document without rewriting unrelated content. locator is a non-empty path whose segments are map keys or zero-based array indexes. Use add for a missing map key or array index, replace for an existing node, append for the end of an existing array, and remove for an existing map key or array item.
|
|
289
|
+
write_file: `Replace a completely read world/ .yaml or .md document body while preserving its identity and metadata, or create/replace opening.md, control/frame.yaml, control/player-views.yaml, ${tabletop ? "control/blocks/*.md, or control/gameplay.json (only a tabletop resolution scheme may change)" : "or control/blocks/*.md"}, plus control/followups.yaml and its referenced prompts/*.md, renderers/*.html, scripts/*.js, regex/*.yaml and assets/* text resources. path may also be an @ref. On a valid document, title, summary, and aliases may be given in the same write to update metadata (any subset; omitted fields are kept), but ref never changes. To repair a damaged world document, provide ref, title, summary, and aliases together; Runtime preserves any recoverable storage identity. Create new world documents with setting_create.`,
|
|
290
|
+
patch: 'Update a completely read YAML world document without rewriting unrelated content. locator is a non-empty path whose segments are map keys or zero-based array indexes. Use add for a missing map key or array index, replace for an existing node, append for the end of an existing array, and remove for an existing map key or array item. To update title, summary, or aliases, use op "set_metadata" with only the fields that change; omitted fields are kept. Rewrite Markdown bodies with setting_write_file.',
|
|
291
291
|
move: "Move a completely read world document to a new world/ .yaml or .md logical path while preserving its identity and contents.",
|
|
292
292
|
delete: "Permanently delete a completely read world document from the content-package current tree. Runtime rejects deletion while currentSituation, a frame slot, a player-view selector, or another document's $ref still points to it, and reports every blocking location. Delete or redirect those references first.",
|
|
293
293
|
});
|
|
@@ -296,8 +296,8 @@ const toolDescriptionsZhCN = (tabletop) => ({
|
|
|
296
296
|
search: "在内容包当前树的 world 文档中按原文字面搜索;within 可为 world、world/ 目录或路径或 @ref。",
|
|
297
297
|
read: "按 world/ 路径或 @ref 完整读取世界文档,或按精确路径完整读取 opening/control;既有文档选择值自动投影为 @ref。结果不会截断或分页。",
|
|
298
298
|
create: "创建一份 world/ 下的 .yaml 或 .md 文档;提供唯一的小写 ASCII ref、标题、摘要、别名和不含技术头的正文,Runtime 自行完成存储封装。创建成功的文档视为已经完整读取。",
|
|
299
|
-
write_file: `整份替换已完整读取的 world/ .yaml 或 .md 正文并保留身份和元信息,或创建/替换 opening.md、control/frame.yaml、control/player-views.yaml、control/blocks/*.md${tabletop ? "、control/gameplay.json(只能修改跑团判定方案,玩法模式不可改)" : ""},以及 control/followups.yaml 和其中引用的 prompts/*.md、renderers/*.html、scripts/*.js、regex/*.yaml、assets/*
|
|
300
|
-
patch: '细粒度更新已完整读取的 YAML 世界文档,不重写无关内容。locator 是非空路径,每段可以是 map key 或从 0 开始的数组下标;add 新建 map key 或数组位置,replace 更新既有节点,append 追加既有数组,remove 删除既有 map key
|
|
299
|
+
write_file: `整份替换已完整读取的 world/ .yaml 或 .md 正文并保留身份和元信息,或创建/替换 opening.md、control/frame.yaml、control/player-views.yaml、control/blocks/*.md${tabletop ? "、control/gameplay.json(只能修改跑团判定方案,玩法模式不可改)" : ""},以及 control/followups.yaml 和其中引用的 prompts/*.md、renderers/*.html、scripts/*.js、regex/*.yaml、assets/* 文本资源。path 也可以是 @ref。有效文档可在同一次写入中提供 title、summary、aliases 的任意子集更新元信息,未提供的保持不变,但 ref 不能改。修复损坏世界文档时同时提供 ref、title、summary、aliases,Runtime 会保留仍可恢复的存储身份。新建世界文档使用 setting_create。`,
|
|
300
|
+
patch: '细粒度更新已完整读取的 YAML 世界文档,不重写无关内容。locator 是非空路径,每段可以是 map key 或从 0 开始的数组下标;add 新建 map key 或数组位置,replace 更新既有节点,append 追加既有数组,remove 删除既有 map key 或数组项。需要更新 title、summary 或 aliases 时用 op "set_metadata",只提供要改变的字段,未提供的保持不变。Markdown 正文用 setting_write_file 整份重写。',
|
|
301
301
|
move: "把已完整读取的世界文档移动到新的 world/ .yaml 或 .md 逻辑路径,并保留身份与内容。",
|
|
302
302
|
delete: "从内容包当前树永久删除一份已完整读取的 world 文档。若 currentSituation、frame slot、player-view selector 或其他文档的 $ref 仍指向它,Runtime 会拒绝并返回全部精确阻挡位置;请先删除或改向这些引用。",
|
|
303
303
|
});
|
|
@@ -306,8 +306,8 @@ const worldRevisionDescriptionsEn = (tabletop) => ({
|
|
|
306
306
|
search: "Search literal source text in world documents in the world revision worktree. within may be state, a state/ directory or path, or @ref.",
|
|
307
307
|
read: "Read a complete world document by state/ path or @ref, or read a complete control file by exact path. Existing document selectors are projected to @refs. The result is never truncated or paginated.",
|
|
308
308
|
create: "Create one state/ .yaml or .md document. Supply a unique lowercase ASCII ref, title, summary, aliases, and body without a technical header; Runtime completes the storage envelope. The created document is already fully read.",
|
|
309
|
-
write_file: `Replace a completely read state/ .yaml or .md document body while preserving its identity and metadata, or create/replace control/frame.yaml, control/player-views.yaml, ${tabletop ? "control/blocks/*.md, or control/gameplay.json (only a tabletop resolution scheme may change)" : "or control/blocks/*.md"}, plus control/followups.yaml and its referenced prompts/*.md, renderers/*.html, scripts/*.js, regex/*.yaml and assets/* text resources. To repair a damaged world document,
|
|
310
|
-
patch: 'Update a completely read YAML world document without rewriting unrelated content. locator is a non-empty path whose segments are map keys or zero-based array indexes. Use add for a missing map key or array index, replace for an existing node, append for the end of an existing array, and remove for an existing map key or array item.
|
|
309
|
+
write_file: `Replace a completely read state/ .yaml or .md document body while preserving its identity and metadata, or create/replace control/frame.yaml, control/player-views.yaml, ${tabletop ? "control/blocks/*.md, or control/gameplay.json (only a tabletop resolution scheme may change)" : "or control/blocks/*.md"}, plus control/followups.yaml and its referenced prompts/*.md, renderers/*.html, scripts/*.js, regex/*.yaml and assets/* text resources. path may also be an @ref. On a valid document, title, summary, and aliases may be given in the same write to update metadata (any subset; omitted fields are kept), but ref never changes. To repair a damaged world document, provide ref, title, summary, and aliases together; Runtime preserves any recoverable storage identity. Create new world documents with world_revision_create.`,
|
|
310
|
+
patch: 'Update a completely read YAML world document without rewriting unrelated content. locator is a non-empty path whose segments are map keys or zero-based array indexes. Use add for a missing map key or array index, replace for an existing node, append for the end of an existing array, and remove for an existing map key or array item. To update title, summary, or aliases, use op "set_metadata" with only the fields that change; omitted fields are kept. Rewrite Markdown bodies with world_revision_write_file.',
|
|
311
311
|
move: "Move a completely read world document to a new state/ .yaml or .md logical path while preserving its identity and contents.",
|
|
312
312
|
delete: "Permanently delete a completely read world document from the world revision worktree. Runtime rejects deletion while currentSituation, a frame slot, a player-view selector, or another document's $ref still points to it, and reports every blocking location. Delete or redirect those references first.",
|
|
313
313
|
});
|
|
@@ -316,8 +316,8 @@ const worldRevisionDescriptionsZhCN = (tabletop) => ({
|
|
|
316
316
|
search: "在世界修订工作树的 state 文档中按原文字面搜索;within 可为 state、state/ 目录或路径或 @ref。",
|
|
317
317
|
read: "按 state/ 路径或 @ref 完整读取世界文档,或按精确路径完整读取 control 文件;既有文档选择值自动投影为 @ref。结果不会截断或分页。",
|
|
318
318
|
create: "创建一份 state/ 下的 .yaml 或 .md 文档;提供唯一的小写 ASCII ref、标题、摘要、别名和不含技术头的正文,Runtime 自行完成存储封装。创建成功的文档视为已经完整读取。",
|
|
319
|
-
write_file: `整份替换已完整读取的 state/ .yaml 或 .md 正文并保留身份和元信息,或创建/替换 control/frame.yaml、control/player-views.yaml、control/blocks/*.md${tabletop ? "、control/gameplay.json(只能修改跑团判定方案,玩法模式不可改)" : ""},以及 control/followups.yaml 和其中引用的 prompts/*.md、renderers/*.html、scripts/*.js、regex/*.yaml、assets/*
|
|
320
|
-
patch: '细粒度更新已完整读取的 YAML 世界文档,不重写无关内容。locator 是非空路径,每段可以是 map key 或从 0 开始的数组下标;add 新建 map key 或数组位置,replace 更新既有节点,append 追加既有数组,remove 删除既有 map key
|
|
319
|
+
write_file: `整份替换已完整读取的 state/ .yaml 或 .md 正文并保留身份和元信息,或创建/替换 control/frame.yaml、control/player-views.yaml、control/blocks/*.md${tabletop ? "、control/gameplay.json(只能修改跑团判定方案,玩法模式不可改)" : ""},以及 control/followups.yaml 和其中引用的 prompts/*.md、renderers/*.html、scripts/*.js、regex/*.yaml、assets/* 文本资源。path 也可以是 @ref。有效文档可在同一次写入中提供 title、summary、aliases 的任意子集更新元信息,未提供的保持不变,但 ref 不能改。修复损坏世界文档时同时提供 ref、title、summary、aliases,Runtime 会保留仍可恢复的存储身份。新建世界文档使用 world_revision_create。`,
|
|
320
|
+
patch: '细粒度更新已完整读取的 YAML 世界文档,不重写无关内容。locator 是非空路径,每段可以是 map key 或从 0 开始的数组下标;add 新建 map key 或数组位置,replace 更新既有节点,append 追加既有数组,remove 删除既有 map key 或数组项。需要更新 title、summary 或 aliases 时用 op "set_metadata",只提供要改变的字段,未提供的保持不变。Markdown 正文用 world_revision_write_file 整份重写。',
|
|
321
321
|
move: "把已完整读取的世界文档移动到新的 state/ .yaml 或 .md 逻辑路径,并保留身份与内容。",
|
|
322
322
|
delete: "从世界修订工作树永久删除一份已完整读取的 world 文档。若 currentSituation、frame slot、player-view selector 或其他文档的 $ref 仍指向它,Runtime 会拒绝并返回全部精确阻挡位置;请先删除或改向这些引用。",
|
|
323
323
|
});
|
|
@@ -519,9 +519,7 @@ export class SettingAuthoringTransaction {
|
|
|
519
519
|
? requiredSettingRef(call.arguments.ref, this.#locale)
|
|
520
520
|
: null;
|
|
521
521
|
const revised = snapshot.revise({
|
|
522
|
-
commands:
|
|
523
|
-
worldRevisionCommand(snapshot, call, this.#surface, this.#locale),
|
|
524
|
-
],
|
|
522
|
+
commands: worldRevisionCommands(snapshot, call, this.#surface, this.#locale),
|
|
525
523
|
});
|
|
526
524
|
if (!revised.ok)
|
|
527
525
|
throw new SettingAuthoringError(renderRevisionFailure(revised.diagnostics, this.#surface, this.#locale));
|
|
@@ -885,7 +883,51 @@ function isWorldWriteCall(call, surface) {
|
|
|
885
883
|
return true;
|
|
886
884
|
return (call.operation === "write_file" &&
|
|
887
885
|
typeof call.arguments.path === "string" &&
|
|
888
|
-
call.arguments.path.startsWith(`${surface.root}/`)
|
|
886
|
+
(call.arguments.path.startsWith(`${surface.root}/`) ||
|
|
887
|
+
call.arguments.path.startsWith("@")));
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* A world write may need two revision commands: the body write, then a
|
|
891
|
+
* metadata patch for any title, summary or aliases given on a valid document.
|
|
892
|
+
* Both target the same logical path, so they apply in one revision.
|
|
893
|
+
*/
|
|
894
|
+
function worldRevisionCommands(snapshot, call, surface, locale) {
|
|
895
|
+
if (call.operation !== "write_file")
|
|
896
|
+
return [worldRevisionCommand(snapshot, call, surface, locale)];
|
|
897
|
+
const logicalPath = writeFileLogicalPath(snapshot, requiredString(call.arguments.path, "path"), surface, locale);
|
|
898
|
+
const request = worldWriteRequest(snapshot, logicalPath, call.arguments, surface, locale);
|
|
899
|
+
const write = {
|
|
900
|
+
kind: "write",
|
|
901
|
+
logicalPath,
|
|
902
|
+
contents: request.contents,
|
|
903
|
+
};
|
|
904
|
+
if (request.metadata === null)
|
|
905
|
+
return [write];
|
|
906
|
+
return [
|
|
907
|
+
write,
|
|
908
|
+
{
|
|
909
|
+
kind: "patch",
|
|
910
|
+
document: { logicalPath },
|
|
911
|
+
edits: [{ op: "set_metadata", ...request.metadata }],
|
|
912
|
+
},
|
|
913
|
+
];
|
|
914
|
+
}
|
|
915
|
+
/** Resolves `@ref` write targets to their logical path; paths are checked as before. */
|
|
916
|
+
function writeFileLogicalPath(snapshot, path, surface, locale) {
|
|
917
|
+
if (!path.startsWith("@"))
|
|
918
|
+
return safeWorldDocumentPath(path, surface, locale);
|
|
919
|
+
const selector = documentSelector(path, surface);
|
|
920
|
+
if (selector === null)
|
|
921
|
+
throw new SettingAuthoringError(localized(locale, `${authoringToolName(surface, "write_file")}.path must be an @ref or ${surface.root}/ document path`, `${authoringToolName(surface, "write_file")}.path 必须是 @ref 或 ${surface.root}/ 文档路径`));
|
|
922
|
+
const resolved = snapshot.query({
|
|
923
|
+
kind: "read_document",
|
|
924
|
+
document: selector,
|
|
925
|
+
});
|
|
926
|
+
if (resolved.kind === "error")
|
|
927
|
+
throw new SettingAuthoringError(localized(locale, `Unknown document ${path}`, `未知文档 ${path}`));
|
|
928
|
+
if (resolved.kind !== "read_document")
|
|
929
|
+
throw new Error("Unexpected world-document write lookup result");
|
|
930
|
+
return resolved.document.logicalPath;
|
|
889
931
|
}
|
|
890
932
|
function worldRevisionCommand(snapshot, call, surface, locale) {
|
|
891
933
|
if (call.operation === "create") {
|
|
@@ -917,16 +959,6 @@ function worldRevisionCommand(snapshot, call, surface, locale) {
|
|
|
917
959
|
body,
|
|
918
960
|
};
|
|
919
961
|
}
|
|
920
|
-
if (call.operation === "write_file") {
|
|
921
|
-
const logicalPath = safeWorldDocumentPath(requiredString(call.arguments.path, "path"), surface, locale);
|
|
922
|
-
const contents = worldWriteContents(snapshot, logicalPath, call.arguments, surface, locale);
|
|
923
|
-
assertNoLiteralUnicodeEscapes(contents, locale);
|
|
924
|
-
return {
|
|
925
|
-
kind: "write",
|
|
926
|
-
logicalPath,
|
|
927
|
-
contents,
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
962
|
if (call.operation === "move") {
|
|
931
963
|
const toLogicalPath = safePath(requiredString(call.arguments.to, "to"), surface);
|
|
932
964
|
if (!documentPathPattern(surface).test(toLogicalPath))
|
|
@@ -940,14 +972,11 @@ function worldRevisionCommand(snapshot, call, surface, locale) {
|
|
|
940
972
|
if (call.operation === "patch") {
|
|
941
973
|
const op = requiredPatchOp(call.arguments, surface);
|
|
942
974
|
if (op === "set_metadata") {
|
|
943
|
-
const
|
|
944
|
-
const summary = requiredString(call.arguments.summary, "summary");
|
|
945
|
-
const aliases = requiredAliases(call.arguments.aliases);
|
|
946
|
-
assertNoLiteralUnicodeEscapes({ title, summary, aliases }, locale);
|
|
975
|
+
const metadata = metadataFields(call.arguments, surface, locale);
|
|
947
976
|
return {
|
|
948
977
|
kind: "patch",
|
|
949
978
|
document: revisionTarget(requiredString(call.arguments.document, "document"), surface),
|
|
950
|
-
edits: [{ op: "set_metadata",
|
|
979
|
+
edits: [{ op: "set_metadata", ...metadata }],
|
|
951
980
|
};
|
|
952
981
|
}
|
|
953
982
|
const locator = requiredYamlLocatorPath(call.arguments.locator, "locator");
|
|
@@ -992,29 +1021,59 @@ function safeWorldDocumentPath(path, surface, locale) {
|
|
|
992
1021
|
throw new SettingAuthoringError(localized(locale, `World files must be .yaml or .md documents below ${surface.root}/`, `world 文件必须是 ${surface.root}/ 下的 .yaml 或 .md 文档`));
|
|
993
1022
|
return logicalPath;
|
|
994
1023
|
}
|
|
995
|
-
|
|
1024
|
+
/**
|
|
1025
|
+
* Title, summary and aliases are public index metadata that AI may update on a
|
|
1026
|
+
* valid document. Only the ones given are read, and at least one must be given.
|
|
1027
|
+
*/
|
|
1028
|
+
function metadataFields(args, surface, locale) {
|
|
1029
|
+
const fields = {};
|
|
1030
|
+
if (args.title !== undefined)
|
|
1031
|
+
fields.title = requiredString(args.title, "title");
|
|
1032
|
+
if (args.summary !== undefined)
|
|
1033
|
+
fields.summary = requiredString(args.summary, "summary");
|
|
1034
|
+
if (args.aliases !== undefined)
|
|
1035
|
+
fields.aliases = requiredAliases(args.aliases);
|
|
1036
|
+
if (Object.keys(fields).length === 0)
|
|
1037
|
+
throw new SettingAuthoringError(localized(locale, `${authoringToolName(surface, "patch")} set_metadata needs at least one of title, summary, or aliases`, `${authoringToolName(surface, "patch")} set_metadata 至少需要 title、summary 或 aliases 之一`));
|
|
1038
|
+
assertNoLiteralUnicodeEscapes(fields, locale);
|
|
1039
|
+
return fields;
|
|
1040
|
+
}
|
|
1041
|
+
function worldWriteRequest(snapshot, logicalPath, args, surface, locale) {
|
|
996
1042
|
if (!hasOnly(args, ["path", "contents", "ref", "title", "summary", "aliases"]))
|
|
997
1043
|
throw new SettingAuthoringError(`${authoringToolName(surface, "write_file")} accepts only its declared arguments`);
|
|
998
1044
|
const body = requiredString(args.contents, "contents");
|
|
999
|
-
const metadataKeys = ["ref", "title", "summary", "aliases"];
|
|
1000
|
-
const provided = metadataKeys.filter((key) => args[key] !== undefined);
|
|
1001
1045
|
const existingFile = snapshot.files.some(({ path }) => path === logicalPath);
|
|
1002
1046
|
const existingDocument = listQueryableWorldDocuments(snapshot).some(({ logicalPath: existingPath }) => existingPath === logicalPath);
|
|
1047
|
+
const metadataGiven = ["title", "summary", "aliases"].some((key) => args[key] !== undefined);
|
|
1048
|
+
if (existingDocument) {
|
|
1049
|
+
if (args.ref !== undefined)
|
|
1050
|
+
throw new SettingAuthoringError(localized(locale, `ref is the stable identity of a valid document and cannot change; omit ref, and use title, summary, or aliases to update its metadata`, `有效文档的 ref 是稳定身份,写入不能改变;请省略 ref,需要更新时只用 title、summary 或 aliases`));
|
|
1051
|
+
return {
|
|
1052
|
+
contents: body,
|
|
1053
|
+
metadata: metadataGiven ? metadataFields(args, surface, locale) : null,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
if (!existingFile) {
|
|
1057
|
+
if (!metadataGiven && containsTechnicalDocumentHeader(logicalPath, body))
|
|
1058
|
+
return { contents: body, metadata: null };
|
|
1059
|
+
throw new SettingAuthoringError(localized(locale, `Create a new world document with ${authoringToolName(surface, "create")}`, `新建世界文档请使用 ${authoringToolName(surface, "create")}`));
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
contents: worldRepairContents(snapshot, logicalPath, args, body, surface, locale),
|
|
1063
|
+
metadata: null,
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
/** Damaged documents keep their body only with a complete ref, title, summary and aliases set. */
|
|
1067
|
+
function worldRepairContents(snapshot, logicalPath, args, body, surface, locale) {
|
|
1068
|
+
const metadataKeys = ["ref", "title", "summary", "aliases"];
|
|
1069
|
+
const provided = metadataKeys.filter((key) => args[key] !== undefined);
|
|
1003
1070
|
if (provided.length === 0) {
|
|
1004
|
-
if (!
|
|
1005
|
-
throw new SettingAuthoringError(localized(locale, `Create a new world document with ${authoringToolName(surface, "create")}`, `新建世界文档请使用 ${authoringToolName(surface, "create")}`));
|
|
1006
|
-
if (existingFile &&
|
|
1007
|
-
!existingDocument &&
|
|
1008
|
-
!containsTechnicalDocumentHeader(logicalPath, body))
|
|
1071
|
+
if (!containsTechnicalDocumentHeader(logicalPath, body))
|
|
1009
1072
|
throw new SettingAuthoringError(localized(locale, "Repair a damaged document by providing ref, title, summary, and aliases with its body", "修复损坏文档时,请在正文之外同时提供 ref、title、summary 和 aliases"));
|
|
1010
1073
|
return body;
|
|
1011
1074
|
}
|
|
1012
1075
|
if (provided.length !== metadataKeys.length)
|
|
1013
1076
|
throw new SettingAuthoringError(localized(locale, "Repair metadata must provide ref, title, summary, and aliases together", "修复元信息时必须同时提供 ref、title、summary 和 aliases"));
|
|
1014
|
-
if (!existingFile)
|
|
1015
|
-
throw new SettingAuthoringError(localized(locale, `Create a new world document with ${authoringToolName(surface, "create")}`, `新建世界文档请使用 ${authoringToolName(surface, "create")}`));
|
|
1016
|
-
if (existingDocument)
|
|
1017
|
-
throw new SettingAuthoringError(localized(locale, `Repair metadata is only for a damaged document; update valid metadata with ${authoringToolName(surface, "patch")} set_metadata`, `修复元信息只用于损坏文档;有效文档请用 ${authoringToolName(surface, "patch")} set_metadata 更新元信息`));
|
|
1018
1077
|
const ref = requiredSettingRef(args.ref, locale);
|
|
1019
1078
|
const title = requiredString(args.title, "title");
|
|
1020
1079
|
const summary = requiredString(args.summary, "summary");
|
|
@@ -1175,13 +1234,13 @@ function deletionLocator(locator) {
|
|
|
1175
1234
|
: `markdown:${JSON.stringify(locator.markdown)}`;
|
|
1176
1235
|
}
|
|
1177
1236
|
function writeOpaque(snapshot, call, reads, surface, locale) {
|
|
1178
|
-
if (!hasOnly(call.arguments, ["path", "contents"]))
|
|
1179
|
-
throw new SettingAuthoringError("Special-file writes accept only path and contents");
|
|
1180
1237
|
const path = safePath(requiredString(call.arguments.path, "path"), surface);
|
|
1181
1238
|
if (!writableOpaquePath(path, surface))
|
|
1182
1239
|
throw new SettingAuthoringError(surface.opening
|
|
1183
1240
|
? localized(locale, "Special-file writes accept only opening.md, control/frame.yaml, control/player-views.yaml, control/blocks/*.md, or control/gameplay.json", "专用文件只允许写入 opening.md、control/frame.yaml、control/player-views.yaml、control/blocks/*.md 或 control/gameplay.json")
|
|
1184
1241
|
: localized(locale, "Special-file writes accept only control/frame.yaml, control/player-views.yaml, control/blocks/*.md, or control/gameplay.json", "专用文件只允许写入 control/frame.yaml、control/player-views.yaml、control/blocks/*.md 或 control/gameplay.json"));
|
|
1242
|
+
if (!hasOnly(call.arguments, ["path", "contents"]))
|
|
1243
|
+
throw new SettingAuthoringError("Special-file writes accept only path and contents");
|
|
1185
1244
|
const authoredContents = requiredString(call.arguments.contents, "contents");
|
|
1186
1245
|
assertNoLiteralUnicodeEscapes(authoredContents, locale);
|
|
1187
1246
|
const contents = projectOpaqueDocumentIds(snapshot, path, authoredContents);
|