@zhin.js/adapter-sandbox 1.1.5 → 1.1.7

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 CHANGED
@@ -1,5 +1,33 @@
1
1
  # @zhin.js/adapter-process
2
2
 
3
+ ## 1.1.7
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5ab6307]
8
+ - @zhin.js/core@1.1.42
9
+
10
+ ## 1.1.6
11
+
12
+ ### Patch Changes
13
+
14
+ - badcc1f: Unify lazy JSX and HTML delivery across commands, inbound middleware and registered components. Remove the former JSX/template component runtimes, respect declared adapter HTML policies, and preserve author/generation ownership for automatic and explicit replies.
15
+
16
+ Add the optional @zhin.js/components library with composable JSXRenderable display props, shared themes, symmetric spacing and local style/text overrides. Include tables, lists, Markdown with highlighted code blocks, and display-only checkbox, radio, switch and button states; provide a reusable preview gallery. Update scaffolds, examples and public authoring documentation together.
17
+
18
+ Add optional official Tailwind static-utility compilation to inline styles. Consolidate raster rendering on @pixel.js/shotium, remove the Satori image toolkit, and align raster format contracts with actual PNG/JPEG/WebP results.
19
+
20
+ Reject cascade-dependent Tailwind values including unset, track the installed Tailwind version in the bundled theme provenance, and preserve both repository and upstream MIT attribution. Keep optional gallery dependency failures visible and document asynchronous Tailwind initialization.
21
+
22
+ - Updated dependencies [badcc1f]
23
+ - @zhin.js/core@1.1.41
24
+ - @zhin.js/feature-kit@1.1.3
25
+ - @zhin.js/adapter@1.1.17
26
+ - @zhin.js/page@1.1.4
27
+ - @zhin.js/skill@1.1.4
28
+ - @zhin.js/host-http@1.1.4
29
+ - @zhin.js/client@1.1.9
30
+
3
31
  ## 1.1.5
4
32
 
5
33
  ### Patch Changes
package/README.md CHANGED
@@ -44,6 +44,8 @@ Root 在 `zhin runtime start` 时装载 `@zhin.js/host-http`、`ConsoleRuntime`
44
44
 
45
45
  出站 wire 只做 JSON 封装;旧 `segment-mapper`(canonical segments)归一化上移到 gateway/core 渲染链。
46
46
 
47
+ Sandbox 声明 `html: direct`,聊天页在隔离 iframe 中展示 canonical `html`,因此 JSX 卡片无需截图引擎即可预览。允许内联样式和 data/blob 图片;组件脚本、事件属性、外部资源、表单提交和父页面访问均被限制。高度按内容调整,超过 1200px 可在框内滚动。
48
+
47
49
  ## 配置
48
50
 
49
51
  **推荐(与 [minimal-bot](../../../examples/minimal-bot/) 一致)**:`plugins.sandbox.endpoints: []`,运行时提供默认 `sandbox-bot` endpoint,无需额外账号配置。
