@world-engines/view-exposure 0.0.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/LICENSE ADDED
@@ -0,0 +1,46 @@
1
+ WorldEngine 官方作者工具许可证
2
+
3
+ 版权所有 (c) 2026 Nixdorfer。保留所有权利。
4
+
5
+ 本仓库的源代码、构建材料及附带资源(统称“本作品”)不是开源软件,
6
+ 不适用任何 OSI 认证的开源许可证。
7
+
8
+ 一、官方作者工具分发许可
9
+
10
+ 版权所有者可以通过其官方网站、npm registry、签名安装包或其他官方渠道,
11
+ 复制并分发由本作品构建的 WorldEngine 作者工具及其必要运行资源
12
+ (统称“官方作者工具”)。仅版权所有者或其书面指定的发布者享有此分发权。
13
+
14
+ 二、作者用户许可
15
+
16
+ 从官方渠道取得官方作者工具的作者用户,可以:
17
+
18
+ 1. 安装和运行官方作者工具;
19
+ 2. 使用官方作者工具创作、编辑、预览、导入、导出和提交其有权处理的内容;
20
+ 3. 为上述使用目的制作合理必要的本地备份副本。
21
+
22
+ 三、未授予的权利
23
+
24
+ 除第二条明确允许的行为外,本许可证不授予作者用户或其他第三方以下权利:
25
+
26
+ 1. 修改、改编、反编译、反汇编或制作官方作者工具的派生作品;
27
+ 2. 复制、镜像、转发、再上传、出售、出租、再分发或再许可官方作者工具;
28
+ 3. 使用本作品的源代码、构建材料或任何部分开发、提供或训练其他产品或服务;
29
+ 4. 删除或规避版权、许可、签名、访问控制或其他权利管理信息。
30
+
31
+ 法律强制允许且合同不得排除的权利不受上述限制影响。
32
+
33
+ 四、源代码查看
34
+
35
+ 第三方可以在已获合法访问权限的范围内查看本作品,用于审查、安全研究或学习参考;
36
+ 查看不授予运行、复制、修改、分发、再许可或用于其他产品与服务的权利。
37
+
38
+ 五、无担保与责任限制
39
+
40
+ 本作品与官方作者工具均按“现状”提供,不附带任何明示或暗示的担保。
41
+ 在适用法律允许的最大范围内,版权所有者不对因访问或使用本作品或官方作者工具
42
+ 造成的任何损失承担责任。
43
+
44
+ 六、终止
45
+
46
+ 违反本许可证将立即终止相应的访问与使用权;终止不影响版权所有者已经产生的权利和救济。
@@ -0,0 +1,2 @@
1
+ export { filterForLlm, filterForTrigger, directorViewToolDescriptors, parseViewExposureManifest, stableViewExposureHash, triggerViewActionRegistrations } from "./normalize.js";
2
+ export { VIEW_EXPOSURE_LIMITS, VIEW_EXPOSURE_RESERVED_NAMES, VIEW_EXPOSURE_SCHEMA_VERSION, type ExposureRole, type DirectorViewToolDescriptor, type ExposureTarget, type LlmControlPolicy, type MessageAction, type MessagePolicy, type NormalizedViewExposureManifest, type PromptSlotAction, type PromptSlotPolicy, type StrictParametersSchema, type StrictSchema, type TriggerViewActionRegistration, type ViewExposureFunction, type ViewExposureManifest, type ViewExposureParseResult } from "./schema.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { filterForLlm, filterForTrigger, directorViewToolDescriptors, parseViewExposureManifest, stableViewExposureHash, triggerViewActionRegistrations } from "./normalize.js";
2
+ export { VIEW_EXPOSURE_LIMITS, VIEW_EXPOSURE_RESERVED_NAMES, VIEW_EXPOSURE_SCHEMA_VERSION } from "./schema.js";
@@ -0,0 +1,7 @@
1
+ import { type NormalizedViewExposureManifest, type ViewExposureFunction, type ViewExposureManifest, type ViewExposureParseResult, type DirectorViewToolDescriptor, type TriggerViewActionRegistration } from "./schema.js";
2
+ export declare const stableViewExposureHash: (manifest: ViewExposureManifest) => string;
3
+ export declare const parseViewExposureManifest: (input: unknown) => ViewExposureParseResult;
4
+ export declare const filterForLlm: (manifest: NormalizedViewExposureManifest) => ReadonlyArray<ViewExposureFunction>;
5
+ export declare const filterForTrigger: (manifest: NormalizedViewExposureManifest) => ReadonlyArray<ViewExposureFunction>;
6
+ export declare const directorViewToolDescriptors: (manifest: NormalizedViewExposureManifest) => ReadonlyArray<DirectorViewToolDescriptor>;
7
+ export declare const triggerViewActionRegistrations: (manifest: NormalizedViewExposureManifest) => ReadonlyArray<TriggerViewActionRegistration>;
@@ -0,0 +1,276 @@
1
+ import { VIEW_EXPOSURE_LIMITS as LIMIT, VIEW_EXPOSURE_RESERVED_NAMES, VIEW_EXPOSURE_SCHEMA_VERSION } from "./schema.js";
2
+ const NAME = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
3
+ const ID = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
4
+ const ENDPOINT = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
5
+ const EFFECT = /^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9]*)*$/;
6
+ const PROP = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
7
+ const TARGETS = new Set(["llm", "trigger", "both"]);
8
+ const ROLES = ["system", "user", "assistant"];
9
+ const PROMPT_ACTIONS = new Set(["read", "append", "replace", "remove"]);
10
+ const MESSAGE_ACTIONS = new Set(["insert", "replace", "remove"]);
11
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
12
+ const utf8Bytes = (value) => {
13
+ let bytes = 0;
14
+ for (const char of value) {
15
+ const point = char.codePointAt(0) ?? 0;
16
+ bytes += point <= 0x7f ? 1 : point <= 0x7ff ? 2 : point <= 0xffff ? 3 : 4;
17
+ }
18
+ return bytes;
19
+ };
20
+ const fail = (error) => ({ ok: false, error });
21
+ const text = (value, field, max, pattern) => {
22
+ if (typeof value !== "string")
23
+ throw new Error(`${field}_must_be_string`);
24
+ const trimmed = value.trim();
25
+ if (trimmed.length === 0)
26
+ throw new Error(`${field}_must_not_be_empty`);
27
+ if (trimmed.length > max)
28
+ throw new Error(`${field}_too_long`);
29
+ if (pattern !== undefined && !pattern.test(trimmed))
30
+ throw new Error(`${field}_invalid`);
31
+ return trimmed;
32
+ };
33
+ const exactKeys = (raw, allowed, field) => {
34
+ const set = new Set(allowed);
35
+ for (const key of Object.keys(raw))
36
+ if (!set.has(key))
37
+ throw new Error(`${field}_unknown_key:${key}`);
38
+ };
39
+ const normalizeSchema = (raw, depth, field) => {
40
+ if (depth > LIMIT.schemaDepth)
41
+ throw new Error(`${field}_too_deep`);
42
+ if (!isRecord(raw))
43
+ throw new Error(`${field}_must_be_object`);
44
+ const type = raw.type;
45
+ const description = raw.description === undefined
46
+ ? undefined
47
+ : text(raw.description, `${field}.description`, LIMIT.descriptionChars);
48
+ const base = description === undefined ? {} : { description };
49
+ if (type === "string") {
50
+ exactKeys(raw, ["type", "description", "enum"], field);
51
+ if (raw.enum === undefined)
52
+ return { type, ...base };
53
+ if (!Array.isArray(raw.enum) || raw.enum.length === 0 || raw.enum.length > LIMIT.enumValues) {
54
+ throw new Error(`${field}.enum_invalid`);
55
+ }
56
+ const values = raw.enum.map((v, index) => text(v, `${field}.enum[${index}]`, LIMIT.enumValueChars));
57
+ if (new Set(values).size !== values.length)
58
+ throw new Error(`${field}.enum_duplicate`);
59
+ return { type, ...base, enum: values };
60
+ }
61
+ if (type === "number" || type === "integer" || type === "boolean") {
62
+ exactKeys(raw, ["type", "description"], field);
63
+ return { type, ...base };
64
+ }
65
+ if (type === "array") {
66
+ exactKeys(raw, ["type", "description", "items"], field);
67
+ return { type, ...base, items: normalizeSchema(raw.items, depth + 1, `${field}.items`) };
68
+ }
69
+ if (type !== "object")
70
+ throw new Error(`${field}.type_unsupported`);
71
+ exactKeys(raw, ["type", "description", "properties", "required", "additionalProperties"], field);
72
+ if (!isRecord(raw.properties))
73
+ throw new Error(`${field}.properties_invalid`);
74
+ const keys = Object.keys(raw.properties).sort();
75
+ if (keys.length > LIMIT.schemaProperties)
76
+ throw new Error(`${field}.properties_too_many`);
77
+ for (const key of keys)
78
+ if (!PROP.test(key))
79
+ throw new Error(`${field}.property_name_invalid:${key}`);
80
+ if (!Array.isArray(raw.required) || raw.required.some((v) => typeof v !== "string")) {
81
+ throw new Error(`${field}.required_invalid`);
82
+ }
83
+ const required = [...raw.required].sort();
84
+ if (required.length !== keys.length || required.some((value, index) => value !== keys[index])) {
85
+ throw new Error(`${field}.required_must_cover_all_properties`);
86
+ }
87
+ if (raw.additionalProperties !== false)
88
+ throw new Error(`${field}.additional_properties_must_be_false`);
89
+ const properties = {};
90
+ for (const key of keys)
91
+ properties[key] = normalizeSchema(raw.properties[key], depth + 1, `${field}.${key}`);
92
+ return { type, ...base, properties, required, additionalProperties: false };
93
+ };
94
+ const normalizeFunction = (raw, index) => {
95
+ const field = `functions[${index}]`;
96
+ if (!isRecord(raw))
97
+ throw new Error(`${field}_must_be_object`);
98
+ exactKeys(raw, ["id", "name", "label", "description", "target", "parameters", "returns", "handler", "effects"], field);
99
+ const id = text(raw.id, `${field}.id`, LIMIT.idChars, ID);
100
+ const name = text(raw.name, `${field}.name`, LIMIT.nameChars, NAME);
101
+ if (VIEW_EXPOSURE_RESERVED_NAMES.has(name))
102
+ throw new Error(`${field}.name_reserved`);
103
+ if (!TARGETS.has(String(raw.target)))
104
+ throw new Error(`${field}.target_invalid`);
105
+ const parameters = normalizeSchema(raw.parameters, 1, `${field}.parameters`);
106
+ if (parameters.type !== "object")
107
+ throw new Error(`${field}.parameters_must_be_object`);
108
+ if (!isRecord(raw.handler))
109
+ throw new Error(`${field}.handler_invalid`);
110
+ exactKeys(raw.handler, ["endpoint"], `${field}.handler`);
111
+ if (!Array.isArray(raw.effects) || raw.effects.length > LIMIT.effects)
112
+ throw new Error(`${field}.effects_invalid`);
113
+ const effects = raw.effects.map((v, i) => text(v, `${field}.effects[${i}]`, 128, EFFECT)).sort();
114
+ if (new Set(effects).size !== effects.length)
115
+ throw new Error(`${field}.effects_duplicate`);
116
+ const returns = normalizeSchema(raw.returns, 1, `${field}.returns`);
117
+ const normalized = {
118
+ id,
119
+ name,
120
+ label: text(raw.label, `${field}.label`, LIMIT.labelChars),
121
+ description: text(raw.description, `${field}.description`, LIMIT.descriptionChars),
122
+ target: raw.target,
123
+ parameters: parameters,
124
+ returns,
125
+ handler: { endpoint: text(raw.handler.endpoint, `${field}.handler.endpoint`, LIMIT.endpointChars, ENDPOINT) },
126
+ effects
127
+ };
128
+ if (utf8Bytes(JSON.stringify(normalized.parameters)) > LIMIT.schemaBytes)
129
+ throw new Error(`${field}.parameters_too_large`);
130
+ if (utf8Bytes(JSON.stringify(returns)) > LIMIT.schemaBytes)
131
+ throw new Error(`${field}.returns_too_large`);
132
+ return normalized;
133
+ };
134
+ const stringActions = (raw, allowed, field) => {
135
+ if (!Array.isArray(raw) || raw.some((v) => typeof v !== "string" || !allowed.has(v)))
136
+ throw new Error(`${field}_invalid`);
137
+ const values = [...raw].sort();
138
+ if (new Set(values).size !== values.length)
139
+ throw new Error(`${field}_duplicate`);
140
+ return values;
141
+ };
142
+ const normalizeLlmControl = (raw, functionIds) => {
143
+ if (!isRecord(raw))
144
+ throw new Error("llmControl_must_be_object");
145
+ exactKeys(raw, ["promptSlots", "messagePolicy"], "llmControl");
146
+ if (!Array.isArray(raw.promptSlots) || raw.promptSlots.length > LIMIT.promptSlots)
147
+ throw new Error("promptSlots_invalid");
148
+ const promptSlots = raw.promptSlots.map((slot, index) => {
149
+ const field = `promptSlots[${index}]`;
150
+ if (!isRecord(slot))
151
+ throw new Error(`${field}_must_be_object`);
152
+ exactKeys(slot, ["id", "role", "actions", "maxChars"], field);
153
+ if (!ROLES.includes(slot.role))
154
+ throw new Error(`${field}.role_invalid`);
155
+ if (!Number.isInteger(slot.maxChars) || Number(slot.maxChars) < 1 || Number(slot.maxChars) > LIMIT.promptSlotChars)
156
+ throw new Error(`${field}.maxChars_invalid`);
157
+ return {
158
+ id: text(slot.id, `${field}.id`, LIMIT.idChars, ID),
159
+ role: slot.role,
160
+ actions: stringActions(slot.actions, PROMPT_ACTIONS, `${field}.actions`),
161
+ maxChars: Number(slot.maxChars)
162
+ };
163
+ }).sort((a, b) => a.id.localeCompare(b.id));
164
+ if (new Set(promptSlots.map((slot) => slot.id)).size !== promptSlots.length)
165
+ throw new Error("promptSlots_id_duplicate");
166
+ const policy = raw.messagePolicy;
167
+ if (!isRecord(policy))
168
+ throw new Error("messagePolicy_must_be_object");
169
+ exactKeys(policy, ["roles", "scope", "maxMessages", "maxCharsPerMessage", "allowToolCalls", "allowedToolIds"], "messagePolicy");
170
+ if (!isRecord(policy.roles))
171
+ throw new Error("messagePolicy.roles_invalid");
172
+ exactKeys(policy.roles, ROLES, "messagePolicy.roles");
173
+ if (policy.scope !== "view_overlay")
174
+ throw new Error("messagePolicy.scope_invalid");
175
+ if (!Number.isInteger(policy.maxMessages) || Number(policy.maxMessages) < 0 || Number(policy.maxMessages) > LIMIT.messageCount)
176
+ throw new Error("messagePolicy.maxMessages_invalid");
177
+ if (!Number.isInteger(policy.maxCharsPerMessage) || Number(policy.maxCharsPerMessage) < 1 || Number(policy.maxCharsPerMessage) > LIMIT.messageChars)
178
+ throw new Error("messagePolicy.maxCharsPerMessage_invalid");
179
+ if (typeof policy.allowToolCalls !== "boolean")
180
+ throw new Error("messagePolicy.allowToolCalls_invalid");
181
+ if (!Array.isArray(policy.allowedToolIds) || policy.allowedToolIds.length > LIMIT.allowedTools)
182
+ throw new Error("messagePolicy.allowedToolIds_invalid");
183
+ const allowedToolIds = policy.allowedToolIds.map((id, i) => text(id, `allowedToolIds[${i}]`, LIMIT.idChars, ID)).sort();
184
+ if (new Set(allowedToolIds).size !== allowedToolIds.length)
185
+ throw new Error("messagePolicy.allowedToolIds_duplicate");
186
+ for (const id of allowedToolIds)
187
+ if (!functionIds.has(id))
188
+ throw new Error(`messagePolicy.allowedToolId_unknown:${id}`);
189
+ if (!policy.allowToolCalls && allowedToolIds.length > 0)
190
+ throw new Error("messagePolicy.tools_disallowed_but_list_nonempty");
191
+ return {
192
+ promptSlots,
193
+ messagePolicy: {
194
+ roles: {
195
+ system: stringActions(policy.roles.system, MESSAGE_ACTIONS, "roles.system"),
196
+ user: stringActions(policy.roles.user, MESSAGE_ACTIONS, "roles.user"),
197
+ assistant: stringActions(policy.roles.assistant, MESSAGE_ACTIONS, "roles.assistant")
198
+ },
199
+ scope: "view_overlay",
200
+ maxMessages: Number(policy.maxMessages),
201
+ maxCharsPerMessage: Number(policy.maxCharsPerMessage),
202
+ allowToolCalls: policy.allowToolCalls,
203
+ allowedToolIds
204
+ }
205
+ };
206
+ };
207
+ const canonicalize = (value) => {
208
+ if (Array.isArray(value))
209
+ return value.map(canonicalize);
210
+ if (!isRecord(value))
211
+ return value;
212
+ const result = {};
213
+ for (const key of Object.keys(value).sort())
214
+ result[key] = canonicalize(value[key]);
215
+ return result;
216
+ };
217
+ export const stableViewExposureHash = (manifest) => {
218
+ const json = JSON.stringify(canonicalize(manifest));
219
+ let hash = 0xcbf29ce484222325n;
220
+ for (const char of json) {
221
+ const point = char.codePointAt(0) ?? 0;
222
+ hash ^= BigInt(point);
223
+ hash = BigInt.asUintN(64, hash * 0x100000001b3n);
224
+ }
225
+ return `fnv1a64:${hash.toString(16).padStart(16, "0")}`;
226
+ };
227
+ export const parseViewExposureManifest = (input) => {
228
+ try {
229
+ if (utf8Bytes(typeof input === "string" ? input : JSON.stringify(input)) > LIMIT.manifestBytes)
230
+ return fail("manifest_too_large");
231
+ const raw = typeof input === "string" ? JSON.parse(input) : input;
232
+ if (!isRecord(raw))
233
+ return fail("manifest_must_be_object");
234
+ exactKeys(raw, ["schemaVersion", "viewId", "revision", "functions", "llmControl"], "manifest");
235
+ if (raw.schemaVersion !== VIEW_EXPOSURE_SCHEMA_VERSION)
236
+ return fail("schema_version_unsupported");
237
+ if (!Number.isSafeInteger(raw.revision) || Number(raw.revision) < 0)
238
+ return fail("revision_invalid");
239
+ if (!Array.isArray(raw.functions) || raw.functions.length > LIMIT.functions)
240
+ return fail("functions_invalid");
241
+ const functions = raw.functions.map(normalizeFunction).sort((a, b) => a.id.localeCompare(b.id));
242
+ if (new Set(functions.map((fn) => fn.id)).size !== functions.length)
243
+ return fail("function_id_duplicate");
244
+ if (new Set(functions.map((fn) => fn.name)).size !== functions.length)
245
+ return fail("function_name_duplicate");
246
+ const manifest = {
247
+ schemaVersion: VIEW_EXPOSURE_SCHEMA_VERSION,
248
+ viewId: text(raw.viewId, "viewId", LIMIT.idChars, ID),
249
+ revision: Number(raw.revision),
250
+ functions,
251
+ llmControl: normalizeLlmControl(raw.llmControl, new Set(functions.map((fn) => fn.id)))
252
+ };
253
+ const normalized = { ...manifest, stableHash: stableViewExposureHash(manifest) };
254
+ return { ok: true, manifest: normalized };
255
+ }
256
+ catch (error) {
257
+ return fail(error instanceof Error ? error.message : "manifest_invalid");
258
+ }
259
+ };
260
+ export const filterForLlm = (manifest) => manifest.functions.filter((fn) => fn.target === "llm" || fn.target === "both");
261
+ export const filterForTrigger = (manifest) => manifest.functions.filter((fn) => fn.target === "trigger" || fn.target === "both");
262
+ export const directorViewToolDescriptors = (manifest) => filterForLlm(manifest).map((fn) => ({
263
+ exposureId: fn.id,
264
+ name: fn.name,
265
+ description: fn.description,
266
+ parameters: fn.parameters,
267
+ returns: fn.returns,
268
+ manifestHash: manifest.stableHash,
269
+ manifestRevision: manifest.revision
270
+ }));
271
+ export const triggerViewActionRegistrations = (manifest) => filterForTrigger(manifest).map((fn) => ({
272
+ action: fn.name,
273
+ exposureId: fn.id,
274
+ manifestHash: manifest.stableHash,
275
+ manifestRevision: manifest.revision
276
+ }));
@@ -0,0 +1,111 @@
1
+ export declare const VIEW_EXPOSURE_SCHEMA_VERSION: 1;
2
+ export declare const VIEW_EXPOSURE_LIMITS: {
3
+ readonly manifestBytes: 65536;
4
+ readonly schemaBytes: 16384;
5
+ readonly schemaDepth: 6;
6
+ readonly schemaProperties: 32;
7
+ readonly functions: 64;
8
+ readonly enumValues: 64;
9
+ readonly enumValueChars: 256;
10
+ readonly idChars: 128;
11
+ readonly nameChars: 64;
12
+ readonly labelChars: 128;
13
+ readonly descriptionChars: 1024;
14
+ readonly endpointChars: 256;
15
+ readonly effects: 32;
16
+ readonly promptSlots: 16;
17
+ readonly promptSlotChars: 16384;
18
+ readonly messageCount: 64;
19
+ readonly messageChars: 16384;
20
+ readonly allowedTools: 64;
21
+ };
22
+ export declare const VIEW_EXPOSURE_RESERVED_NAMES: ReadonlySet<string>;
23
+ export type ExposureTarget = "llm" | "trigger" | "both";
24
+ export type ExposureRole = "system" | "user" | "assistant";
25
+ export type PromptSlotAction = "read" | "append" | "replace" | "remove";
26
+ export type MessageAction = "insert" | "replace" | "remove";
27
+ export type StrictSchema = {
28
+ readonly type: "string";
29
+ readonly description?: string;
30
+ readonly enum?: ReadonlyArray<string>;
31
+ } | {
32
+ readonly type: "number" | "integer" | "boolean";
33
+ readonly description?: string;
34
+ } | {
35
+ readonly type: "array";
36
+ readonly description?: string;
37
+ readonly items: StrictSchema;
38
+ } | {
39
+ readonly type: "object";
40
+ readonly description?: string;
41
+ readonly properties: Readonly<Record<string, StrictSchema>>;
42
+ readonly required: ReadonlyArray<string>;
43
+ readonly additionalProperties: false;
44
+ };
45
+ export type StrictParametersSchema = Extract<StrictSchema, {
46
+ readonly type: "object";
47
+ }>;
48
+ export interface ViewExposureFunction {
49
+ readonly id: string;
50
+ readonly name: string;
51
+ readonly label: string;
52
+ readonly description: string;
53
+ readonly target: ExposureTarget;
54
+ readonly parameters: StrictParametersSchema;
55
+ readonly returns: StrictSchema;
56
+ readonly handler: {
57
+ readonly endpoint: string;
58
+ };
59
+ readonly effects: ReadonlyArray<string>;
60
+ }
61
+ export interface PromptSlotPolicy {
62
+ readonly id: string;
63
+ readonly role: ExposureRole;
64
+ readonly actions: ReadonlyArray<PromptSlotAction>;
65
+ readonly maxChars: number;
66
+ }
67
+ export interface MessagePolicy {
68
+ readonly roles: Readonly<Record<ExposureRole, ReadonlyArray<MessageAction>>>;
69
+ readonly scope: "view_overlay";
70
+ readonly maxMessages: number;
71
+ readonly maxCharsPerMessage: number;
72
+ readonly allowToolCalls: boolean;
73
+ readonly allowedToolIds: ReadonlyArray<string>;
74
+ }
75
+ export interface LlmControlPolicy {
76
+ readonly promptSlots: ReadonlyArray<PromptSlotPolicy>;
77
+ readonly messagePolicy: MessagePolicy;
78
+ }
79
+ export interface ViewExposureManifest {
80
+ readonly schemaVersion: typeof VIEW_EXPOSURE_SCHEMA_VERSION;
81
+ readonly viewId: string;
82
+ readonly revision: number;
83
+ readonly functions: ReadonlyArray<ViewExposureFunction>;
84
+ readonly llmControl: LlmControlPolicy;
85
+ }
86
+ export interface NormalizedViewExposureManifest extends ViewExposureManifest {
87
+ readonly stableHash: string;
88
+ }
89
+ /** Director 可见的最小客户端桥元数据;刻意不包含 iframe endpoint 和 effects。 */
90
+ export interface DirectorViewToolDescriptor {
91
+ readonly exposureId: string;
92
+ readonly name: string;
93
+ readonly description: string;
94
+ readonly parameters: StrictParametersSchema;
95
+ readonly returns: StrictSchema;
96
+ readonly manifestHash: string;
97
+ readonly manifestRevision: number;
98
+ }
99
+ export interface TriggerViewActionRegistration {
100
+ readonly action: string;
101
+ readonly exposureId: string;
102
+ readonly manifestHash: string;
103
+ readonly manifestRevision: number;
104
+ }
105
+ export type ViewExposureParseResult = {
106
+ readonly ok: true;
107
+ readonly manifest: NormalizedViewExposureManifest;
108
+ } | {
109
+ readonly ok: false;
110
+ readonly error: string;
111
+ };
package/dist/schema.js ADDED
@@ -0,0 +1,28 @@
1
+ export const VIEW_EXPOSURE_SCHEMA_VERSION = 1;
2
+ export const VIEW_EXPOSURE_LIMITS = {
3
+ manifestBytes: 65_536,
4
+ schemaBytes: 16_384,
5
+ schemaDepth: 6,
6
+ schemaProperties: 32,
7
+ functions: 64,
8
+ enumValues: 64,
9
+ enumValueChars: 256,
10
+ idChars: 128,
11
+ nameChars: 64,
12
+ labelChars: 128,
13
+ descriptionChars: 1_024,
14
+ endpointChars: 256,
15
+ effects: 32,
16
+ promptSlots: 16,
17
+ promptSlotChars: 16_384,
18
+ messageCount: 64,
19
+ messageChars: 16_384,
20
+ allowedTools: 64
21
+ };
22
+ export const VIEW_EXPOSURE_RESERVED_NAMES = new Set([
23
+ "LS", "Read", "Write", "Edit", "Bash", "BashOutput", "KillShell",
24
+ "Grep", "Glob", "WebFetch", "WebSearch", "ask_user", "craft_tool",
25
+ "list_registered_tools", "unregister_tool", "world_event_emit", "graph_query",
26
+ "entity_get", "relation_list", "vector_search", "setEntityTrigger",
27
+ "setPropTrigger", "clearEntityTrigger", "clearPropTrigger"
28
+ ]);
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@world-engines/view-exposure",
3
+ "private": false,
4
+ "version": "0.0.0",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "worldengine_source_sha256": "16846a6350543f542f746d271a8ffd9c7045b73a572eeb9f8e736ebf4841e1e3",
20
+ "worldengine_source_identity_provenance": {
21
+ "schema": "worldengine-public-namespace-projection/v1",
22
+ "kind": "composite-source-identity; namespace projection; not-full-source-recompile",
23
+ "original_name": "@chat/view-exposure",
24
+ "original_archive_sha256": "7431c8f6a82b0b4f1dc360c0f39529063b115bc510e68140b6b5fbd6bfe796a9",
25
+ "original_source_sha256": "d4713218e9c323ce747b568e124189f5c9039d5de7c16c8e12f488754ba9db99",
26
+ "projected_name": "@world-engines/view-exposure",
27
+ "package_name_mapping": {
28
+ "@chat/blocks-editor": "@world-engines/blocks-editor",
29
+ "@chat/ladybug-bridge": "@world-engines/ladybug-bridge",
30
+ "@chat/monaco-host": "@world-engines/monaco-host",
31
+ "@chat/protocol-ts": "@world-engines/protocol-ts",
32
+ "@chat/scenario-author-source": "@world-engines/scenario-author-source",
33
+ "@chat/scenario-review-snapshot": "@world-engines/scenario-review-snapshot",
34
+ "@chat/tmw": "@world-engines/tmw",
35
+ "@chat/view-exposure": "@world-engines/view-exposure",
36
+ "@world-engines/chatplay-vite-plugin": "@world-engines/chatplay-vite-plugin",
37
+ "@worldengine/agent-kit": "@world-engines/agent-kit",
38
+ "@worldengine/authoring-bridge": "@world-engines/authoring-bridge",
39
+ "@worldengine/authoring-ui": "@world-engines/authoring-ui",
40
+ "@worldengine/create-project": "@world-engines/create-project",
41
+ "@worldengine/project-format": "@world-engines/project-format",
42
+ "@worldengine/project-host": "@world-engines/project-host",
43
+ "@worldengine/project-setup": "@world-engines/project-setup",
44
+ "@worldengine/spatial-authoring": "@world-engines/spatial-authoring",
45
+ "@worldengine/view-sdk": "@world-engines/view-sdk"
46
+ }
47
+ }
48
+ }