@ptengine/inline-editor 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +286 -2
- package/dist/InlineEditor.d.ts +349 -0
- package/dist/InlineEditor.js +886 -0
- package/dist/PagePreview.d.ts +83 -0
- package/dist/PagePreview.js +111 -0
- package/dist/assets/AssetsPanel.d.ts +19 -0
- package/dist/assets/AssetsPanel.js +23 -0
- package/dist/assets/componentLibrary.d.ts +23 -0
- package/dist/assets/componentLibrary.js +12 -0
- package/dist/canvas-ui/index.d.ts +17 -0
- package/dist/canvas-ui/index.js +7 -0
- package/dist/canvas-ui/scope.d.ts +13 -0
- package/dist/canvas-ui/scope.js +1 -0
- package/dist/canvas-ui/selection/classNames.d.ts +30 -0
- package/dist/canvas-ui/selection/classNames.js +15 -0
- package/dist/canvas-ui/selection/tokens.css +204 -0
- package/dist/canvas-ui/tree/TreePanel.d.ts +47 -0
- package/dist/canvas-ui/tree/TreePanel.js +132 -0
- package/dist/canvas-ui/tree/classNames.d.ts +21 -0
- package/dist/canvas-ui/tree/classNames.js +8 -0
- package/dist/canvas-ui/tree/order.d.ts +38 -0
- package/dist/canvas-ui/tree/order.js +38 -0
- package/dist/canvas-ui/tree/tree.css +131 -0
- package/dist/chrome/EditorChrome.d.ts +83 -0
- package/dist/chrome/EditorChrome.js +10 -0
- package/dist/chrome/VersionMenu.d.ts +26 -0
- package/dist/chrome/VersionMenu.js +86 -0
- package/dist/chrome/topbarPrimitives.d.ts +69 -0
- package/dist/chrome/topbarPrimitives.js +39 -0
- package/dist/chrome/useDismissOnOutside.d.ts +23 -0
- package/dist/chrome/useDismissOnOutside.js +27 -0
- package/dist/dialogs/ClickActionDialog.d.ts +24 -0
- package/dist/dialogs/ClickActionDialog.js +35 -0
- package/dist/dialogs/HtmlEditDialog.d.ts +23 -0
- package/dist/dialogs/HtmlEditDialog.js +23 -0
- package/dist/dialogs/ImageEditDialog.d.ts +30 -0
- package/dist/dialogs/ImageEditDialog.js +57 -0
- package/dist/dialogs/ImageSettingDialog.d.ts +16 -0
- package/dist/dialogs/ImageSettingDialog.js +17 -0
- package/dist/dialogs/InsertElementDialog.d.ts +23 -0
- package/dist/dialogs/InsertElementDialog.js +28 -0
- package/dist/dialogs/ReplaceVideoDialog.d.ts +18 -0
- package/dist/dialogs/ReplaceVideoDialog.js +16 -0
- package/dist/dialogs/actionTypes.d.ts +53 -0
- package/dist/dialogs/actionTypes.js +74 -0
- package/dist/dialogs/htmlValidation.d.ts +24 -0
- package/dist/dialogs/htmlValidation.js +37 -0
- package/dist/dialogs/imageEdit.d.ts +49 -0
- package/dist/dialogs/imageEdit.js +30 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +53 -0
- package/dist/kernel/CanvasContextBar.d.ts +23 -0
- package/dist/kernel/CanvasContextBar.js +12 -0
- package/dist/kernel/CanvasFrame.d.ts +56 -0
- package/dist/kernel/CanvasFrame.js +53 -0
- package/dist/kernel/ai/aiInlineApply.d.ts +330 -0
- package/dist/kernel/ai/aiInlineApply.js +477 -0
- package/dist/kernel/ai/imageSource.d.ts +24 -0
- package/dist/kernel/ai/imageSource.js +19 -0
- package/dist/kernel/ai/insertHtmlGate.d.ts +71 -0
- package/dist/kernel/ai/insertHtmlGate.js +123 -0
- package/dist/kernel/ai/postApplyCheck.d.ts +56 -0
- package/dist/kernel/ai/postApplyCheck.js +74 -0
- package/dist/kernel/ai/replaceHtmlGate.d.ts +71 -0
- package/dist/kernel/ai/replaceHtmlGate.js +147 -0
- package/dist/kernel/blocks/BlockOverlay.d.ts +16 -0
- package/dist/kernel/blocks/BlockOverlay.js +66 -0
- package/dist/kernel/blocks/annotateAndTile.d.ts +106 -0
- package/dist/kernel/blocks/annotateAndTile.js +122 -0
- package/dist/kernel/blocks/resolveBlocks.d.ts +153 -0
- package/dist/kernel/blocks/resolveBlocks.js +233 -0
- package/dist/kernel/canvasCapabilities.d.ts +31 -0
- package/dist/kernel/canvasCapabilities.js +39 -0
- package/dist/kernel/canvasCommands.d.ts +126 -0
- package/dist/kernel/canvasCommands.js +146 -0
- package/dist/kernel/canvasErrors.d.ts +1 -0
- package/dist/kernel/canvasErrors.js +14 -0
- package/dist/kernel/captureGeometry.d.ts +35 -0
- package/dist/kernel/captureGeometry.js +25 -0
- package/dist/kernel/captureOrchestration.d.ts +48 -0
- package/dist/kernel/captureOrchestration.js +43 -0
- package/dist/kernel/captureSlices.d.ts +36 -0
- package/dist/kernel/captureSlices.js +20 -0
- package/dist/kernel/changelist/ChangeListPanel.d.ts +13 -0
- package/dist/kernel/changelist/ChangeListPanel.js +47 -0
- package/dist/kernel/changelist/ChangeListPopover.d.ts +20 -0
- package/dist/kernel/changelist/ChangeListPopover.js +10 -0
- package/dist/kernel/changelist/builders.d.ts +89 -0
- package/dist/kernel/changelist/builders.js +81 -0
- package/dist/kernel/changelist/changeSummary.d.ts +19 -0
- package/dist/kernel/changelist/changeSummary.js +85 -0
- package/dist/kernel/changelist/clipboard.d.ts +16 -0
- package/dist/kernel/changelist/clipboard.js +4 -0
- package/dist/kernel/changelist/exportForSave.d.ts +30 -0
- package/dist/kernel/changelist/exportForSave.js +11 -0
- package/dist/kernel/changelist/mergeForSave.d.ts +79 -0
- package/dist/kernel/changelist/mergeForSave.js +40 -0
- package/dist/kernel/changelist/moveObserverSafety.d.ts +70 -0
- package/dist/kernel/changelist/moveObserverSafety.js +39 -0
- package/dist/kernel/changelist/overrides.d.ts +22 -0
- package/dist/kernel/changelist/overrides.js +63 -0
- package/dist/kernel/changelist/useChangeList.d.ts +200 -0
- package/dist/kernel/changelist/useChangeList.js +282 -0
- package/dist/kernel/config.d.ts +29 -0
- package/dist/kernel/config.js +10 -0
- package/dist/kernel/dataUrlToBlob.d.ts +8 -0
- package/dist/kernel/dataUrlToBlob.js +17 -0
- package/dist/kernel/linkHref.d.ts +25 -0
- package/dist/kernel/linkHref.js +16 -0
- package/dist/kernel/mobileFit.d.ts +46 -0
- package/dist/kernel/mobileFit.js +44 -0
- package/dist/kernel/moveState.d.ts +35 -0
- package/dist/kernel/moveState.js +14 -0
- package/dist/kernel/selection/SelectionOverlay.d.ts +10 -0
- package/dist/kernel/selection/SelectionOverlay.js +25 -0
- package/dist/kernel/selection/SelectionToolbar.d.ts +30 -0
- package/dist/kernel/selection/SelectionToolbar.js +82 -0
- package/dist/kernel/selection/SelectorPathBar.d.ts +27 -0
- package/dist/kernel/selection/SelectorPathBar.js +55 -0
- package/dist/kernel/selection/buildDescendantShelf.d.ts +40 -0
- package/dist/kernel/selection/buildDescendantShelf.js +50 -0
- package/dist/kernel/selection/buildRootShelf.d.ts +26 -0
- package/dist/kernel/selection/buildRootShelf.js +149 -0
- package/dist/kernel/selection/elementAiContext.d.ts +324 -0
- package/dist/kernel/selection/elementAiContext.js +122 -0
- package/dist/kernel/selection/elementGeometryForAi.d.ts +9 -0
- package/dist/kernel/selection/elementGeometryForAi.js +15 -0
- package/dist/kernel/selection/geometry.d.ts +55 -0
- package/dist/kernel/selection/geometry.js +18 -0
- package/dist/kernel/selection/resolveAnchors.d.ts +116 -0
- package/dist/kernel/selection/resolveAnchors.js +173 -0
- package/dist/kernel/selection/shelfRow.d.ts +33 -0
- package/dist/kernel/selection/shelfRow.js +21 -0
- package/dist/kernel/selection/tagLabels.d.ts +9 -0
- package/dist/kernel/selection/tagLabels.js +46 -0
- package/dist/kernel/selection/toolbarButtons.d.ts +60 -0
- package/dist/kernel/selection/toolbarButtons.js +105 -0
- package/dist/kernel/selection/useAiSelectionContext.d.ts +26 -0
- package/dist/kernel/selection/useAiSelectionContext.js +26 -0
- package/dist/kernel/selection/useCanvasGeometry.d.ts +32 -0
- package/dist/kernel/selection/useCanvasGeometry.js +47 -0
- package/dist/kernel/selection/useSelectionRestore.d.ts +18 -0
- package/dist/kernel/selection/useSelectionRestore.js +25 -0
- package/dist/kernel/shrinkImageForUpload.d.ts +45 -0
- package/dist/kernel/shrinkImageForUpload.js +61 -0
- package/dist/kernel/useCanvasBridge.d.ts +36 -0
- package/dist/kernel/useCanvasBridge.js +41 -0
- package/dist/kernel/useCanvasGate.d.ts +22 -0
- package/dist/kernel/useCanvasGate.js +35 -0
- package/dist/kernel/useCanvasSession.d.ts +44 -0
- package/dist/kernel/useCanvasSession.js +182 -0
- package/dist/kernel/useCanvasStream.d.ts +39 -0
- package/dist/kernel/useCanvasStream.js +45 -0
- package/dist/kernel/useMobileFit.d.ts +40 -0
- package/dist/kernel/useMobileFit.js +139 -0
- package/dist/locales.d.ts +1094 -0
- package/dist/locales.js +545 -0
- package/dist/panels/StylePanel.d.ts +24 -0
- package/dist/panels/StylePanel.js +40 -0
- package/dist/panels/styleFields.d.ts +39 -0
- package/dist/panels/styleFields.js +91 -0
- package/dist/tree/LayersPanel.d.ts +30 -0
- package/dist/tree/LayersPanel.js +15 -0
- package/dist/tree/domTreeAdapter.d.ts +63 -0
- package/dist/tree/domTreeAdapter.js +90 -0
- package/dist/useInlineEditor.d.ts +161 -0
- package/dist/useInlineEditor.js +346 -0
- package/package.json +58 -3
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI 提出的 inline 改动 → 落到画布上。
|
|
3
|
+
*
|
|
4
|
+
* ## 这是三道闸的第三道
|
|
5
|
+
*
|
|
6
|
+
* | 闸 | 在哪 | 拦什么 |
|
|
7
|
+
* |---|---|---|
|
|
8
|
+
* | ① 生成端 | mastra `agents/experience-inline/schema.ts` 的 zod | 形状、`<`、`{}`/`javascript:`、CSS 属性名形状、条数 |
|
|
9
|
+
* | ② 装配端 | backend 的 inline 白名单(53/54/55/56) | 存库时的类型准入 |
|
|
10
|
+
* | ③ 编辑器 | **本文件** | 白名单、形状、作用域、selector 是否真的命中、内容安全 |
|
|
11
|
+
*
|
|
12
|
+
* 第三道不是多余的:前两道都在服务端,而**只有这里知道客户页此刻长什么样**
|
|
13
|
+
* (selector 命中几个元素要发 `resolveSelector` 才知道),也只有这里在真的往用户的
|
|
14
|
+
* 页面上写东西。
|
|
15
|
+
*
|
|
16
|
+
* ## 与现役 engage-editor 逐字对齐
|
|
17
|
+
*
|
|
18
|
+
* 映射语义抄自 `engage-editor/src/editor/services/aiInlineApply.service.js`:
|
|
19
|
+
*
|
|
20
|
+
* - `EDIT_TEXT` → 一条 `elementContent`,`mode: 'replace'` + **`isTextChange: true`**
|
|
21
|
+
* (走「换 innerHTML、外壳保留」;漏掉这个字段会把元素本身换掉)
|
|
22
|
+
* - `CHANGE_STYLE` → **每个 CSS 属性一条** `elementStyle`
|
|
23
|
+
*
|
|
24
|
+
* 另外三个是本路径(编辑器里的对话)特有的,现役那份没有:
|
|
25
|
+
*
|
|
26
|
+
* - `INSERT_ELEMENT` → `insertElement()`,即 `elementContent` + `mode: insert/append/before/after`。
|
|
27
|
+
* content 是 **HTML** —— 全项目唯一一处真要审标记的地方,见 `insertHtmlGate.ts`
|
|
28
|
+
* - `MOVE_ELEMENT` → `elementMove`,target **只允许选中元素的祖先**(理由见 scope 注释)
|
|
29
|
+
* - `DELETE_ELEMENT` → `deleteElement()`,即 `display: none`(**不是真删**,与工具条一致)
|
|
30
|
+
* - `CHANGE_IMAGE` → `replaceImage()` 的 img-src / background 两分支(**不走 insert**:
|
|
31
|
+
* AI 只换图不插图),`alt` 有值时再追加一条 `setImageAlt()`
|
|
32
|
+
* - `SET_LINK` → `setClickAction()` + `buildActionObject({type:'link'})`,与「点击动作」
|
|
33
|
+
* 弹框里选 link 产出的对象逐字段同形
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ 后五个**直接复用 `useChangeList` 里工具条那几个函数**(`insertElement` / `deleteElement` /
|
|
36
|
+
* `replaceImage` / `setImageAlt` / `setClickAction`),不自己拼 input:AI 与用户手工操作必须
|
|
37
|
+
* 产出同一种 change,否则同一个改动两条路存出来的数据不一样。
|
|
38
|
+
*
|
|
39
|
+
* ## 换图 / 改跳转多一道「来源闸」
|
|
40
|
+
*
|
|
41
|
+
* 前五个 op 的内容是模型自己写的文字与样式,落点全在客户页内部;这两个不一样 ——
|
|
42
|
+
* 一个 `src` / `url` 就是一条**对外请求面**,写进去等于让客户页去拉一个第三方地址
|
|
43
|
+
* (换图还会被真实用户加载,改跳转会把流量送走)。所以它们的地址必须**来源可指认**:
|
|
44
|
+
* 图片 origin 在宿主给的白名单里(上传域 / 页面自身),链接与页面同源或用户逐字给过。
|
|
45
|
+
* 模型凭记忆敲一个域名出来,这里必须拦下。
|
|
46
|
+
*
|
|
47
|
+
* ⚠️ 两个编辑器必须产出同样的 change,否则同一个 AI 建议在两边存出来的数据不一样,
|
|
48
|
+
* 而这种偏差要到发布后看线上效果才会发现。错误码也照抄(`INVALID_TEXT_CONTENT` 等),
|
|
49
|
+
* 好让两边的日志能对照着看。
|
|
50
|
+
*
|
|
51
|
+
* ## 刻意不做的事
|
|
52
|
+
*
|
|
53
|
+
* 不自己构造 `InlineChange`,而是产出 `*Input` 交给 `useChangeList` 的 `addStyle` /
|
|
54
|
+
* `addContent` —— 那条路径带着覆盖去重(DEC-21)、「先应用成功再入列」的顺序、以及
|
|
55
|
+
* 撤销闭包的记账。绕过它自己拼 change 等于把这些全丢掉。
|
|
56
|
+
*/
|
|
57
|
+
import type { ContentChangeInput, MoveChangeInput, StyleChangeInput } from '../changelist/builders.js';
|
|
58
|
+
import type { AttributeChangeInput, ActionChangeInput } from '../changelist/builders.js';
|
|
59
|
+
import type { ElementCapabilities, ViewportRect } from '@ptengine/inline-core/protocol';
|
|
60
|
+
import { type ApplyCheck } from './postApplyCheck.js';
|
|
61
|
+
/**
|
|
62
|
+
* 允许 AI 产出的操作。与 mastra `EDITOR_INLINE_OPS` 逐字一致。
|
|
63
|
+
*
|
|
64
|
+
* ⚠️ 比 Harness 那条批量流的 `INLINE_SAFE_OPS`(只有前两个)**宽**:那边是无人值守地
|
|
65
|
+
* 批量生成,这边是用户选中了一个元素、在编辑器里看着结果、每条都能单独撤销。
|
|
66
|
+
* 两个词表**刻意分开**,别为了「统一」把 Harness 那边一起放宽。
|
|
67
|
+
*
|
|
68
|
+
* ⚠️ **顺序与拼写都要与 mastra 那份对齐**(`tools/inline-edit/schema.ts`):这边多一个,
|
|
69
|
+
* agent 给的那条会被 `NOT_IN_WHITELIST` 拒掉;那边多一个,agent 永远不会调它。
|
|
70
|
+
* 两边都不报错,只是改动永远不落地。
|
|
71
|
+
*/
|
|
72
|
+
export declare const AI_SAFE_OPS: readonly ["EDIT_TEXT", "CHANGE_STYLE", "INSERT_ELEMENT", "MOVE_ELEMENT", "DELETE_ELEMENT", "CHANGE_IMAGE", "SET_LINK", "EDIT_HTML"];
|
|
73
|
+
/** `INSERT_ELEMENT` 的位置。**不含 `replace`** —— 那会把目标元素整个换掉,不是「插入」。 */
|
|
74
|
+
export declare const AI_INSERT_MODES: readonly ["insert", "append", "before", "after"];
|
|
75
|
+
/** `MOVE_ELEMENT` 的位置。与 content 那套词表不同(同名 before/after 映射到不同数值)。 */
|
|
76
|
+
export declare const AI_MOVE_MODES: readonly ["top", "bottom", "before", "after"];
|
|
77
|
+
export type AiSafeOp = (typeof AI_SAFE_OPS)[number];
|
|
78
|
+
/** 线上形状 —— 与 mastra `inlineChangeSchema` 一致(`rationale` 只用于展示)。 */
|
|
79
|
+
export interface AiWireChange {
|
|
80
|
+
abTestType: string;
|
|
81
|
+
selector: string;
|
|
82
|
+
/** EDIT_TEXT: 纯文本;CHANGE_STYLE: CSS 声明;INSERT_ELEMENT: HTML。MOVE/DELETE 不用。 */
|
|
83
|
+
content?: string;
|
|
84
|
+
/** INSERT_ELEMENT / MOVE_ELEMENT 的位置(两套词表不同,见上)。 */
|
|
85
|
+
mode?: string;
|
|
86
|
+
/** MOVE_ELEMENT 的目标 —— 只允许选中元素的祖先之一。 */
|
|
87
|
+
targetSelector?: string;
|
|
88
|
+
/** CHANGE_IMAGE 的新图地址。必须过 host 白名单闸(见 `allowedImageOrigins`)。 */
|
|
89
|
+
src?: string;
|
|
90
|
+
/** CHANGE_IMAGE 的新 alt。有值时**额外**落一条 `changeElementAttribute alt`。 */
|
|
91
|
+
alt?: string;
|
|
92
|
+
/** SET_LINK 的跳转地址。必须过来源闸(同源,或用户逐字给过)。 */
|
|
93
|
+
url?: string;
|
|
94
|
+
/** SET_LINK 是否新标签页打开。缺省 false。 */
|
|
95
|
+
newTab?: boolean;
|
|
96
|
+
rationale?: {
|
|
97
|
+
candidateSelector?: string;
|
|
98
|
+
briefPoint?: string;
|
|
99
|
+
summary?: string;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export type AiRejectReason = 'NOT_IN_WHITELIST' | 'INVALID_SHAPE' | 'OUT_OF_SCOPE' | 'ELEMENTS_NOT_FOUND'
|
|
103
|
+
/** content / summary 里有替换字符 U+FFFD(模型吐坏的字):这一条不落地,让它只重发这一条。 */
|
|
104
|
+
| 'GARBLED_TEXT'
|
|
105
|
+
/** 探测 selector 时通道 / 会话出错(不是「找不到」):该重试,`detail` 带原文。 */
|
|
106
|
+
| 'RESOLVE_FAILED' | 'AMBIGUOUS_SELECTOR' | 'INVALID_TEXT_CONTENT' | 'INVALID_STYLE_CONTENT'
|
|
107
|
+
/** 新增元素那段 HTML 没过闸(标签/属性/取值/体量),detail 里是具体原因。 */
|
|
108
|
+
| 'INVALID_HTML_CONTENT'
|
|
109
|
+
/** mode 不在该 op 的词表里(两套词表容易串)。 */
|
|
110
|
+
| 'INVALID_MODE'
|
|
111
|
+
/** 移动的目标不是选中元素的祖先,或它在页面上不唯一。 */
|
|
112
|
+
| 'INVALID_MOVE_TARGET' | 'APPLY_FAILED'
|
|
113
|
+
/** 换图的 `src` 不是 http(s),或它的 origin 不在宿主给的白名单里(模型凭记忆编的域名)。 */
|
|
114
|
+
| 'UNSAFE_IMAGE_SRC'
|
|
115
|
+
/**
|
|
116
|
+
* `EDIT_TEXT` 的目标是个容器(自己没有直接文本、却有子元素):换 innerHTML 会把里面的图片、按钮
|
|
117
|
+
* 一起换成一个字符串。2026-09-30 方案卡对 `div.pf-31_>div` 写 EDIT_TEXT 就是这种 —— 正确的落点
|
|
118
|
+
* 是它里面那个文字叶子(货架里有)。能力位拿不到(老扩展)时不判。
|
|
119
|
+
*/
|
|
120
|
+
| 'TEXT_TARGET_IS_CONTAINER'
|
|
121
|
+
/** `insert` / `append` 进一个装不下孩子的元素(`<img>`、void 标签):扩展会静默插进去、页面上什么都不出现。 */
|
|
122
|
+
| 'INSERT_TARGET_NO_CHILDREN'
|
|
123
|
+
/** `before` / `after` 在一个不能有兄弟的元素旁(`<td>` 这类):落点不成立。 */
|
|
124
|
+
| 'INSERT_NO_SIBLING'
|
|
125
|
+
/** 目标既不是 `<img>` 也没有背景图 —— 换图无处可落(AI 不走「插入一张新图」那条分支)。 */
|
|
126
|
+
| 'IMAGE_TARGET_UNSUPPORTED'
|
|
127
|
+
/** 跳转地址不是 http(s),或既不同源也不是用户逐字给过的那个 URL。 */
|
|
128
|
+
| 'UNSAFE_LINK_URL'
|
|
129
|
+
/** 目标不可点(`capabilities.canEditLink` 为假):配上去 SDK 也不会执行。 */
|
|
130
|
+
| 'LINK_TARGET_UNSUPPORTED'
|
|
131
|
+
/**
|
|
132
|
+
* agent 报的版本名在宿主那边**查无此版**(名字对不上、那一版已被删)。
|
|
133
|
+
*
|
|
134
|
+
* ⚠️ **本文件永远不会产出它** —— 包只认 versionId,名字到 id 的映射是宿主做的,
|
|
135
|
+
* 只有宿主知道有哪些版本。放进同一个词表是因为它回答的是同一个问题:
|
|
136
|
+
* 「这条为什么没落地」,卡片上要与其它原因并排展示。
|
|
137
|
+
*/
|
|
138
|
+
| 'VERSION_NOT_FOUND'
|
|
139
|
+
/**
|
|
140
|
+
* 这一批指名了另一个版本,但切过去失败了 —— **不是**这一层产出的,由 `InlineEditor`
|
|
141
|
+
* 在切换失败时整批填进来(停留在当前版本,一条都不应用:半批落在错误版本上比不落更糟)。
|
|
142
|
+
*/
|
|
143
|
+
| 'VERSION_SWITCH_FAILED'
|
|
144
|
+
/**
|
|
145
|
+
* 要撤销的那一批不属于当前版本(id 映射后不在当前清单里)—— 同样由 `InlineEditor`
|
|
146
|
+
* 产出,宿主据此把卡片上的「撤销这一批」禁掉,而不是让用户点了什么都没发生。
|
|
147
|
+
*/
|
|
148
|
+
| 'VERSION_NOT_ACTIVE'
|
|
149
|
+
/**
|
|
150
|
+
* 编辑器已关 / 画布会话失效 —— **不是**这一层产出的,由宿主在拿不到 apply 入口时
|
|
151
|
+
* 填进来。放进同一个词表是因为它回答的是同一个问题:「这条为什么没落地」。
|
|
152
|
+
*/
|
|
153
|
+
| 'EDITOR_CLOSED';
|
|
154
|
+
export interface AiApplyReject {
|
|
155
|
+
index: number;
|
|
156
|
+
selector: string;
|
|
157
|
+
reason: AiRejectReason;
|
|
158
|
+
/** `APPLY_FAILED` 时是画布命令的错误码/消息。 */
|
|
159
|
+
detail?: string;
|
|
160
|
+
}
|
|
161
|
+
export interface AiAppliedChange {
|
|
162
|
+
index: number;
|
|
163
|
+
selector: string;
|
|
164
|
+
op: AiSafeOp;
|
|
165
|
+
/** 一句人话(来自 `rationale.summary`),给卡片展示。 */
|
|
166
|
+
summary?: string;
|
|
167
|
+
/** 落进清单的 changeId —— 卡片靠它「撤销这一批」,不能用 revertAll(那会连用户手改的一起撤)。 */
|
|
168
|
+
changeIds: string[];
|
|
169
|
+
/** 这条改动插入的新元素 selector(INSERT 的根 / EDIT_HTML 的新根)。没有就没这个键。 */
|
|
170
|
+
insertedSelectors?: string[];
|
|
171
|
+
/** 几何自检结果(宿主能量几何时才有,见 `AiApplyDeps.resolve`)。 */
|
|
172
|
+
check?: ApplyCheck;
|
|
173
|
+
}
|
|
174
|
+
export interface AiApplyOutcome {
|
|
175
|
+
applied: AiAppliedChange[];
|
|
176
|
+
rejected: AiApplyReject[];
|
|
177
|
+
}
|
|
178
|
+
/** `'color: red; font-weight: 700'` → 逐条声明。非法声明直接丢掉(不是整条拒绝)。 */
|
|
179
|
+
export declare function parseStyleDeclarations(content: string): Array<{
|
|
180
|
+
property: string;
|
|
181
|
+
value: string;
|
|
182
|
+
}>;
|
|
183
|
+
/**
|
|
184
|
+
* **授权票** —— 发消息那一刻交给 agent 的那份作用域(`<page-element>` 块里写着的
|
|
185
|
+
* 根 selector + 货架),由宿主随这一批改动一起交回来。
|
|
186
|
+
*
|
|
187
|
+
* ⚠️ 为什么需要它(真机 2026-09-22,vivaia 首屏换图):`<page-element>` 是**发消息那一刻**
|
|
188
|
+
* 的快照,而 `scope` 是**落地那一刻**的实时选中。一轮 agent 要 60-120 秒(光生图就 25 秒),
|
|
189
|
+
* 这中间选中只要没了(画布里点一下、切一次设备都会重建会话),作用域就退成整页 ——
|
|
190
|
+
* 于是 agent 逐字抄我们给它的 selector 也会被判 `OUT_OF_SCOPE`,而两端都不报错,
|
|
191
|
+
* 回执读起来像「AI 改不了这个页面」。
|
|
192
|
+
*
|
|
193
|
+
* 判的口径没变,仍然是**「我们给过它什么」**:票里的 selector 全是我们自己采集、自己发出去的,
|
|
194
|
+
* 落地前该做的解析、唯一性校验一条没少。它只是让这份授权活到这一轮结束,而不是活到
|
|
195
|
+
* 用户下一次点击为止。
|
|
196
|
+
*
|
|
197
|
+
* 货架是**数组不是取值函数**(与 `scope.descendants` 刻意不同):票就是一份快照,
|
|
198
|
+
* 它要的正是「当时那一份」,取值函数反而会取到现在这一份。
|
|
199
|
+
*/
|
|
200
|
+
export interface AiScopeGrant {
|
|
201
|
+
/** 票的根 —— `<page-element>` 里那行 `selector:`。 */
|
|
202
|
+
selector: string;
|
|
203
|
+
/** 票里的货架 —— 块里逐行列出、agent 唯一能逐字抄的那些。 */
|
|
204
|
+
descendants: string[];
|
|
205
|
+
/** 根的祖先链(不含根自己)。放行的改动按它算 `ancestors`,落盘收敛要用。 */
|
|
206
|
+
ancestors: string[];
|
|
207
|
+
}
|
|
208
|
+
export interface AiApplyDeps {
|
|
209
|
+
/**
|
|
210
|
+
* 允许被改的元素 —— 就是**用户提问时选中的那一个**。
|
|
211
|
+
*
|
|
212
|
+
* ⚠️ 这道闸不能省。agent 拿到的 selector 是我们给它的,但它完全可能自己编一个
|
|
213
|
+
* (`body > div:nth-of-type(3)`)。不校验的话,一句「把这个按钮改成绿色」可能改掉
|
|
214
|
+
* 整页所有按钮,**而且没有任何报错** —— 用户只会看到页面花了。
|
|
215
|
+
*/
|
|
216
|
+
scope: {
|
|
217
|
+
selector: string;
|
|
218
|
+
/**
|
|
219
|
+
* 作用域根的 identifier。
|
|
220
|
+
*
|
|
221
|
+
* ⚠️ **不再进 change** —— 每条 change 的 `identifier` 一律用它自己的 selector
|
|
222
|
+
* (见 `base` 那段注释:与工具条产出同形)。保留这个字段是因为调用方仍用它自述
|
|
223
|
+
* 「这个作用域是谁」,而且它属于已发布的签名。
|
|
224
|
+
*/
|
|
225
|
+
identifier: string;
|
|
226
|
+
/**
|
|
227
|
+
* 被授权的后代 selector(货架)—— **取值函数,不是数组**。
|
|
228
|
+
*
|
|
229
|
+
* 作用域 = 「选中元素本身」∪ 这一批。它是授权清单,不是参考资料:
|
|
230
|
+
* agent 只能逐字抄,不能自己拼;拼错的 selector 改错元素不报错。
|
|
231
|
+
*
|
|
232
|
+
* ⚠️ **为什么是函数**:货架是异步拉来的(`getDomTree`),而 apply 入口在选中变化
|
|
233
|
+
* 那一刻就注册好了。传数组的话闭包里存的是注册那一瞬间的快照 —— 那时货架还是空的,
|
|
234
|
+
* 于是 agent 明明按货架给了子元素 selector,却全被判 `OUT_OF_SCOPE`(真机踩过)。
|
|
235
|
+
* 改成函数让**调用时才取**,这类错就结构上不可能再犯。
|
|
236
|
+
*
|
|
237
|
+
* 省略 / 返回空 = 退回「只能改选中元素本身」。
|
|
238
|
+
*/
|
|
239
|
+
descendants?: () => string[];
|
|
240
|
+
/**
|
|
241
|
+
* 选中元素的祖先 selector(由近及远或反序都行,只做集合判断)。
|
|
242
|
+
*
|
|
243
|
+
* `MOVE_ELEMENT` 的 target **只允许**取自这里。理由:agent 手上只有选中元素与它的
|
|
244
|
+
* 祖先链,兄弟元素的 selector 它没有 —— 让它自由填 target 就等于让它编一个,
|
|
245
|
+
* 而移动到一个编出来的位置**没有任何报错**,用户只会看到元素跑到了奇怪的地方。
|
|
246
|
+
*
|
|
247
|
+
* 「移到这个 section 的开头 / 移到这个 div 之前」用祖先 + mode 就能表达,够用。
|
|
248
|
+
*/
|
|
249
|
+
ancestors: string[];
|
|
250
|
+
/**
|
|
251
|
+
* 货架里某一项的祖先链(由近及远,含作用域根自己)。**整页作用域专用**。
|
|
252
|
+
*
|
|
253
|
+
* 元素作用域不传:那时 `ancestors` 就是选中元素的祖先链,而作用域里的后代都在它
|
|
254
|
+
* 底下,同一条链够用。整页作用域不一样 —— 根是 `body`,它的 `ancestors` 是空数组,
|
|
255
|
+
* 拿它去判 `MOVE_ELEMENT` 的 target 会把**所有**移动判成非法(body 没有祖先)。
|
|
256
|
+
* 这个函数让那道闸改为对着「被移动的那个元素」的祖先链判,规则本身没变。
|
|
257
|
+
*
|
|
258
|
+
* 返回 `undefined`(不认识这个 selector)时退回 `ancestors` —— 与今天完全一致。
|
|
259
|
+
*/
|
|
260
|
+
ancestorsOf?: (selector: string) => string[] | undefined;
|
|
261
|
+
/**
|
|
262
|
+
* 发消息那一刻交给 agent 的那份作用域(见 `AiScopeGrant`)。
|
|
263
|
+
*
|
|
264
|
+
* 与上面这份是**并集**,不是替代:实时选中还在时它一条都不多放;选中在这一轮里
|
|
265
|
+
* 丢了(或换了)时,它是唯一还记得「我们当时授权了什么」的东西。
|
|
266
|
+
*/
|
|
267
|
+
grant?: AiScopeGrant;
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* 问 `selector` 在客户页上命中几个(跨域,必须走 agent 命令)。
|
|
271
|
+
*
|
|
272
|
+
* `viewportRect` 可选:给了矩形就表示宿主**能量几何**,落地后会跑一次几何自检
|
|
273
|
+
* (`postApplyCheck`)——改前的矩形就是这次探活顺带拿到的那份。不给 / null = 不检查。
|
|
274
|
+
*/
|
|
275
|
+
resolve: (selector: string) => Promise<{
|
|
276
|
+
matched: boolean;
|
|
277
|
+
matchCount: number;
|
|
278
|
+
viewportRect?: ViewportRect | null;
|
|
279
|
+
}>;
|
|
280
|
+
/**
|
|
281
|
+
* 这条 changeId 插入了哪些新元素(扩展 `applyChange` 回报的 `insertedSelectors`,
|
|
282
|
+
* 改动清单记在内存里)。几何自检要量它们;宿主也要把它们并进授权范围,模型下一轮才改得动。
|
|
283
|
+
*/
|
|
284
|
+
insertedSelectorsOf?: (changeId: string) => string[];
|
|
285
|
+
/** 落地后、量之前等一会(transition / 图片加载)。不给 = 不等。 */
|
|
286
|
+
settle?: () => Promise<void>;
|
|
287
|
+
/** 当前画布视口宽(判 OVERFLOW_X 用)。 */
|
|
288
|
+
viewportWidth?: () => number | undefined;
|
|
289
|
+
addStyle: (input: StyleChangeInput) => Promise<string>;
|
|
290
|
+
addContent: (input: ContentChangeInput) => Promise<string>;
|
|
291
|
+
addMove: (input: MoveChangeInput) => Promise<string>;
|
|
292
|
+
/** `CHANGE_IMAGE` 的 img-src 分支与 alt 用。 */
|
|
293
|
+
addAttribute: (input: AttributeChangeInput) => Promise<string>;
|
|
294
|
+
/** `SET_LINK` 用(`changeElementAction`)。 */
|
|
295
|
+
addAction: (input: ActionChangeInput) => Promise<string>;
|
|
296
|
+
/**
|
|
297
|
+
* 目标元素的能力位 —— `CHANGE_IMAGE` 要靠它分 img-src / background 两支,
|
|
298
|
+
* `SET_LINK` 要靠 `canEditLink` 判目标可不可点。
|
|
299
|
+
*
|
|
300
|
+
* ⚠️ **必须按 selector 现问**,不能复用选中态里那份:作用域允许改**货架里的后代**,
|
|
301
|
+
* 而后代的能力位与选中元素完全不同(选中的是 section,要换的图在里面的 `<img>` 上)。
|
|
302
|
+
* 拿选中元素的能力位去判分支,会对着一个 div 产出 `src` 属性 —— 属性确实设上了,
|
|
303
|
+
* div 不吃 src,表现是「AI 说换好了、图没变」。
|
|
304
|
+
*
|
|
305
|
+
* 省略 / 抛错 / 返回 null = 判不出目标类型,这两个 op 一律拒(不硬猜)。
|
|
306
|
+
*/
|
|
307
|
+
getCapabilities?: (selector: string) => Promise<ElementCapabilities | null>;
|
|
308
|
+
/**
|
|
309
|
+
* 允许出现在 `src` 里的 origin 白名单(宿主注入:图片上传域 + 客户页自身的 origin)。
|
|
310
|
+
*
|
|
311
|
+
* 白名单而不是「只要是 http(s) 就行」:模型完全可能凭记忆敲一个域名出来,
|
|
312
|
+
* 而那个 `src` 会被**每一个真实访客**加载 —— 等于我们替客户往他的页面上挂了一个
|
|
313
|
+
* 第三方请求(可跟踪、可换内容、可失效)。空数组 = 全拒(fail closed)。
|
|
314
|
+
*/
|
|
315
|
+
allowedImageOrigins: string[];
|
|
316
|
+
/**
|
|
317
|
+
* 本会话编辑器在这个页面上**读到过**的图片地址(完整 URL,整串相等才放行)。
|
|
318
|
+
* origin 白名单之外的第二条路:Shopify 这类站的图在 `cdn.shopify.com`,不在客户页 origin 下
|
|
319
|
+
* (见 `imageSource.ts`)。换图、整块重写、插入三处共用。缺省 = 这一路不放行。
|
|
320
|
+
*/
|
|
321
|
+
allowedImageUrls?: string[];
|
|
322
|
+
/**
|
|
323
|
+
* 用户在对话里**逐字给过**的跳转地址。同源之外只认这一张表,且是**整串逐字相等**
|
|
324
|
+
* (不是 origin 相等):外站地址是把客户的流量送走,得由用户自己说出来才算数。
|
|
325
|
+
*/
|
|
326
|
+
allowedLinkUrls: string[];
|
|
327
|
+
/** 客户页自身的 origin —— 同源跳转直接放行(站内链接是最常见的正当用法)。 */
|
|
328
|
+
pageOrigin: string;
|
|
329
|
+
}
|
|
330
|
+
export declare function applyAiChanges(changes: AiWireChange[], deps: AiApplyDeps): Promise<AiApplyOutcome>;
|