@@ -12,6 +12,7 @@ export default defineAdapter({
12
12
  // Console UI 直连 URL 媒体、直接渲染 base64 内联媒体;path 由端点读盘
13
13
  // 物化为 base64 内联(sandbox 无平台上传通道)。交互段由 Console 原生承载。
14
14
  segments: {
15
+ html: 'direct',
15
16
  outboundMedia: ['url', 'base64', 'path'],
16
17
  interactive: 'native',
17
18
  },
@@ -17,6 +17,7 @@ export default defineAdapter<SandboxEndpointConfig>({
17
17
  // Console UI 直连 URL 媒体、直接渲染 base64 内联媒体;path 由端点读盘
18
18
  // 物化为 base64 内联(sandbox 无平台上传通道)。交互段由 Console 原生承载。
19
19
  segments: {
20
+ html: 'direct',
20
21
  outboundMedia: ['url', 'base64', 'path'],
21
22
  interactive: 'native',
22
23
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-sandbox",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Zhin.js Sandbox adapter for Plugin Runtime (WebSocket /sandbox)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -48,16 +48,16 @@
48
48
  "dependencies": {
49
49
  "lucide-react": "^0.525.0",
50
50
  "react": "^19.2.8",
51
- "@zhin.js/adapter": "1.1.16",
52
- "@zhin.js/client": "1.1.8",
51
+ "@zhin.js/adapter": "1.1.17",
52
+ "@zhin.js/client": "1.1.9",
53
53
  "@zhin.js/console-contract": "1.1.1",
54
- "@zhin.js/core": "1.1.40",
55
- "@zhin.js/feature-kit": "1.1.2",
56
- "@zhin.js/host-http": "1.1.3",
54
+ "@zhin.js/core": "1.1.42",
55
+ "@zhin.js/feature-kit": "1.1.3",
56
+ "@zhin.js/host-http": "1.1.4",
57
57
  "@zhin.js/im-contract": "1.1.3",
58
58
  "@zhin.js/logger": "1.1.1",
59
- "@zhin.js/page": "1.1.3",
60
- "@zhin.js/skill": "1.1.3"
59
+ "@zhin.js/page": "1.1.4",
60
+ "@zhin.js/skill": "1.1.4"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/react": "^19.2.18",
@@ -65,18 +65,18 @@
65
65
  "typescript": "^6.0.3",
66
66
  "vitest": "^4.1.10",
67
67
  "ws": "^8.21.1",
68
- "@zhin.js/pagemanager": "1.1.4",
69
- "@zhin.js/runtime": "1.1.4",
70
- "zhin.js": "1.1.5"
68
+ "@zhin.js/pagemanager": "1.1.5",
69
+ "@zhin.js/runtime": "1.1.5",
70
+ "zhin.js": "1.1.7"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "react": "^19.0.0",
74
- "@zhin.js/adapter": "^1.1.16",
74
+ "@zhin.js/adapter": "^1.1.17",
75
75
  "@zhin.js/console-contract": "^1.1.1",
76
- "@zhin.js/core": "^1.1.40",
77
- "@zhin.js/host-http": "^1.1.3",
78
- "@zhin.js/page": "^1.1.3",
79
- "zhin.js": "^1.1.5"
76
+ "@zhin.js/core": "^1.1.42",
77
+ "@zhin.js/host-http": "^1.1.4",
78
+ "@zhin.js/page": "^1.1.4",
79
+ "zhin.js": "^1.1.7"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "react": {
@@ -0,0 +1,33 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React, { useEffect, useRef, useState } from 'react';
4
+ /** HTML stays in an opaque-origin frame; only the size reporter can run scripts. */
5
+ export default function HtmlMessage({ html }) {
6
+ const frame = useRef(null);
7
+ const [nonce] = useState(createHtmlMessageNonce);
8
+ const [height, setHeight] = useState(240);
9
+ useEffect(() => {
10
+ const onSize = (event) => {
11
+ if (event.source !== frame.current?.contentWindow
12
+ || event.data?.type !== 'sandbox-html-size'
13
+ || event.data?.nonce !== nonce)
14
+ return;
15
+ const value = event.data.height;
16
+ if (typeof value === 'number' && Number.isFinite(value)) {
17
+ setHeight(Math.ceil(Math.min(1200, Math.max(32, value))));
18
+ }
19
+ };
20
+ window.addEventListener('message', onSize);
21
+ return () => window.removeEventListener('message', onSize);
22
+ }, [nonce]);
23
+ const srcDoc = createHtmlMessageDocument(html, nonce);
24
+ return _jsx("iframe", { ref: frame, title: "HTML \u6D88\u606F", sandbox: "allow-scripts", srcDoc: srcDoc, className: "block w-full min-w-0 border-0 rounded-lg my-1 bg-transparent", style: { height } });
25
+ }
26
+ /** getRandomValues is available on ordinary HTTP LAN pages as well as HTTPS. */
27
+ export function createHtmlMessageNonce() {
28
+ return Array.from(crypto.getRandomValues(new Uint8Array(16)), byte => byte.toString(16).padStart(2, '0')).join('');
29
+ }
30
+ /** The trusted reporter precedes raw markup so an unfinished tag cannot swallow it. */
31
+ export function createHtmlMessageDocument(html, nonce) {
32
+ return `<!doctype html><html><head><meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data: blob:; font-src data:; style-src 'unsafe-inline'; script-src 'nonce-${nonce}'; base-uri 'none'; form-action 'none'"><style>html,body{margin:0;padding:0;min-height:0}body{display:flow-root;overflow-wrap:anywhere}img{max-width:100%}</style></head><body><script nonce="${nonce}">const report=()=>parent.postMessage({type:'sandbox-html-size',nonce:'${nonce}',height:document.body.getBoundingClientRect().height},'*');new ResizeObserver(report).observe(document.body);report();<\/script>${html}</body></html>`;
33
+ }
@@ -0,0 +1,44 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+
3
+ /** HTML stays in an opaque-origin frame; only the size reporter can run scripts. */
4
+ export default function HtmlMessage({ html }: { readonly html: string }) {
5
+ const frame = useRef<HTMLIFrameElement>(null);
6
+ const [nonce] = useState(createHtmlMessageNonce);
7
+ const [height, setHeight] = useState(240);
8
+
9
+ useEffect(() => {
10
+ const onSize = (event: MessageEvent) => {
11
+ if (event.source !== frame.current?.contentWindow
12
+ || event.data?.type !== 'sandbox-html-size'
13
+ || event.data?.nonce !== nonce) return;
14
+ const value = event.data.height;
15
+ if (typeof value === 'number' && Number.isFinite(value)) {
16
+ setHeight(Math.ceil(Math.min(1200, Math.max(32, value))));
17
+ }
18
+ };
19
+ window.addEventListener('message', onSize);
20
+ return () => window.removeEventListener('message', onSize);
21
+ }, [nonce]);
22
+
23
+ const srcDoc = createHtmlMessageDocument(html, nonce);
24
+
25
+ return <iframe
26
+ ref={frame}
27
+ title="HTML 消息"
28
+ sandbox="allow-scripts"
29
+ srcDoc={srcDoc}
30
+ className="block w-full min-w-0 border-0 rounded-lg my-1 bg-transparent"
31
+ style={{ height }}
32
+ />;
33
+ }
34
+
35
+ /** getRandomValues is available on ordinary HTTP LAN pages as well as HTTPS. */
36
+ export function createHtmlMessageNonce(): string {
37
+ return Array.from(crypto.getRandomValues(new Uint8Array(16)),
38
+ byte => byte.toString(16).padStart(2, '0')).join('');
39
+ }
40
+
41
+ /** The trusted reporter precedes raw markup so an unfinished tag cannot swallow it. */
42
+ export function createHtmlMessageDocument(html: string, nonce: string): string {
43
+ return `<!doctype html><html><head><meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data: blob:; font-src data:; style-src 'unsafe-inline'; script-src 'nonce-${nonce}'; base-uri 'none'; form-action 'none'"><style>html,body{margin:0;padding:0;min-height:0}body{display:flow-root;overflow-wrap:anywhere}img{max-width:100%}</style></head><body><script nonce="${nonce}">const report=()=>parent.postMessage({type:'sandbox-html-size',nonce:'${nonce}',height:document.body.getBoundingClientRect().height},'*');new ResizeObserver(report).observe(document.body);report();<\/script>${html}</body></html>`;
44
+ }
@@ -5,6 +5,7 @@ import { cn, CodeBlock, MarkdownContent, resolveMediaSrc, pickMediaRawUrl, } fro
5
5
  import { buildSandboxWebSocketUrl } from './sandboxTransport';
6
6
  import { User, Bot, Users, Trash2, Send, Hash, MessageSquare, Wifi, WifiOff, Smile, Image, X, Check, Info, Search, Video, Music, Plus, PanelRight, ExternalLink, RefreshCw, Sparkles, Activity, Wrench, Coins, CircleAlert, Gauge, SlidersHorizontal, FolderOpen, ShieldCheck, Network, Square, RotateCcw, FileDiff, Terminal, FlaskConical, ChevronDown, FileDown, ListChecks, } from 'lucide-react';
7
7
  import RichTextEditor, {} from './RichTextEditor';
8
+ import HtmlMessage from './HtmlMessage.js';
8
9
  import { agentStudioPath, buildAgentRunReport, buildSandboxSessionKey, cancelAgentTask, deriveAgentRunSteps, deriveTaskRuns, deriveWorkbenchArtifacts, fetchAgentTrace, loadCachedAgentTrace, mergeTraceSnapshot, presentTraceEvent, summarizeTrace, saveCachedAgentTrace, } from './agentTrace.js';
9
10
  import { createDefaultPlaygroundState, loadPlaygroundState, savePlaygroundState, } from './playgroundState.js';
10
11
  export default function Sandbox() {
@@ -359,6 +360,8 @@ export default function Sandbox() {
359
360
  case 'markdown':
360
361
  case 'md':
361
362
  return _jsx(MarkdownContent, { text: String(d.text ?? d.content ?? ''), className: isSent ? 'zhin-markdown--inverse' : undefined }, index);
363
+ case 'html':
364
+ return _jsx(HtmlMessage, { html: String(d.html ?? '') }, index);
362
365
  case 'code':
363
366
  return _jsx(CodeBlock, { code: String(d.code ?? d.text ?? d.content ?? ''), language: String(d.language ?? d.lang ?? '') }, index);
364
367
  case 'mention':
@@ -18,6 +18,7 @@ import {
18
18
  FileDown, ListChecks,
19
19
  } from 'lucide-react';
20
20
  import RichTextEditor, { type RichTextEditorRef } from './RichTextEditor';
21
+ import HtmlMessage from './HtmlMessage.js';
21
22
  import {
22
23
  agentStudioPath,
23
24
  buildAgentRunReport,
@@ -409,6 +410,8 @@ export default function Sandbox() {
409
410
  case 'markdown':
410
411
  case 'md':
411
412
  return <MarkdownContent key={index} text={String(d.text ?? d.content ?? '')} className={isSent ? 'zhin-markdown--inverse' : undefined} />
413
+ case 'html':
414
+ return <HtmlMessage key={index} html={String(d.html ?? '')} />
412
415
  case 'code':
413
416
  return <CodeBlock key={index} code={String(d.code ?? d.text ?? d.content ?? '')} language={String(d.language ?? d.lang ?? '')} />
414
417
  case 'mention':