@realsee/vr-cli 0.1.3 → 0.1.4
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/NOTICE.md +1 -1
- package/README.md +3 -3
- package/dist/cli.mjs +1 -1
- package/package.json +1 -1
package/NOTICE.md
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
|
|
5
5
|
Use of Realsee SDK packages, Open Platform services, brands, customer data, and generated integrations remains subject to the applicable agreements, account permissions, and data authorization. Public availability of this CLI does not grant additional rights to those SDKs, services, or resources.
|
|
6
6
|
|
|
7
|
-
The CLI package is licensed under `SEE LICENSE IN TERMS.txt`; review [TERMS.txt](
|
|
7
|
+
The CLI package is licensed under `SEE LICENSE IN TERMS.txt`; review [TERMS.txt](https://unpkg.com/@realsee/vr-cli@latest/TERMS.txt) before use, modification, redistribution, or deployment.
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ CI 和自动化生成流程应使用明确版本。当前版本示例:
|
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
43
|
npm exec --yes \
|
|
44
|
-
--package=@realsee/vr-cli@0.1.
|
|
44
|
+
--package=@realsee/vr-cli@0.1.4 \
|
|
45
45
|
-- vr-cli create ./my-vrapp --no-install
|
|
46
46
|
|
|
47
47
|
cd ./my-vrapp
|
|
@@ -207,10 +207,10 @@ nvm use
|
|
|
207
207
|
|
|
208
208
|
- npm 包:`@realsee/vr-cli`。
|
|
209
209
|
- 可执行命令:`vr-cli`。
|
|
210
|
-
- 当前版本:`0.1.
|
|
210
|
+
- 当前版本:`0.1.4`。
|
|
211
211
|
|
|
212
212
|
`0.x` 版本可能调整模板、检查规则和生成内容。生产环境与 CI 应固定 CLI 版本,并在升级时审查生成差异。
|
|
213
213
|
|
|
214
214
|
## 许可证
|
|
215
215
|
|
|
216
|
-
本包的许可证声明为 `SEE LICENSE IN TERMS.txt`,完整条款见 [TERMS.txt](
|
|
216
|
+
本包的许可证声明为 `SEE LICENSE IN TERMS.txt`,完整条款见 [TERMS.txt](https://unpkg.com/@realsee/vr-cli@latest/TERMS.txt)。Realsee SDK、开放平台服务、品牌、客户数据及第三方资源的使用应符合相应协议与授权范围。
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{parseArgs as Mr}from"node:util";var Y="@realsee/vr-cli";var F="https://registry.npmjs.org/",N="public";var j="0.1.
|
|
1
|
+
import{parseArgs as Mr}from"node:util";var Y="@realsee/vr-cli";var F="https://registry.npmjs.org/",N="public";var j="0.1.4",O=["portable","all","none"],B="22.23.2",C="22.18.0",te=`>=${C}`,D="11.19.0",ae=">=11.19.0",se=`npm@${D}`,G=Object.freeze({"@fastify/static":"10.1.3","@realsee/dnalogel":"3.81.2","@realsee/five":"6.8.9","@realsee/vapor":"0.2.12",fastify:"5.12.1",react:"18.3.1","react-dom":"18.3.1",three:"0.117.1"}),V=Object.freeze({three:G.three}),oe=(r,t)=>r in V?t:`>=${t}`,H=r=>{if(typeof r!="string")return null;let t=/^>=(\d+\.\d+\.\d+(?:[-+][\w.]+)?)$/.exec(r.trim());return t?t[1]:null},P=(r,t)=>{let e=i=>{if(typeof i!="string")return null;let o=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(i.trim());return o?{core:o.slice(1,4).map(Number),prerelease:o[4]??null}:null},a=e(r),n=e(t);if(!a||!n)return!1;for(let i=0;i<3;i+=1){let o=a.core[i]-n.core[i];if(o>0)return!0;if(o<0)return!1}return a.prerelease===n.prerelease||a.prerelease===null?!0:n.prerelease===null?!1:a.prerelease.localeCompare(n.prerelease,"en",{numeric:!0})>=0},q=Object.freeze({"@eslint/js":"10.0.1","@types/node":"24.13.3","@types/react":"18.3.12","@types/react-dom":"18.3.1","@vitejs/plugin-react":"4.3.1",concurrently:"10.0.5",eslint:"10.9.1","eslint-plugin-react-hooks":"7.1.1",globals:"17.11.0",prettier:"3.9.6",typescript:"5.9.3","typescript-eslint":"8.68.0",vite:"5.4.14"}),ie=Object.freeze(["APP_ID","REALSEE_GATEWAY_ENDPOINT","REALSEE_GATEWAY_APP_KEY","REALSEE_GATEWAY_APP_SECRET","REALSEE_SOURCE"]),ne=Object.freeze(["REALSEE_GATEWAY_APP_KEY","REALSEE_GATEWAY_APP_SECRET"]),le=Object.freeze(["REALSEE_GATEWAY_APP_SECRET"]),ce=Object.freeze(["package.json","package-lock.json","README.md","index.html","tsconfig.json","tsconfig.server.json","vite.config.ts",".editorconfig",".nvmrc",".node-version",".npmrc",".prettierignore","eslint.config.mjs","prettier.config.mjs","server/types.ts","server/config.ts","server/check-config.ts","server/realsee-open-api.ts","server/work-service.ts","server/work-route.ts","server/app.ts","server/index.ts","shared/model-floorplan.ts","src/main.tsx","src/app/App.tsx","src/shared/useElementSize.ts","src/vr/five/api.ts","src/vr/five/fiveConfig.ts","src/vr/five/SpatialRuntimeProvider.tsx","src/vr/five/initialState.ts","src/vr/plugins/dnalogel.ts","src/vr/plugins/SpatialPluginRegistry.ts","src/vr/plugins/examples/FeatureOwnedMeshPlugin.ts","src/vr/work/WorkSource.ts","src/features/floorplan/ModelFloorplanFeature.ts","src/features/navigation/ModeSwitcher.tsx","src/features/tags/PanoTagFeature.ts","src/ui/ViewerOverlay.tsx","src/styles.css",".env.example",".gitignore",".vr-cli.json"]);import{spawn as er}from"node:child_process";import{rename as be,writeFile as rr}from"node:fs/promises";import A from"node:path";import{fileURLToPath as tr}from"node:url";import _ from"node:path";import{mkdir as qe,readFile as Ze,writeFile as me}from"node:fs/promises";import{mkdir as ue,readFile as Be,readdir as Z,stat as fe,writeFile as pe}from"node:fs/promises";import L from"node:path";var He=new Set(["",".css",".html",".json",".md",".mjs",".ts",".tsx",".txt",".yml",".yaml"]);function Q(r,t){return Object.entries(t).reduce((e,[a,n])=>e.replaceAll(`{{${a}}}`,String(n)).replaceAll(`__${a}__`,String(n)),r)}async function u(r){try{return await fe(r),!0}catch(t){if(t?.code==="ENOENT")return!1;throw t}}async function de(r){if(!await u(r)){await ue(r,{recursive:!0});return}if(!(await fe(r)).isDirectory())throw new Error(`\u76EE\u6807\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\uFF1A${r}`);if((await Z(r)).length)throw new Error(`\u76EE\u6807\u76EE\u5F55\u5FC5\u987B\u4E3A\u7A7A\uFF1A${r}`)}async function T(r,t,e={}){if(!await u(r))throw new Error(`\u6A21\u677F\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${r}`);await ue(t,{recursive:!0});for(let a of await Z(r,{withFileTypes:!0})){let n=L.join(r,a.name),i=L.join(t,a.name);if(a.isDirectory()){await T(n,i,e);continue}if(!a.isFile())continue;let o=L.extname(a.name),m=await Be(n);if(!He.has(o)){await pe(i,m);continue}await pe(i,Q(m.toString("utf8"),e))}}async function K(r,t=r){let e=[];for(let a of await Z(t,{withFileTypes:!0})){let n=L.join(t,a.name);a.isDirectory()?e.push(...await K(r,n)):a.isFile()&&e.push(L.relative(r,n).split(L.sep).join("/"))}return e.sort()}var ve=Object.freeze(["realsee-vr-app","realsee-image-resources","threejs-r117-five"]),Qe=Object.freeze(["realsee-vr-app/SKILL.md","realsee-vr-app/references/dnalogel-api-capabilities.md","realsee-vr-app/references/dnalogel-openapi-recipes.md","realsee-vr-app/references/continuous-improvement.md","realsee-vr-app/references/five-api-capabilities.md","realsee-vr-app/references/five-runtime.md","realsee-vr-app/references/official-docs.md","realsee-vr-app/references/plugin-lifecycle.md","realsee-vr-app/references/ui-and-validation.md","realsee-vr-app/references/vapor-dom-layer.md","realsee-vr-app/scripts/verify-project.mjs","realsee-image-resources/SKILL.md","realsee-image-resources/references/cors-and-three-textures.md","realsee-image-resources/references/data-wanxiang.md","realsee-image-resources/references/five-image-url-transform.md","realsee-image-resources/references/source-and-domain-policy.md","threejs-r117-five/SKILL.md","threejs-r117-five/references/five-ownership.md","threejs-r117-five/references/r117-capabilities.md","threejs-r117-five/references/r117-version-guards.md"]),X=r=>Qe.map(t=>_.posix.join(r,t)),ge=Object.freeze(["AGENTS.md",...X(".agents/skills")]),Xe=Object.freeze([".agents/README.md",...X(".claude/skills"),...X(".kiro/skills"),"CLAUDE.md",".cursor/rules/realsee-vr.mdc",".github/copilot-instructions.md",".kiro/steering/realsee-vr.md"]),he=Object.freeze([".agents",".claude/skills",".kiro/skills",".cursor/rules",".kiro/steering"]),we=Object.freeze(["AGENTS.md","CLAUDE.md",".github/copilot-instructions.md"]),Ee=Object.freeze([".claude/skills",".kiro/skills",".cursor/rules",".kiro/steering"]),Se=Object.freeze([".agents/README.md","CLAUDE.md",".github/copilot-instructions.md"]),Je=Object.freeze([...ge,...Xe]);function W(r){if(r==="none")return[];if(r==="portable")return[...ge];if(r==="all")return[...Je];throw new Error(`\u672A\u77E5 agent assets \u6A21\u5F0F\uFF1A${r}`)}async function ye({toolRoot:r,targetRoot:t,mode:e,tokens:a}){if(e==="none")return[];for(let i of ve)await T(_.join(r,"skills",i),_.join(t,".agents","skills",i),a);let n=await Ze(_.join(r,"agent-assets","AGENTS.md"),"utf8");if(await me(_.join(t,"AGENTS.md"),Q(n,a)),e!=="all")return W(e);for(let i of[".claude/skills",".kiro/skills"])for(let o of ve)await T(_.join(r,"skills",o),_.join(t,i,o),a);return await T(_.join(r,"agent-assets","adapters"),t,a),await qe(_.join(t,".agents"),{recursive:!0}),await me(_.join(t,".agents","README.md"),"# Agent assets\n\n`skills/realsee-vr-app`, `skills/realsee-image-resources` and `skills/threejs-r117-five` are the three canonical portable Skills. Vendor-specific copies are generated; edit the canonical copies and regenerate adapters.\n"),W(e)}var ar=!0,J=tr(new URL(ar?"..":"../..",import.meta.url)),sr=process.platform==="win32"?"npm.cmd":"npm";function or(r,t){let e=t||A.basename(r),a=e.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"");if(!a||!/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/.test(a))throw new Error(`\u65E0\u6CD5\u751F\u6210\u5408\u6CD5 npm \u5305\u540D\uFF1A${e}`);return a}function ir(r){return new Promise((t,e)=>{let a=er(sr,["ci"],{cwd:r,stdio:"inherit",shell:!1});a.once("error",e),a.once("exit",(n,i)=>{n===0?t():e(new Error(`npm ci \u5931\u8D25\uFF08code=${n??"null"}, signal=${i??"none"}\uFF09`))})})}async function ke({directory:r,preset:t,name:e,agentAssets:a="portable",install:n=!0}){if(!r)throw new Error("\u7F3A\u5C11\u76EE\u6807\u76EE\u5F55\u3002\u7528\u6CD5\uFF1Avr-cli create <directory>");if(t&&t!=="viewer")throw new Error("--preset \u6682\u65F6\u53EA\u652F\u6301 viewer\u3002");if(!O.includes(a))throw new Error(`\u672A\u77E5 agent assets \u6A21\u5F0F\uFF1A${a}\u3002\u53EF\u9009\u503C\uFF1A${O.join(", ")}`);let i=A.resolve(r),o=or(i,e),m={PACKAGE_NAME:o,TOOL_VERSION:j};await de(i),await T(A.join(J,"templates","base"),i,m),await be(A.join(i,".gitignore.template"),A.join(i,".gitignore")),await be(A.join(i,".npmrc.template"),A.join(i,".npmrc")),await T(A.join(J,"templates","viewer"),i,m);let f=await ye({toolRoot:J,targetRoot:i,mode:a,tokens:m}),p={schemaVersion:1,toolVersion:j,preset:"viewer",packageName:o,agentAssets:a,generatedAt:new Date().toISOString()};return await rr(A.join(i,".vr-cli.json"),`${JSON.stringify(p,null,2)}
|
|
2
2
|
`),n&&await ir(i),{targetRoot:i,packageName:o,installedAgentAssets:f,installed:n}}import{execFile as nr}from"node:child_process";import{readFile as E,readdir as lr,stat as cr}from"node:fs/promises";import l from"node:path";import{promisify as pr}from"node:util";var ur=pr(nr),s=(r,t,e,a)=>({level:r,code:t,message:e,...a?{detail:a}:{}}),_e=r=>/(?:^|_)(?:AK|SK|SECRET|TOKEN|PASSWORD|CREDENTIALS?)(?:_|$)/i.test(r),fr=Object.freeze([/\bAPP_ID\b/,/\bREALSEE_(?:GATEWAY_[A-Z0-9_]+|SOURCE|ACCESS_TOKEN)\b/,/\b(?:VITE_)?(?:AK|SK|ACCESS_TOKEN)\b/]),ee=r=>{for(let t of fr){let e=t.exec(r);if(e)return e[0]}return null},y=r=>r.replace(/\/\*[\s\S]*?\*\//g,"").replace(/(^|[^:])\/\/.*$/gm,"$1"),dr=Object.freeze([{pattern:/three\/addons\//,message:"r117 \u6269\u5C55\u6A21\u5757\u5FC5\u987B\u4ECE three/examples/jsm \u5BFC\u5165\u3002"},{pattern:/three\/tsl\b/,message:"Three r117 \u4E0D\u63D0\u4F9B\u73B0\u4EE3 TSL \u5165\u53E3\u3002"},{pattern:/\b(?:SRGBColorSpace|LinearSRGBColorSpace|NoColorSpace|CapsuleGeometry|WebGPURenderer)\b/,message:"\u6E90\u7801\u4F7F\u7528\u4E86 Three r117 \u4E0D\u5B58\u5728\u7684\u73B0\u4EE3\u7B26\u53F7\u3002"},{pattern:/\b(?:renderer|[\w$]*Renderer)\.outputColorSpace\b/,message:"Three r117 \u4F7F\u7528 renderer.outputEncoding\u3002"},{pattern:/\b(?:texture|[\w$]*(?:map|Map|texture|Texture))\.colorSpace\s*=/,message:"Three r117 \u7EB9\u7406\u4F7F\u7528 encoding\uFF0C\u800C\u4E0D\u662F colorSpace\u3002"}]),mr=Object.freeze(["from '@realsee/five'","from 'three'","FEATURE_OWNED_MESH_PLUGIN_NAME","example.featureOwnedMesh","new Group(","new BoxBufferGeometry(","new MeshBasicMaterial(","new Mesh(","five.scene.add(root)","root.parent?.remove(root)","five.needsRender = true","geometry.dispose()","material.dispose()","plugins.register(FEATURE_OWNED_MESH_PLUGIN_NAME, plugin)","plugin.dispose()"]),vr=Object.freeze(["new Five(","new WebGLRenderer(","renderer.render(","requestAnimationFrame(","five.dispose(","three/addons/"]),gr=Object.freeze(["Image resources use approved Realsee CDN domains only; never use `ljcdn.com`, `lianjia.com` or their subdomains.","Prefer Five `defaultImageURLTransform` over hand-built \u6570\u636E\u4E07\u8C61 query strings when its installed contract satisfies the request.","URL transformation does not grant CORS access.","Ordinary images use the deployment's approved image-4 host.","Feature media from OpenAPI or Work data is displayed through a derived sized variant, never the original: pass ordinary images through the reviewed `defaultImageURLTransform` adapter with a bounded `size`, and do not hand a full-resolution URL to a tag, tour, card or DOM thumbnail."]),hr=Object.freeze(["When the user explicitly requests Vapor components, use matching named exports from the installed `@realsee/vapor` package for every applicable DOM control; importing `Vapor` or `vapor.css` alone does not satisfy the request.","Do not replace an available Vapor component with raw HTML or a locally styled replica; use raw DOM only for semantics or capabilities absent from the installed Vapor declarations, and record that gap.","Before implementing Vapor UI, read `node_modules/@realsee/vapor/AI_CONTEXT.md`, `llms.txt`, `vapor.d.ts`, and the selected component declarations; never invent component names or props.","Use the installed `ai_guides` only for component discovery and composition recipes; the target project's root `vapor.d.ts` and selected component declarations are the API contract, and conflicts resolve in favor of installed declarations.","Keep the Five canvas in its dedicated sibling host outside `Vapor`; Vapor layout components own DOM chrome only, even when an external recipe nests a placeholder VR component inside a stack."]),wr=Object.freeze(["The current generated baseline is `@realsee/vapor@0.2.12`.","The 0.2.12 baseline requires exactly one executable `@realsee/vapor/vapor.css` import, not `vapor.scss`","Choose by product semantics before styling:","`HStack` arranges DOM horizontally, `VStack` vertically and `ZStack` overlays DOM children.","The 0.2.12 match union is exact:","if both represent the same physical inset, de-duplicate rather than adding it twice."]),Er=Object.freeze(["For an explicit Vapor request, executable source must import and render the matching non-provider Vapor component; the provider and stylesheet alone are insufficient.","exactly one executable `@realsee/vapor/vapor.css` import and no `vapor.scss` or copied internal stylesheet;","the `Vapor` provider rectangle matches the DOM overlay host","safe-area behavior uses the declared source/merge rule without double-counting","correct portal order, focus entry/return, Escape/backdrop behavior and close reasons;","no application stylesheet overrides `.vapor-*` internals","typecheck validates every component prop, compound child and symbol"]),Sr=/\bimport\s*['"]@realsee\/vapor\/vapor\.css['"]\s*;?/,Ae=r=>r.match(new RegExp(Sr.source,"g"))?.length??0,z=(r,t)=>new RegExp(`\\bimport\\s*\\{[^}]*\\b${t}\\b[^}]*\\}\\s*from\\s*['"]@realsee/vapor['"]`).test(r),U=(r,t)=>new RegExp(`<${t}(?:\\s|/?>)`).test(r),yr=Object.freeze(["Spatial capability resolution order: installed @realsee/dnalogel preset -> native Five -> Three.js.","Tags, hotspots, and anchors default to PanoTagPlugin with GET /open/v3/hot/list.","Normalize optional OpenAPI configuration fields such as `version`, `globalConfig` and `contentTypeConfig`: treat `null` as absent before validating the installed SDK contract.","Load ordinary PanoTag point/plane tags after `five.load` without waiting for `five.model.loaded`; gate only model-dependent tag content or anchors on model readiness.","Tours use Five State snapshots with GET /open/v3/observerpicture/search.","Model annotations default to ModelMakerPlugin with GET /open/v3/annotation/search.","Routes use GuideLinePlugin for rendering and shape-selected CruisePlugin or MovePlugin playback with GET /open/v3/route/search.","Tour adapters read `data.list`, map each validated record to `Partial<State>` with the active `workCode`, and never cast an observer-picture record directly to `State`.","Model annotation adapters read `data.list`, validate `object_data` for `box`, `triangles` or `prism`, and pass `{ list }` to ModelMaker only for a model-capable Work.","Feature API, schema, or plugin failures disable only the affected feature; keep the base Viewer usable and never runtime-fallback to raw data or a custom Three implementation.","Scope tour, ModelMaker, GuideLine, Cruise and Move work to an active `workCode`/generation token; abort fetches, ignore stale continuations, pause the owned playback controller, remove hooks, clear GuideLine data, wait for pending loads, then let identity-safe unregister dispose each registered controller exactly once before `five.dispose()`.","SDK-shaped custom data requires an explicit developer opt-out from Open Platform data.","VR spatial tag (spatial annotation) is the umbrella concept","Classify content, renderer, anchor, and lifecycle/data ownership","Never infer PanoTag from","Never directly edit `work.json`, downloaded Work, or customer Work"]),R=Object.freeze(["dnalogel 3.81.2 route playback is shape-selected: a validated pano group uses `CruisePlugin` `{ panoIndexList }`, while a validated model-space curve uses `MovePlugin` `{ path }`; `GuideLinePlugin` renders route geometry and is not playback input.","`CruisePlugin` accepts exactly one of `panoIndexList` or `keyframes`; its installed union has no type discriminator.","OpenAPI route records are never passed raw: rename validated style config only for GuideLine `lines`, and never pass GuideLine `PathItem` arrays or style objects to `CruisePlugin` or `MovePlugin`.","If a source record contains both `pano_group` and `path`, the route adapter must choose product semantics explicitly and pass only the selected geometry branch to GuideLine.","`GuideLinePlugin.load` waits for model readiness; `CruisePlugin` waits only for Work and observers; `MovePlugin` enters Model and awaits Five readiness when playback starts.","Reject empty routes, unknown pano indexes, unsupported curves, non-finite coordinates, timing or speed, and ambiguous multi-segment Move paths before plugin load.","Route cleanup pauses the owned playback controller before hook removal and disposal; `clear` belongs to GuideLine, is not a public Cruise operation, and GuideLine disposal does not own an external or embedded Cruise controller automatically.","Do not invent `RoutePlugin`, `PanoRove`, `stop()`, or a universal route controller; use only the exports and methods declared by the installed package."]),Oe=Object.freeze(["Floorplans default to ModelFloorplanPlugin with GET /open/v3/floorplan/plugins.","`data.format_floorplan_url`, not `format_model_url`, resolves to the preferred `{ version, data: FloorplanServerData }` plugin input.","Expose `capabilities.modelFloorplan` only after validating the complete wrapper and nested floorplan shape; missing, empty, malformed or failed floorplan data must leave the base Viewer usable.","The default tabs are `\u6F2B\u6E38` for `Panorama` and `\u4E09\u7EF4\u6A21\u578B` for `Mapview`; do not expose `Topview` as `\u5730\u56FE`.","Add the `\u5E73\u9762\u56FE` tab only after the capability validates and `ModelFloorplanPlugin.load` succeeds.","Configure `ModelFloorplanPlugin` with `autoShowEnable: false`; the application tab owns explicit `show()`/`hide()`, uses `modelOpacity: 0` while the floorplan is visible, and restores the Five model surface on hide, failure, and disposal.","Resolve the Five canvas parent and call `ModelFloorplanPlugin.appendTo(wrapper)` before `load`; `five.addExtraElement` registers input handling but does not mount the plugin DOM.","For multi-floor Work, ModelFloorplanPlugin and Five pano/model floor synchronization are the floor source of truth; do not invent a React-only `floorIndex`.","Floorplan show/hide, hooks, pending load and identity-safe disposal must finish before `five.dispose()`."]),br=Object.freeze(Oe.slice(0,3)),kr="The complete model floorplan contract lives in",_r="The complete route playback contract lives in",Ar=Object.freeze([R[0],R[7],_r]),Te=Object.freeze(["Vapor","Text","TitleBar","ZStack","VStack","Layer"]),Re=Object.freeze(["Button","Font","HStack","VStack"]),je=Object.freeze(["title?: string | null",'className="viewer-vapor"','width="100%"','height="100%"','theme="arc_beauty"',"useSaveAreaInsets()","useDimension()","<Layer vignetting />","labelMaxWidth={titleMaxWidth}",'className="viewer-controls"',"align={{ horizontal: 'center' }}",'className="viewer-status"','appearance="solid"',"role={error ? 'alert' : 'status'}","aria-live={error ? 'assertive' : 'polite'}","env(safe-area-inset-${side}, 0px)"]),Pe=Object.freeze(['role="group"',"useDimension()","width={controlWidth}","height={compact ? '3rem' : '5rem'}","align={{ horizontal: 'space-around' }}",'appearance="shadow"',"weight={selected ? 'bold' : 'regular'}","opacity={selected ? '100' : '80'}",'className="mode-switcher-indicator"',"onClick={() => void changeTab(option.value)}"]),Le=Object.freeze([".dom-overlay",".viewer-controls",".mode-switcher","pointer-events: auto",".mode-switcher-indicator","bottom: -0.5rem","width: 3.375rem","height: 0.125rem","background-image: linear-gradient(",".viewer-status"]),Ne=Object.freeze(["viewer-glass",'className="viewer-topbar"',"<h1"]),xe=Object.freeze(["Segmented","viewer-segmented","viewer-glass",'appearance="horizontal"','maxWidth="100%"']),Me=Object.freeze(["--viewer-glass-","--viewer-control-size",".vapor-segmented","backdrop-filter"]);async function re(r){return JSON.parse(await E(r,"utf8"))}async function Or(){let r=process.platform==="win32"?"npm.cmd":"npm",{stdout:t}=await ur(r,["--version"],{encoding:"utf8"});return t.trim()}async function $e(r,t){let e=[];for(let[n,i,o]of[["packageManager",t.packageManager,se],["engines.node",t.engines?.node,te],["engines.npm",t.engines?.npm,ae]])i!==o&&e.push(s("error","toolchain.version",`package.json ${n} \u5FC5\u987B\u4E3A ${o}\uFF0C\u5F53\u524D\u4E3A ${i??"\u672A\u58F0\u660E"}`));for(let n of[".nvmrc",".node-version"]){let i=l.join(r,n);if(await u(i)){let o=(await E(i,"utf8")).trim();o!==B&&e.push(s("error","toolchain.node-pin",`${n} \u5FC5\u987B\u56FA\u5B9A Node ${B}\uFF0C\u5F53\u524D\u4E3A ${o||"\u7A7A"}`))}}let a=l.join(r,".npmrc");if(await u(a)){let n=new Set((await E(a,"utf8")).split(/\r?\n/).map(i=>i.trim()).filter(Boolean));for(let i of["engine-strict=true","package-lock=true","save-prefix=>="])n.has(i)||e.push(s("error","toolchain.npmrc",`.npmrc \u5FC5\u987B\u5305\u542B ${i}`))}return e}async function Tr(r,t){let e=l.join(r,"package-lock.json");if(!await u(e))return[];try{let a=await re(e),n=a.packages?.[""],i=[];if(a.lockfileVersion!==3||!n)return[s("error","lockfile.invalid","package-lock.json \u5FC5\u987B\u4F7F\u7528 lockfileVersion 3 \u5E76\u5305\u542B\u6839\u5305\u8BB0\u5F55\u3002")];(a.name!==t.name||n.name!==t.name||n.version!==t.version)&&i.push(s("error","lockfile.package","package-lock.json \u6839\u5305\u540D\u79F0\u6216\u7248\u672C\u4E0E package.json \u4E0D\u4E00\u81F4\u3002"));for(let[o,m,f,p]of[["dependency",n.dependencies,t.dependencies,G],["dev-dependency",n.devDependencies,t.devDependencies,q]])for(let[w,b]of Object.entries(f??{})){m?.[w]!==b&&i.push(s("error",`lockfile.${o}`,`package-lock.json \u4E0E package.json \u4E0D\u4E00\u81F4\uFF1A${w}@${b}\uFF1B\u8BF7\u8FD0\u884C npm run deps:relock\u3002`));let k=p[w];if(!k)continue;let c=a.packages?.[`node_modules/${w}`]?.version;if(!c){i.push(s("error","lockfile.resolved",`package-lock.json \u7F3A\u5C11\u76F4\u63A5\u4F9D\u8D56 ${w} \u7684\u89E3\u6790\u7248\u672C\u3002`));continue}if(w in V){c!==k&&i.push(s("error","lockfile.locked",`package-lock.json \u5FC5\u987B\u5C06 ${w} \u89E3\u6790\u4E3A ${k}\uFF0C\u5F53\u524D\u4E3A ${c}\u3002`));continue}let d=H(b);d&&(!P(c,k)||!P(c,d))&&i.push(s("error","lockfile.minimum",`${w} \u5728 package-lock.json \u4E2D\u89E3\u6790\u4E3A ${c}\uFF0C\u5FC5\u987B\u540C\u65F6\u6EE1\u8DB3\u751F\u6210\u5668\u57FA\u7EBF >=${k} \u4E0E\u58F0\u660E ${b}\u3002`))}return i}catch(a){return[s("error","lockfile.invalid","package-lock.json \u65E0\u6CD5\u89E3\u6790\u3002",String(a))]}}async function x(r){let t=[];for(let e of await lr(r,{withFileTypes:!0})){let a=l.join(r,e.name);e.isDirectory()?t.push(...await x(a)):e.isFile()&&/\.(?:[cm]?[jt]sx?)$/.test(e.name)&&t.push(a)}return t}async function Fe(r,t){let e=l.join(r,t);if(!await u(e))return[];let a=y(await E(e,"utf8")),n=[];for(let m of mr)a.includes(m)||n.push(s("error","architecture.custom-plugin-example",`${t} \u7F3A\u5C11\u81EA\u5B9A\u4E49\u63D2\u4EF6\u6240\u6709\u6743\u6807\u8BB0\uFF1A${m}`));for(let m of vr)a.includes(m)&&n.push(s("error","architecture.custom-plugin-example",`${t} \u7981\u6B62\u62E5\u6709 Five \u8FD0\u884C\u65F6\u6216\u7B2C\u4E8C\u6E32\u67D3\u5FAA\u73AF\uFF1A${m}`));let i=t.startsWith("templates/")?"templates/viewer/src/features/tags/PanoTagFeature.ts":"src/features/tags/PanoTagFeature.ts",o=l.join(r,i);if(await u(o)){let m=y(await E(o,"utf8"));for(let f of["from '@realsee/dnalogel/libs/PanoTagPlugin'","const PLUGIN_NAME = 'dnalogel.panoTag'","const candidate = PanoTagPlugin(","plugins.register(PLUGIN_NAME, candidate)","candidate.dispose()","async load(panoTagList: Tags['tagList'])","plugin.load({ tagList: panoTagList })","const disposeError = plugins.unregister(PLUGIN_NAME, plugin)"])m.includes(f)||n.push(s("error","architecture.pano-tag-contract",`${i} \u7F3A\u5C11 PanoTag \u517C\u5BB9\u6027\u3001\u663E\u5F0F\u7C7B\u578B\u6216\u6240\u6709\u6743\u6807\u8BB0\uFF1A${f}`));for(let f of["model_file","as Tags['tagList']","from '../../vr/work/WorkSource'"])m.includes(f)&&n.push(s("error","architecture.pano-tag-contract",`${i} \u542B\u975E\u6807\u51C6 content type \u6216\u672A\u9A8C\u8BC1\u7684 PanoTag \u8F6C\u6362\uFF1A${f}`))}return n}async function Ie(r,t){let e=[];for(let a of t){let n=l.join(r,a);if(!await u(n))continue;let i=await E(n,"utf8");for(let o of gr)i.includes(o)||e.push(s("error","agents.image-resource-guidance",`${a} \u7F3A\u5C11\u56FE\u7247\u8D44\u6E90\u57DF\u540D\u3001Five URL transform\u3001\u6570\u636E\u4E07\u8C61\u6216 CORS \u89C4\u5219\uFF1A${o}`))}return e}async function Ce(r,t){let e=[];for(let a of t){let n=l.join(r,a);if(!await u(n))continue;let i=await E(n,"utf8");for(let o of hr)i.includes(o)||e.push(s("error","agents.vapor-guidance",`${a} \u7F3A\u5C11 Vapor \u771F\u5B9E\u7EC4\u4EF6\u9009\u62E9\u3001\u58F0\u660E\u6838\u5BF9\u6216 raw DOM \u4F8B\u5916\u89C4\u5219\uFF1A${o}`))}return e}async function De(r,t,e){let a=[];for(let[n,i,o,m]of[[t,wr,"agents.vapor-reference","\u7248\u672C\u5316\u8D44\u6599\u8DEF\u7531\u3001\u7EC4\u4EF6\u9009\u578B\u3001\u5E03\u5C40\u6216 safe-area \u89C4\u5219"],[e,Er,"agents.vapor-acceptance","\u8FD0\u884C\u65F6 Vapor \u9A8C\u6536\u89C4\u5219"]]){let f=l.join(r,n);if(!await u(f))continue;let p=await E(f,"utf8");for(let w of i)p.includes(w)||a.push(s("error",o,`${n} \u7F3A\u5C11 ${m}\uFF1A${w}`))}return a}async function Ge(r,t,e){let a=[];for(let i of t){let o=l.join(r,i);if(!await u(o))continue;let m=await E(o,"utf8");for(let f of yr)m.includes(f)||a.push(s("error","agents.spatial-tag-guidance",`${i} \u7F3A\u5C11\u7A7A\u95F4\u6807\u7B7E\u51B3\u7B56\u6216\u53EA\u8BFB\u89C4\u5219\uFF1A${f}`))}let n=l.join(r,e);if(await u(n)){let i=await E(n,"utf8");for(let o of["Spatial capability resolution order: installed @realsee/dnalogel preset -> native Five -> Three.js.","Tags, hotspots, and anchors default to PanoTagPlugin with GET /open/v3/hot/list.","Normalize optional OpenAPI configuration fields such as `version`, `globalConfig` and `contentTypeConfig`: treat `null` as absent before validating the installed SDK contract.","Load ordinary PanoTag point/plane tags after `five.load` without waiting for `five.model.loaded`; gate only model-dependent tag content or anchors on model readiness.","Tours use Five State snapshots with GET /open/v3/observerpicture/search.","Model annotations default to ModelMakerPlugin with GET /open/v3/annotation/search.","Routes use GuideLinePlugin for rendering and shape-selected CruisePlugin or MovePlugin playback with GET /open/v3/route/search.","Tour adapters read `data.list`, map each validated record to `Partial<State>` with the active `workCode`, and never cast an observer-picture record directly to `State`.","Model annotation adapters read `data.list`, validate `object_data` for `box`, `triangles` or `prism`, and pass `{ list }` to ModelMaker only for a model-capable Work.","Feature API, schema, or plugin failures disable only the affected feature; keep the base Viewer usable and never runtime-fallback to raw data or a custom Three implementation.","Scope tour, ModelMaker, GuideLine, Cruise and Move work to an active `workCode`/generation token; abort fetches, ignore stale continuations, pause the owned playback controller, remove hooks, clear GuideLine data, wait for pending loads, then let identity-safe unregister dispose each registered controller exactly once before `five.dispose()`.","SDK-shaped custom data requires an explicit developer opt-out from Open Platform data.","`model_file` is not canonical","`ModelTVVideoPlugin`","`CSS3DRenderPlugin.create3DDomContainer`","`PanoVideoPlugin`","generic `tags`, `tagList` and `tag_list`","`ServerData` with `box`, `triangles` or `prism` items"])i.includes(o)||a.push(s("error","agents.spatial-tag-capabilities",`${e} \u7F3A\u5C11\u7A7A\u95F4\u80FD\u529B\u4F18\u5148\u7EA7\u3001\u6570\u636E\u6E90\u6216\u63D2\u4EF6\u7C7B\u578B\u8DEF\u7531\uFF1A${o}`))}return a}async function Ve(r,t,e){let a=[],n=[...t.map(i=>[i,i.endsWith("SKILL.md")?Ar:R]),[`${e}/references/dnalogel-api-capabilities.md`,R],[`${e}/references/five-runtime.md`,R.slice(4,6)],[`${e}/references/plugin-lifecycle.md`,R.slice(6,8)],[`${e}/references/official-docs.md`,R.slice(2,4)]];for(let[i,o]of n){let m=l.join(r,i);if(!await u(m))continue;let f=await E(m,"utf8");for(let p of o)f.includes(p)||a.push(s("error","agents.route-guidance",`${i} \u7F3A\u5C11\u70B9\u4F4D/\u81EA\u5B9A\u4E49\u8DEF\u7EBF\u5206\u6D41\u3001\u6821\u9A8C\u6216\u751F\u547D\u5468\u671F\u89C4\u5219\uFF1A${p}`))}return a}async function Ke(r,t,e){let a=[],n=[[`${e}/references/dnalogel-api-capabilities.md`,Oe],...t.map(i=>[i,br]),...["five-runtime.md","official-docs.md","plugin-lifecycle.md","ui-and-validation.md"].map(i=>[`${e}/references/${i}`,[kr]])];for(let[i,o]of n){let m=l.join(r,i);if(!await u(m))continue;let f=await E(m,"utf8");for(let p of o)f.includes(p)||a.push(s("error","agents.floorplan-guidance",`${i} \u7F3A\u5C11\u5E73\u9762\u56FE endpoint\u3001\u6821\u9A8C\u3001\u52A8\u6001 tab\u3001\u591A\u697C\u5C42\u6216\u6E05\u7406\u89C4\u5219\uFF1A${p}`))}return a}async function We(r,t){let e=[],a=[[t.validator,["export function asModelFloorplanServerData(","!isInteger(value.version)","value.version < 0","!isFloorplanServerData(value.data)","value.outlines.length > 0","value.floor_datas.length > 0","isArrayOf(value.rooms, isRoom)","isRules(value.rules)","value.entrance === null || isEntrance(value.entrance)","isBounding(value.bounding)","isArrayOf(value.observers, isObserver)","isArrayOf(value.doors, isDoor)"]],[t.types,["WorkCapabilities","modelFloorplan?: ModelFloorplanServerData","ModelFloorplanClient","RealseeSpatialClient","extends WorkDetailClient, ModelFloorplanClient"]],[t.client,["implements RealseeSpatialClient","FLOORPLAN_PLUGINS_PATH = '/open/v3/floorplan/plugins'","asRecord(descriptor.data).format_floorplan_url","floorplanUrl.protocol !== 'https:'","floorplanUrl.username","floorplanUrl.password","redirect: 'error'","asModelFloorplanServerData(payload)"]],[t.service,[".getModelFloorplan(resourceCode, { signal })",".catch((error: unknown) =>","modelFloorplan ? { capabilities: { modelFloorplan } } : {}"]],[t.workSource,["modelFloorplan?: ModelFloorplanServerData","asModelFloorplanServerData(","asRecord(envelope.capabilities).modelFloorplan","modelFloorplan ? { capabilities: { modelFloorplan } } : {}"]],[t.feature,["@realsee/dnalogel/libs/floorplan/ModelFloorplanPlugin","dnalogel.modelFloorplan","ModelFloorplanPlugin(five, { autoShowEnable: false })","plugins.register(PLUGIN_NAME, candidate)","candidate.dispose()","const modelSurface = five.getElement()","const wrapper = modelSurface?.parentElement","plugin.appendTo(wrapper)","plugin.load(serverData)","modelOpacity: 0","plugin.hide({ userAction: true })",".finally(restoreModelSurface)","if (!state.visible) restoreModelSurface()","plugins.unregister(PLUGIN_NAME, plugin)","stopStateChange()","if (disposeRequested) finalize()","if (!loading) finalize()"]],[t.app,["payload.capabilities?.modelFloorplan","if (modelFloorplan)","createModelFloorplanFeature(five, plugins)","await currentFloorplan.load(modelFloorplan)","currentFloorplan.dispose()","setFloorplanFeature(floorplan)","floorplan?.dispose()"]],[t.modeSwitcher,["floorplan?.subscribeVisibility","await floorplan.show()","if (floorplan?.visible) await floorplan.hide()","floorplan?.visible ? 'floorplan' : tabFromFiveMode(five.currentMode)","Five.Mode.Panorama","Five.Mode.Mapview"]]];for(let[o,m]of a){let f=l.join(r,o);if(!await u(f)){e.push(s("error","architecture.floorplan-missing",`\u7F3A\u5C11\u5E73\u9762\u56FE\u5408\u540C\u6587\u4EF6\uFF1A${o}`));continue}let p=y(await E(f,"utf8"));for(let w of m)p.includes(w)||e.push(s("error","architecture.floorplan-contract",`${o} \u7F3A\u5C11\u5E73\u9762\u56FE\u6821\u9A8C\u3001capability \u6216\u751F\u547D\u5468\u671F\u6807\u8BB0\uFF1A${w}`))}let n=l.join(r,t.feature);if(await u(n)){let o=y(await E(n,"utf8"));for(let[v,h]of[[/plugin\.hooks\.on\(\s*['"]show['"]/,"show hook"],[/plugin\.hooks\.on\(\s*['"]hide['"]/,"hide hook"],[/plugin\.hooks\.on\(\s*['"]stateChange['"]/,"stateChange hook"]])v.test(o)||e.push(s("error","architecture.floorplan-lifecycle",`${t.feature} \u7F3A\u5C11 ${h}\u3002`));/autoShowEnable\s*:\s*true/.test(o)&&e.push(s("error","architecture.floorplan-lifecycle",`${t.feature} \u5FC5\u987B\u4FDD\u6301 autoShowEnable: false\u3002`));let m=o.indexOf("plugin.appendTo(wrapper)"),f=o.indexOf("plugin.load(serverData)");(m<0||f<m)&&e.push(s("error","architecture.floorplan-mount",`${t.feature} \u5FC5\u987B\u5148\u628A\u63D2\u4EF6 DOM appendTo Five \u5BBF\u4E3B\uFF0C\u518D\u52A0\u8F7D format_floorplan_url \u6570\u636E\u3002`));let p=o.indexOf("stopShow()"),w=o.indexOf("stopHide()"),b=o.indexOf("stopStateChange()"),k=o.indexOf("if (!loading) finalize()"),c=o.indexOf("const finalize ="),d=o.indexOf("restoreModelSurface()",c),g=o.indexOf("plugins.unregister(PLUGIN_NAME, plugin)",c);(p<0||w<p||b<w||k<b||c<0||d<c||g<d)&&e.push(s("error","architecture.floorplan-cleanup",`${t.feature} \u5FC5\u987B\u5728 hide\u3001\u5931\u8D25\u4E0E\u9500\u6BC1\u65F6\u6062\u590D Five model surface\uFF0C\u5E76\u5148\u79FB\u9664\u5168\u90E8 hooks\uFF0C\u518D\u6309 pending load \u72B6\u6001 identity-safe \u6E05\u7406\u3002`))}let i=l.join(r,t.modeSwitcher);if(await u(i)){let o=y(await E(i,"utf8"));for(let[f,p]of[[/type\s+ViewerTab\s*=\s*['"]tour['"]\s*\|\s*['"]model['"]\s*\|\s*['"]floorplan['"]/,"\u4E09\u4E2A ViewerTab"],[/value\s*:\s*['"]tour['"]\s*,\s*text\s*:\s*['"]漫游['"]/,"Panorama \u6F2B\u6E38 tab"],[/value\s*:\s*['"]model['"]\s*,\s*text\s*:\s*['"]三维模型['"]/,"Mapview \u4E09\u7EF4\u6A21\u578B tab"],[/\.\.\.\(\s*floorplan\s*\?\s*\[\{\s*value\s*:\s*['"]floorplan['"](?:\s+as\s+const)?\s*,\s*text\s*:\s*['"]平面图['"]\s*\}\]\s*:\s*\[\]\s*\)/,"\u6761\u4EF6\u5E73\u9762\u56FE tab"]])f.test(o)||e.push(s("error","architecture.floorplan-tabs",`${t.modeSwitcher} \u7F3A\u5C11 ${p}\u3002`));(o.match(/floorplan\?\.visible\s*\?\s*['"]floorplan['"]\s*:\s*tabFromFiveMode\(five\.currentMode\)/g)?.length??0)<2&&e.push(s("error","architecture.floorplan-tabs",`${t.modeSwitcher} \u5FC5\u987B\u5728\u521D\u59CB\u72B6\u6001\u548C\u5207\u6362\u5931\u8D25\u540E\u90FD\u6309\u63D2\u4EF6\u771F\u5B9E\u53EF\u89C1\u6027\u540C\u6B65 Tab\u3002`)),(o.includes("Five.Mode.Topview")||/text\s*:\s*['"]地图['"]/.test(o))&&e.push(s("error","architecture.floorplan-tabs",`${t.modeSwitcher} \u4E0D\u5F97\u628A Topview \u66B4\u9732\u4E3A\u5730\u56FE tab\u3002`))}for(let[o,m]of[[t.browserTsconfig,'"include": ["src", "shared", "vite.config.ts"]'],[t.serverTsconfig,'"include": ["server", "shared"]']]){let f=l.join(r,o);if(!await u(f))continue;(await E(f,"utf8")).includes(m)||e.push(s("error","tooling.floorplan-include",`${o} \u5FC5\u987B\u5305\u542B shared floorplan validator\uFF1A${m}`))}return e}function Rr(r){let t=new Map;for(let e of r.split(/\r?\n/)){let a=e.trim();if(!a||a.startsWith("#"))continue;let n=/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(a);n&&t.set(n[1],n[2].trim())}return t}async function ze(r,t){let e=[],a=l.join(r,".env.example");if(await u(a)){let f=Rr(await E(a,"utf8"));for(let p of ie)f.has(p)||e.push(s("error","env.required-key",`.env.example \u7F3A\u5C11 ${p}\u3002`));for(let[p,w]of f)p.startsWith("VITE_WORK_")&&e.push(s("error","env.legacy-work-url",`.env.example \u4E0D\u5F97\u58F0\u660E\u8DEF\u7531\u6A21\u5F0F\u4E0D\u9700\u8981\u7684 ${p}\u3002`)),p.startsWith("VITE_")&&_e(p)&&e.push(s("error","env.client-secret",`.env.example \u7981\u6B62\u58F0\u660E\u6D4F\u89C8\u5668\u53EF\u89C1\u7684\u5BC6\u94A5\u53D8\u91CF ${p}\u3002`)),_e(p)&&!le.includes(p)&&w&&w!=="*"&&e.push(s("error","env.secret",`.env.example \u7684 ${p} \u53EA\u80FD\u4E3A\u7A7A\u6216\u4F7F\u7528 * \u5360\u4F4D\uFF0C\u4E0D\u80FD\u5305\u542B\u771F\u5B9E\u5BC6\u94A5\u3002`));for(let p of ne){let w=f.get(p);w!==void 0&&w!==""&&w!=="*"&&e.push(s("error","env.credential",`.env.example \u7684 ${p} \u53EA\u80FD\u4E3A\u7A7A\u6216\u4F7F\u7528 * \u5360\u4F4D\u3002`))}}await u(l.join(r,".env.server.example"))&&e.push(s("error","env.legacy-file","\u73AF\u5883\u914D\u7F6E\u5DF2\u5408\u5E76\u5230 .env.example\uFF0C\u4E0D\u5F97\u4FDD\u7559 .env.server.example\u3002"));let n=l.join(r,"src");if(await u(n))for(let f of await x(n)){let p=y(await E(f,"utf8")),w=ee(p);w&&e.push(s("error","env.client-server-only-reference",`${l.relative(r,f)} \u4E0D\u5F97\u8BFB\u53D6\u6216\u5F15\u7528 server-only \u914D\u7F6E\u6216\u51ED\u636E\uFF1A${w}\u3002`))}let i=l.join(r,"src","vr","work","WorkSource.ts");if(await u(i)){let f=y(await E(i,"utf8"));for(let p of["resourceCodeFromPathname","window.location.pathname","segments.length !== 1","`/api/work/${encodeURIComponent(resourceCode)}`","asExplicitPanoTagList","hasCanonicalPanoTagData(value.contentType, value.data)","hasCanonicalPanoTagAnchor(value)","asRecord(envelope.presetData)","presetData: { panoTagList }","displayName: string","displayName: displayNameFrom(work.name) ?? workCode","new RouteWorkSource()"])f.includes(p)||e.push(s("error","architecture.resource-route",`WorkSource \u7F3A\u5C11 /{resourceCode} \u8DEF\u7531\u3001\u540C\u6E90 API \u6216\u663E\u5F0F preset \u6807\u8BB0\uFF1A${p}`));for(let p of["VITE_WORK_URL","/work.json","envelope.tags","envelope.tagList","envelope.tag_list","payload.tags"])f.includes(p)&&e.push(s("error","architecture.resource-route",`WorkSource \u4E0D\u5F97\u4F9D\u8D56\u65E7 Work URL\u3001\u672C\u5730 Work \u6587\u4EF6\u6216\u628A generic tags \u6620\u5C04\u5230 PanoTag\uFF1A${p}`))}for(let f of["vite.config.ts","vite.config.js","vite.config.mjs"]){let p=l.join(r,f);if(!await u(p))continue;let w=y(await E(p,"utf8")),b=ee(w);(b||/envPrefix\s*:\s*[^\n]*REALSEE_/.test(w))&&e.push(s("error","env.vite-secret",`${f} \u4E0D\u5F97\u628A server-only \u914D\u7F6E\u3001AK/SK/token \u6216 REALSEE_* \u524D\u7F00\u6CE8\u5165\u6D4F\u89C8\u5668${b?`\uFF1A${b}`:"\u3002"}`));let k=w.match(/\bhost\s*:\s*['"]127\.0\.0\.1['"]/g)?.length??0,c=w.match(/\bport\s*:\s*8087\b/g)?.length??0,d=w.match(/\bstrictPort\s*:\s*true\b/g)?.length??0,g=/target\s*:\s*['"]http:\/\/127\.0\.0\.1:8088['"]/.test(w);(k<2||c<2||d<2||!g)&&e.push(s("error","architecture.dev-route",`${f} \u5FC5\u987B\u8BA9 Vite server/preview \u4F7F\u7528 strict IPv4 127.0.0.1:8087\uFF0C\u5E76\u628A /api \u4EE3\u7406\u5230 Fastify 127.0.0.1:8088\u3002`))}let o=[["server/types.ts",["ServerConfig","WorkEnvelope","WorkDetailClient","WorkService"]],["server/config.ts",["loadServerConfig","REALSEE_GATEWAY_APP_KEY","REALSEE_GATEWAY_APP_SECRET","gatewayEndpoint.protocol !== 'https:'","): ServerConfig {"]],["server/check-config.ts",["loadServerConfig()","BFF server configuration is valid."]],["server/realsee-open-api.ts",["RealseeOpenApiClient","implements RealseeSpatialClient","ACCESS_TOKEN_PATH = '/auth/access_token'","'application/x-www-form-urlencoded'","WORK_INFO_PATH = '/open/v3/vr/info'","Authorization: accessToken","resource_code: resourceCode","UNAUTHORIZED_UPSTREAM_CODES","TOKEN_REFRESH_SKEW_MS"]],["server/work-service.ts",["createWorkService","): WorkService {","getWorkByResourceCode","openApiClient.getWorkDetail(resourceCode, { signal })"]],["server/work-route.ts",["'/api/work/:resourceCode'","getWorkByResourceCode(resourceCode, {","signal: requestAbort.signal","WORK_UPSTREAM_FAILED"]],["server/app.ts",["Fastify({ logger })","'/api/health'","fastifyStatic","serveFrontend","reply.sendFile('index.html')","Promise<FastifyInstance>"]],["server/index.ts",["loadServerConfig","RealseeOpenApiClient","createWorkService","createApp","app.listen({ host: config.host, port: config.port })"]]];for(let[f,p]of o){let w=l.join(r,f);if(!await u(w)){e.push(s("error","architecture.bff-missing",`\u7F3A\u5C11 Fastify BFF \u6587\u4EF6\uFF1A${f}`));continue}let b=y(await E(w,"utf8"));for(let k of p)b.includes(k)||e.push(s("error","architecture.bff-contract",`${f} \u7F3A\u5C11 BFF \u89E3\u8026\u6216 OpenAPI \u5951\u7EA6\uFF1A${k}`))}let m=l.join(r,t);if(await u(m)){let f=new Set((await E(m,"utf8")).split(/\r?\n/).map(p=>p.trim()).filter(Boolean));for(let p of[".env*","!.env.example"])f.has(p)||e.push(s("error","env.gitignore",`${t} \u5FC5\u987B\u5305\u542B ${p}\u3002`))}return e}async function jr(r,t){return t.name!==Y?!1:Object.hasOwn(t.bin??{},"vr-cli")||await u(l.join(r,"bin","vr-cli.mjs"))||await u(l.join(r,"templates","base"))}async function Pr(r,t){let e=[];t.private!==!1&&e.push(s("error","tool.private","\u53EF\u53D1\u5E03\u5DE5\u5177\u5FC5\u987B\u663E\u5F0F\u58F0\u660E private: false\u3002"));let a=Object.entries(t.bin??{});(a.length!==1||a[0]?.[0]!=="vr-cli"||a[0]?.[1]!=="bin/vr-cli.mjs")&&e.push(s("error","tool.bin","\u5F00\u53D1\u5DE5\u5177\u5FC5\u987B\u53EA\u66B4\u9732 vr-cli -> bin/vr-cli.mjs\u3002")),((typeof t.repository=="string"?t.repository:t.repository?.url)??null)!==null&&e.push(s("error","tool.repository",null===null?"\u5F53\u524D\u53D1\u5E03 profile \u8981\u6C42 package.json \u7701\u7565 repository\u3002":`package.json repository \u5FC5\u987B\u4E3A ${null}\u3002`));let i=t.publishConfig?.registry??null,o=t.publishConfig?.access??null;(i!==F||o!==N)&&e.push(s("error","tool.publish-profile",`package.json publishConfig \u5FC5\u987B\u5339\u914D\u5F53\u524D\u53D1\u5E03 profile\uFF1Aregistry=${F}\uFF0Caccess=${N??"\u672A\u8BBE\u7F6E"}\u3002`)),e.push(...await $e(r,t));let m=["README.md",...await u(l.join(r,".git"))?[".nvmrc",".node-version",".npmrc"]:[],"agent-assets/AGENTS.md","bin","bin/vr-cli.mjs",...N==="public"?["dist/cli.mjs"]:["src","src/core/spatial-policy.mjs"],"templates/base","templates/base/README.md","templates/base/.editorconfig","templates/base/.env.example","templates/base/.gitignore.template","templates/base/.nvmrc","templates/base/.node-version","templates/base/.npmrc.template","templates/base/.prettierignore","templates/base/eslint.config.mjs","templates/base/package-lock.json","templates/base/prettier.config.mjs","templates/base/tsconfig.server.json","templates/base/server/types.ts","templates/base/server/config.ts","templates/base/server/check-config.ts","templates/base/server/realsee-open-api.ts","templates/base/server/work-service.ts","templates/base/server/work-route.ts","templates/base/server/app.ts","templates/base/server/index.ts","templates/base/shared/model-floorplan.ts","templates/base/src/vr/five/api.ts","templates/base/src/vr/five/fiveConfig.ts","templates/base/src/vr/five/SpatialRuntimeProvider.tsx","templates/base/src/vr/five/initialState.ts","templates/base/src/vr/plugins/dnalogel.ts","templates/base/src/vr/plugins/SpatialPluginRegistry.ts","templates/base/src/vr/plugins/examples/FeatureOwnedMeshPlugin.ts","templates/base/src/vr/work/WorkSource.ts","templates/viewer/src/app/App.tsx","templates/viewer/src/features/floorplan/ModelFloorplanFeature.ts","templates/viewer/src/features/navigation/ModeSwitcher.tsx","templates/viewer/src/features/tags/PanoTagFeature.ts","templates/viewer/src/ui/ViewerOverlay.tsx","skills/realsee-vr-app","skills/realsee-vr-app/references/five-api-capabilities.md","skills/realsee-vr-app/references/dnalogel-api-capabilities.md","skills/realsee-vr-app/references/five-runtime.md","skills/realsee-vr-app/references/official-docs.md","skills/realsee-vr-app/references/plugin-lifecycle.md","skills/realsee-vr-app/references/ui-and-validation.md","skills/realsee-vr-app/references/vapor-dom-layer.md","skills/realsee-image-resources/SKILL.md","skills/realsee-image-resources/references/cors-and-three-textures.md","skills/realsee-image-resources/references/data-wanxiang.md","skills/realsee-image-resources/references/five-image-url-transform.md","skills/realsee-image-resources/references/source-and-domain-policy.md","skills/threejs-r117-five/SKILL.md","skills/threejs-r117-five/references/r117-capabilities.md","skills/threejs-r117-five/references/r117-version-guards.md","skills/threejs-r117-five/references/five-ownership.md"];for(let v of m)await u(l.join(r,v))||e.push(s("error","tool.missing",`\u7F3A\u5C11\u5DE5\u5177\u8DEF\u5F84\uFF1A${v}`));for(let v of["templates/base/README.md","agent-assets/AGENTS.md"]){let h=l.join(r,v);if(!await u(h))continue;let S=await E(h,"utf8");S.includes("{{TOOL_VERSION}}")||e.push(s("error","tool.token",`${v} \u5FC5\u987B\u4F7F\u7528 {{TOOL_VERSION}} \u7248\u672C token\u3002`)),S.includes("__TOOL_VERSION__")&&e.push(s("error","tool.token",`${v} \u4E0D\u5F97\u4F7F\u7528\u4E0E Markdown \u7C97\u4F53\u51B2\u7A81\u7684 __TOOL_VERSION__ token\u3002`))}let f=l.join(r,"templates","base");if(await u(f)){let v=new Set(["package-lock.json","package.json","tsconfig.json","tsconfig.server.json"]);for(let h of await K(f))h.endsWith(".json")&&!v.has(h)&&e.push(s("error","tool.data-asset",`\u6A21\u677F\u4E0D\u5F97\u5206\u53D1\u672A\u7ECF\u660E\u786E\u5BA1\u6838\u7684 JSON/Work \u6570\u636E\uFF1Atemplates/base/${h}`))}e.push(...await Ge(r,["skills/realsee-vr-app/SKILL.md","agent-assets/AGENTS.md"],"skills/realsee-vr-app/references/dnalogel-api-capabilities.md")),e.push(...await Ve(r,["skills/realsee-vr-app/SKILL.md","agent-assets/AGENTS.md"],"skills/realsee-vr-app")),e.push(...await Ke(r,["agent-assets/AGENTS.md","skills/realsee-vr-app/SKILL.md"],"skills/realsee-vr-app")),e.push(...await We(r,{validator:"templates/base/shared/model-floorplan.ts",types:"templates/base/server/types.ts",client:"templates/base/server/realsee-open-api.ts",service:"templates/base/server/work-service.ts",workSource:"templates/base/src/vr/work/WorkSource.ts",feature:"templates/viewer/src/features/floorplan/ModelFloorplanFeature.ts",app:"templates/viewer/src/app/App.tsx",modeSwitcher:"templates/viewer/src/features/navigation/ModeSwitcher.tsx",browserTsconfig:"templates/base/tsconfig.json",serverTsconfig:"templates/base/tsconfig.server.json"})),e.push(...await Ie(r,["agent-assets/AGENTS.md","skills/realsee-vr-app/SKILL.md","skills/realsee-image-resources/SKILL.md"])),e.push(...await Ce(r,["agent-assets/AGENTS.md","skills/realsee-vr-app/SKILL.md","skills/realsee-vr-app/references/vapor-dom-layer.md"])),e.push(...await De(r,"skills/realsee-vr-app/references/vapor-dom-layer.md","skills/realsee-vr-app/references/ui-and-validation.md")),e.push(...await Fe(r,"templates/base/src/vr/plugins/examples/FeatureOwnedMeshPlugin.ts"));let p=l.join(r,"templates","base","src","main.tsx");if(await u(p)){let v=y(await E(p,"utf8"));(Ae(v)!==1||v.includes("@realsee/vapor/vapor.scss"))&&e.push(s("error","tool.vapor-css","\u9ED8\u8BA4\u6A21\u677F\u5FC5\u987B\u6070\u597D\u4E00\u6B21\u4EE5\u53EF\u6267\u884C side-effect import \u52A0\u8F7D @realsee/vapor/vapor.css\uFF0C\u4E14\u4E0D\u5F97\u4F7F\u7528 vapor.scss\u3002"))}let w=l.join(r,"templates","base","src","vr","work","WorkSource.ts");if(await u(w)){let v=y(await E(w,"utf8"));for(let h of["displayName: string","displayNameFrom(work.name) ?? workCode"])v.includes(h)||e.push(s("error","tool.work-name",`\u9ED8\u8BA4 WorkSource \u5FC5\u987B\u4ECE work.name \u5B89\u5168\u6D3E\u751F VR \u5C55\u793A\u540D\u79F0\uFF1A${h}`))}let b=l.join(r,"templates","viewer","src","ui","ViewerOverlay.tsx");if(await u(b)){let v=y(await E(b,"utf8")),h=Te.filter(S=>!z(v,S)||!U(v,S));h.length>0&&e.push(s("error","tool.vapor-provider",`\u9ED8\u8BA4 ViewerOverlay \u5FC5\u987B\u4ECE @realsee/vapor \u5BFC\u5165\u5E76\u5B9E\u9645\u6E32\u67D3\u5B98\u65B9 Demo \u7EC4\u4EF6\uFF1A${h.join(", ")}`));for(let S of je)v.includes(S)||e.push(s("error","tool.viewer-topbar",`\u9ED8\u8BA4 ViewerOverlay \u5FC5\u987B\u4F7F\u7528 Vapor TitleBar\u3001Layer \u4E0E\u54CD\u5E94\u5F0F Stack\uFF0C\u5E76\u6E32\u67D3\u5DE6\u4E0A\u6807\u9898\u3001\u5C45\u4E2D controls \u4E0E\u72B6\u6001\u8BED\u4E49\uFF1A${S}`));for(let S of Ne)v.includes(S)&&e.push(s("error","tool.viewer-native-vapor",`\u9ED8\u8BA4 ViewerOverlay \u4E0D\u5F97\u7528\u539F\u751F\u6807\u9898\u6216\u81EA\u5B9A\u4E49 glass \u6837\u5F0F\u66FF\u4EE3 Vapor \u7EC4\u4EF6\u89C6\u89C9\uFF1A${S}`))}let k=l.join(r,"templates","base","src","styles.css");if(await u(k)){let v=await E(k,"utf8");for(let h of Le)v.includes(h)||e.push(s("error","tool.viewer-layout",`\u9ED8\u8BA4 Viewer \u5FC5\u987B\u4FDD\u6301 safe-area \u53CA\u684C\u9762/\u5E73\u677F/\u624B\u673A/\u77EE\u5C4F\u5916\u5C42\u54CD\u5E94\u5F0F\u5E03\u5C40\uFF1A${h}`));for(let h of Me)v.includes(h)&&e.push(s("error","tool.viewer-native-vapor",`\u9ED8\u8BA4 Viewer \u6837\u5F0F\u4E0D\u5F97\u8986\u76D6 Vapor \u5185\u90E8\u7C7B\u6216\u91CD\u7ED8\u7EC4\u4EF6\u89C6\u89C9\uFF1A${h}`))}let c=l.join(r,"templates","viewer","src","features","navigation","ModeSwitcher.tsx");if(await u(c)){let v=y(await E(c,"utf8")),h=Re.filter(S=>!z(v,S)||!U(v,S));h.length>0&&e.push(s("error","tool.vapor-component",`\u9ED8\u8BA4 ModeSwitcher \u5FC5\u987B\u4ECE @realsee/vapor \u5BFC\u5165\u5E76\u5B9E\u9645\u6E32\u67D3\u5B98\u65B9 Demo \u7684\u6A21\u5F0F\u5207\u6362\u7EC4\u4EF6\uFF1A${h.join(", ")}`));for(let S of Pe)v.includes(S)||e.push(s("error","tool.viewer-control-size",`\u9ED8\u8BA4 ModeSwitcher \u5FC5\u987B\u4F7F\u7528\u5B98\u65B9 Demo \u7684 Font/HStack/VStack \u4E0E shadow Button \u7EC4\u5408\uFF1A${S}`));for(let S of xe)v.includes(S)&&e.push(s("error","tool.viewer-native-vapor",`\u9ED8\u8BA4 ModeSwitcher \u4E0D\u5F97\u9000\u56DE Segmented \u6216\u6DFB\u52A0\u65E7\u7684\u62C9\u4F38/glass \u6837\u5F0F\uFF1A${S}`))}let d=l.join(r,"templates","viewer","src");if(await u(d))for(let v of await x(d)){let h=y(await E(v,"utf8")),S=ee(h);S&&e.push(s("error","env.client-server-only-reference",`${l.relative(r,v)} \u4E0D\u5F97\u8BFB\u53D6\u6216\u5F15\u7528 server-only \u914D\u7F6E\u6216\u51ED\u636E\uFF1A${S}\u3002`))}let g=l.join(r,"templates","viewer","src","app","App.tsx");if(await u(g)){let v=y(await E(g,"utf8"));for(let h of["setWorkName(payload.displayName)","title={workName}"])v.includes(h)||e.push(s("error","tool.work-name",`\u9ED8\u8BA4 App \u5FC5\u987B\u628A WorkSource \u5C55\u793A\u540D\u79F0\u4F20\u7ED9 ViewerOverlay\uFF1A${h}`));for(let h of["FeatureOwnedMeshPlugin","registerFeatureOwnedMeshPlugin","vr/plugins/examples"])v.includes(h)&&e.push(s("error","tool.custom-plugin-enabled",`\u9ED8\u8BA4 Viewer \u4E0D\u5F97\u542F\u7528\u81EA\u5B9A\u4E49\u63D2\u4EF6\u793A\u4F8B\uFF1A${h}`))}return e.push(...await ze(l.join(r,"templates","base"),".gitignore.template")),e}async function Lr(r,t,e){let a=new Set;for(let n of e)await u(l.join(r,n))&&a.add(n);for(let n of t){let i=l.join(r,n);if(!await u(i))continue;if(!(await cr(i)).isDirectory()){a.add(n);continue}for(let m of await K(i))a.add(l.posix.join(n,m))}return a}async function Nr(r){let t=[],e=l.join(r,".vr-cli.json");if(!await u(e)){let o=l.join(r,".agents"),m=await u(l.join(r,"AGENTS.md")),f=await u(o);if(!m&&!f)t.push(s("warning","agents.missing","\u672A\u5B89\u88C5\u8DE8 Agent \u6307\u4EE4\u8D44\u4EA7\u3002"));else for(let p of["skills/realsee-vr-app/SKILL.md","skills/realsee-image-resources/SKILL.md","skills/realsee-image-resources/references/cors-and-three-textures.md","skills/realsee-image-resources/references/data-wanxiang.md","skills/realsee-image-resources/references/five-image-url-transform.md","skills/realsee-image-resources/references/source-and-domain-policy.md","skills/threejs-r117-five/SKILL.md","skills/threejs-r117-five/references/r117-capabilities.md","skills/threejs-r117-five/references/r117-version-guards.md","skills/threejs-r117-five/references/five-ownership.md"])await u(l.join(o,p))||t.push(s("error","agents.skill-missing",`.agents/${p} \u7F3A\u5931\u3002`));return t}let a;try{a=await re(e)}catch(o){return[s("error","manifest.invalid",".vr-cli.json \u65E0\u6CD5\u89E3\u6790\u3002",String(o))]}if(!(a&&typeof a=="object"&&!Array.isArray(a)&&a.schemaVersion===1&&O.includes(a.agentAssets)))return[s("error","manifest.invalid",".vr-cli.json \u7F3A\u5C11\u6709\u6548\u7684 schemaVersion \u6216 agentAssets\u3002")];for(let o of W(a.agentAssets))await u(l.join(r,o))||t.push(s("error","agents.asset-missing",`agentAssets=${a.agentAssets} \u7F3A\u5C11\uFF1A${o}`));let i=a.agentAssets==="portable"?{directoryRoots:Ee,singleFiles:Se}:a.agentAssets==="none"?{directoryRoots:he,singleFiles:we}:null;if(i)for(let o of await Lr(r,i.directoryRoots,i.singleFiles))t.push(s("error","agents.unexpected",`agentAssets=${a.agentAssets} \u4E0D\u5E94\u5305\u542B\uFF1A${o}`));return t}async function xr(r,t){let e=[];t.private!==!0&&e.push(s("error","project.public","\u751F\u6210\u9879\u76EE\u5FC5\u987B\u4FDD\u6301 private\u3002")),t.type!=="module"&&e.push(s("error","project.module","\u751F\u6210\u9879\u76EE\u5FC5\u987B\u4F7F\u7528 ESM\uFF1Atype=module\u3002")),e.push(...await $e(r,t));for(let c of ce)await u(l.join(r,c))||e.push(s("error","project.missing",`\u7F3A\u5C11\u751F\u6210\u6587\u4EF6\uFF1A${c}`));for(let[c,d,g]of[["dependency",t.dependencies,G],["dev-dependency",t.devDependencies,q]])for(let[v,h]of Object.entries(g)){let S=d?.[v];if(S===void 0){e.push(s("error",`${c}.missing`,`${v} \u5FC5\u987B\u58F0\u660E\uFF0C\u751F\u6210\u5668\u57FA\u7EBF\u4E3A ${h}`));continue}if(v in V){S!==h&&e.push(s("error",`${c}.locked`,`${v} \u5FC5\u987B\u9501\u5B9A\u4E3A ${h}\uFF0C\u5F53\u524D\u4E3A ${S}\uFF1BFive 6.8.9 \u4E0E Three \u80FD\u529B\u53C2\u8003\u5747\u9488\u5BF9\u8BE5\u7248\u672C\uFF0C\u5347\u7EA7\u9700\u6574\u4F53\u8BC4\u4F30\u5E76\u540C\u6B65\u751F\u6210\u5668\u3002`));continue}let $=H(S);if(!$){e.push(s("error",`${c}.range`,`${v} \u5FC5\u987B\u4F7F\u7528\u5F00\u653E\u6700\u4F4E\u7248\u672C\u8303\u56F4 >=x.y.z\uFF0C\u751F\u6210\u5668\u57FA\u7EBF\u4E3A >=${h}\uFF0C\u5F53\u524D\u4E3A ${S}\u3002`));continue}if(!P($,h)){e.push(s("error",`${c}.minimum`,`${v} \u7684\u58F0\u660E\u4E0B\u9650 ${$} \u4F4E\u4E8E\u751F\u6210\u5668\u57FA\u7EBF ${h}\u3002`));continue}S!==oe(v,h)&&e.push(s("warning",`${c}.updated`,`${v} \u7684\u6700\u4F4E\u7248\u672C\u5DF2\u4ECE\u751F\u6210\u5668\u57FA\u7EBF ${h} \u63D0\u9AD8\u5230 ${$}\uFF1B\u8BF7\u786E\u8BA4 npm run check \u4E0E npm run build \u901A\u8FC7\uFF0C\u5E76\u5728\u5347\u7EA7 SDK \u65F6\u590D\u6838\u7248\u672C\u5316 fixture\u3002`))}for(let[c,d]of[["dev",["check:env","concurrently"]],["dev:bff",["--env-file-if-exists=.env.development","server/index.ts"]],["dev:web",["vite"]],["check:env",["--env-file-if-exists=.env.development","server/check-config.ts"]],["typecheck",["npm run typecheck:web","npm run typecheck:bff"]],["typecheck:web",["tsc -p tsconfig.json"]],["typecheck:bff",["tsc -p tsconfig.server.json"]],["lint",["eslint . --max-warnings=0"]],["format",["prettier --write ."]],["format:check",["prettier --check ."]],["check",["npm run typecheck","npm run lint","npm run format:check"]],["check:bff",["typecheck:bff"]],["deps:relock",["npm install --package-lock-only"]],["deps:install",["npm ci"]],["start",["--env-file-if-exists=.env.development","server/index.ts","--serve-frontend"]]])for(let g of d)t.scripts?.[c]?.includes(g)||e.push(s("error","script.contract",`package.json scripts.${c} \u5FC5\u987B\u5305\u542B\uFF1A${g}`));e.push(...await Tr(r,t));for(let[c,d]of[["eslint.config.mjs",["from '@eslint/js'","from 'typescript-eslint'","from 'eslint-plugin-react-hooks'","recommendedTypeChecked","tsconfig.server.json","globals.browser","globals.node","'react-hooks/rules-of-hooks'","'react-hooks/exhaustive-deps'","no-floating-promises","disableTypeChecked"]],["prettier.config.mjs",["semi: false","singleQuote: true","trailingComma: 'all'"]],["tsconfig.json",['"strict": true','"noUncheckedIndexedAccess": true','"noEmit": true','"include": ["src", "shared", "vite.config.ts"]']],["tsconfig.server.json",['"strict": true','"erasableSyntaxOnly": true','"verbatimModuleSyntax": true','"exactOptionalPropertyTypes": true','"noUncheckedIndexedAccess": true','"types": ["node"]','"include": ["server", "shared"]']]]){let g=l.join(r,c);if(!await u(g))continue;let v=await E(g,"utf8");for(let h of d)v.includes(h)||e.push(s("error","tooling.config",`${c} \u7F3A\u5C11\u914D\u7F6E\u6807\u8BB0\uFF1A${h}`))}let a=l.join(r,"src","main.tsx");if(await u(a)){let c=await E(a,"utf8"),d=y(c);(Ae(d)!==1||d.includes("@realsee/vapor/vapor.scss"))&&e.push(s("error","vapor.css","src/main.tsx \u5FC5\u987B\u6070\u597D\u4E00\u6B21\u4EE5\u53EF\u6267\u884C side-effect import \u5BFC\u5165 @realsee/vapor/vapor.css\uFF0C\u4E14\u4E0D\u5F97\u4F7F\u7528 vapor.scss\u3002")),d.includes("./app/App")||e.push(s("error","architecture.app","src/main.tsx \u5FC5\u987B\u4ECE app \u5C42\u7EC4\u5408\u7A7A\u95F4\u8FD0\u884C\u65F6\u4E0E DOM UI\u3002"))}let n=l.join(r,"src","vr","five","api.ts");if(await u(n)){let c=await E(n,"utf8"),d=y(c);for(let g of["@realsee/five","@realsee/five/plugins","@realsee/five/line","@realsee/five/sticker","@realsee/five/vfx","@realsee/five/gltf-loader","@realsee/five/shader-lib","@realsee/five/work-downloader"])d.includes(`'${g}'`)||e.push(s("error","architecture.five-api",`Five \u80FD\u529B\u5165\u53E3\u7F3A\u5931\uFF1A${g}`))}let i=l.join(r,"src","vr","plugins","dnalogel.ts");await u(i)&&(y(await E(i,"utf8")).includes("from '@realsee/dnalogel'")||e.push(s("error","architecture.dnalogel-api","dnalogel \u9884\u8BBE\u63D2\u4EF6\u6839\u80FD\u529B\u5165\u53E3\u7F3A\u5931\u3002"))),e.push(...await Fe(r,"src/vr/plugins/examples/FeatureOwnedMeshPlugin.ts"));let o=l.join(r,"src");if(await u(o))for(let c of await x(o)){let d=y(await E(c,"utf8"));d.includes("@realsee/five/react")&&e.push(s("error","architecture.five-react",`${l.relative(r,c)} \u7981\u6B62\u4F7F\u7528\u66F4\u65B0\u6EDE\u540E\u7684 @realsee/five/react\uFF1B\u8BF7\u76F4\u63A5\u4F7F\u7528\u539F\u751F Five API\u3002`));for(let g of dr)g.pattern.test(d)&&e.push(s("error","compatibility.three-r117",`${l.relative(r,c)}\uFF1A${g.message}`))}let m=l.join(r,"src","vr","five","SpatialRuntimeProvider.tsx");if(await u(m)){let c=await E(m,"utf8"),d=y(c);(d.includes("unsafe__useFiveInstance")||d.includes("provider?.five"))&&e.push(s("error","architecture.five-instance","\u7A7A\u95F4\u8FD0\u884C\u65F6\u7981\u6B62\u901A\u8FC7 Five React wrapper \u83B7\u53D6\u5B9E\u4F8B\u3002")),/import\s*\{[^}]*\bFive\b[^}]*\}\s*from\s*['"]@realsee\/five['"]/.test(d)||e.push(s("error","architecture.five-native","SpatialRuntimeProvider \u5FC5\u987B\u4ECE @realsee/five \u5BFC\u5165\u539F\u751F Five\u3002"));for(let h of["new Five(",".appendTo(",".refresh(",".getElement()",".dispose()","new ResizeObserver","new SpatialRuntimeLifetime","runExclusive<T>(","ownedLifetime?.disposeFeatures()","ownedLifetime.afterPending(finalize)","width <= 0 || height <= 0",'className="five-surface"'])d.includes(h)||e.push(s("error","architecture.five-native",`\u539F\u751F Five \u751F\u547D\u5468\u671F\u7F3A\u5C11\uFF1A${h}`));let g=d.indexOf("ownedLifetime?.disposeFeatures()"),v=d.indexOf("ownedLifetime.afterPending(finalize)");(g<0||v<g)&&e.push(s("error","architecture.five-cleanup","\u5FC5\u987B\u5148\u540C\u6B65\u505C\u6B62 feature\uFF0C\u518D\u7B49\u5F85\u539F\u751F\u5F02\u6B65\u4EFB\u52A1\u5B8C\u6210\u540E\u6E05\u7406\u63D2\u4EF6\u548C Five\u3002"))}let f=l.join(r,"src","app","App.tsx");if(await u(f)){let c=await E(f,"utf8"),d=y(c);for(let g of["lifetime.own(","lifetime.runExclusive(","await five.load(","await waitForActiveModel(","const panoTagList = payload.presetData?.panoTagList","if (panoTagList?.length)","await currentTags.load(panoTagList)","setWorkName(payload.displayName)","title={workName}"])d.includes(g)||e.push(s("error","architecture.feature-lifetime",`App \u7684\u539F\u751F\u5F02\u6B65\u751F\u547D\u5468\u671F\u6216\u663E\u5F0F PanoTag preset \u6761\u4EF6\u7F3A\u5C11\uFF1A${g}`));d.includes("payload.tags")&&e.push(s("error","architecture.pano-tag-contract","App \u4E0D\u5F97\u628A generic payload.tags \u76F4\u63A5\u52A0\u8F7D\u4E3A PanoTag\u3002"))}let p=l.join(r,"src","ui"),w=l.join(p,"ViewerOverlay.tsx");if(await u(w)){let c=y(await E(w,"utf8")),d=Te.filter(g=>!z(c,g)||!U(c,g));d.length>0&&e.push(s("error","architecture.vapor-provider",`ViewerOverlay \u5FC5\u987B\u4ECE @realsee/vapor \u5BFC\u5165\u5E76\u5B9E\u9645\u6E32\u67D3\u5B98\u65B9 Demo \u7EC4\u4EF6\uFF1A${d.join(", ")}`));for(let g of je)c.includes(g)||e.push(s("error","architecture.viewer-topbar",`ViewerOverlay \u5FC5\u987B\u4F7F\u7528 Vapor TitleBar\u3001Layer \u4E0E\u54CD\u5E94\u5F0F Stack\uFF0C\u5E76\u6E32\u67D3\u5DE6\u4E0A\u6807\u9898\u3001\u5C45\u4E2D controls \u4E0E\u72B6\u6001\u8BED\u4E49\uFF1A${g}`));for(let g of Ne)c.includes(g)&&e.push(s("error","architecture.viewer-native-vapor",`ViewerOverlay \u4E0D\u5F97\u7528\u539F\u751F\u6807\u9898\u6216\u81EA\u5B9A\u4E49 glass \u6837\u5F0F\u66FF\u4EE3 Vapor \u7EC4\u4EF6\u89C6\u89C9\uFF1A${g}`))}let b=l.join(r,"src","features","navigation","ModeSwitcher.tsx");if(await u(b)){let c=y(await E(b,"utf8")),d=Re.filter(g=>!z(c,g)||!U(c,g));d.length>0&&e.push(s("error","architecture.vapor-component",`ModeSwitcher \u5FC5\u987B\u4ECE @realsee/vapor \u5BFC\u5165\u5E76\u5B9E\u9645\u6E32\u67D3\u5B98\u65B9 Demo \u7684\u6A21\u5F0F\u5207\u6362\u7EC4\u4EF6\uFF1A${d.join(", ")}`));for(let g of Pe)c.includes(g)||e.push(s("error","architecture.viewer-control-size",`ModeSwitcher \u5FC5\u987B\u4F7F\u7528\u5B98\u65B9 Demo \u7684 Font/HStack/VStack \u4E0E shadow Button \u7EC4\u5408\uFF1A${g}`));for(let g of xe)c.includes(g)&&e.push(s("error","architecture.viewer-native-vapor",`ModeSwitcher \u4E0D\u5F97\u9000\u56DE Segmented \u6216\u6DFB\u52A0\u65E7\u7684\u62C9\u4F38/glass \u6837\u5F0F\uFF1A${g}`))}if(await u(p))for(let c of await x(p)){let d=y(await E(c,"utf8")),g=/(?:from|import)\s*(?:\(\s*)?['"][^'"]*\/vr\//.test(d);(d.includes("@realsee/five")||d.includes("@realsee/dnalogel")||g)&&e.push(s("error","architecture.ui-boundary",`${l.relative(r,c)} \u4E0D\u5F97\u5BFC\u5165 src/vr\u3001Five \u6216 dnalogel \u7A7A\u95F4\u8FD0\u884C\u65F6\u3002`))}let k=l.join(r,"src","styles.css");if(await u(k)){let c=await E(k,"utf8");(!c.includes(".five-surface")||!c.includes(".dom-overlay")||!c.includes("pointer-events: none"))&&e.push(s("error","architecture.dom-overlay","\u539F\u751F Five surface \u4E0E DOM overlay \u5FC5\u987B\u4FDD\u6301\u72EC\u7ACB\u5206\u5C42\u53CA pointer-events \u9694\u79BB\u3002"));for(let d of Le)c.includes(d)||e.push(s("error","architecture.viewer-layout",`Viewer \u5FC5\u987B\u4FDD\u6301 safe-area \u53CA\u684C\u9762/\u5E73\u677F/\u624B\u673A/\u77EE\u5C4F\u5916\u5C42\u54CD\u5E94\u5F0F\u5E03\u5C40\uFF1A${d}`));for(let d of Me)c.includes(d)&&e.push(s("error","architecture.viewer-native-vapor",`Viewer \u6837\u5F0F\u4E0D\u5F97\u8986\u76D6 Vapor \u5185\u90E8\u7C7B\u6216\u91CD\u7ED8\u7EC4\u4EF6\u89C6\u89C9\uFF1A${d}`))}return e.push(...await ze(r,".gitignore")),e.push(...await Ge(r,[".agents/skills/realsee-vr-app/SKILL.md","AGENTS.md"],".agents/skills/realsee-vr-app/references/dnalogel-api-capabilities.md")),e.push(...await Ve(r,[".agents/skills/realsee-vr-app/SKILL.md","AGENTS.md"],".agents/skills/realsee-vr-app")),e.push(...await Ke(r,["AGENTS.md",".agents/skills/realsee-vr-app/SKILL.md"],".agents/skills/realsee-vr-app")),e.push(...await We(r,{validator:"shared/model-floorplan.ts",types:"server/types.ts",client:"server/realsee-open-api.ts",service:"server/work-service.ts",workSource:"src/vr/work/WorkSource.ts",feature:"src/features/floorplan/ModelFloorplanFeature.ts",app:"src/app/App.tsx",modeSwitcher:"src/features/navigation/ModeSwitcher.tsx",browserTsconfig:"tsconfig.json",serverTsconfig:"tsconfig.server.json"})),e.push(...await Ie(r,["AGENTS.md",".agents/skills/realsee-vr-app/SKILL.md",".agents/skills/realsee-image-resources/SKILL.md"])),e.push(...await Ce(r,["AGENTS.md",".agents/skills/realsee-vr-app/SKILL.md",".agents/skills/realsee-vr-app/references/vapor-dom-layer.md"])),e.push(...await De(r,".agents/skills/realsee-vr-app/references/vapor-dom-layer.md",".agents/skills/realsee-vr-app/references/ui-and-validation.md")),e.push(...await Nr(r)),e}async function Ue({directory:r=".",json:t=!1}){let e=l.resolve(r),a=l.join(e,"package.json"),n=[];P(process.versions.node,C)||n.push(s("error","node.version",`\u9700\u8981 Node >=${C}\uFF0C\u5F53\u524D ${process.versions.node}`));try{let o=await Or();P(o,D)||n.push(s("error","npm.version",`\u9700\u8981 npm >=${D}\uFF0C\u5F53\u524D ${o}`))}catch(o){n.push(s("error","npm.unavailable","\u65E0\u6CD5\u6267\u884C npm --version\u3002",String(o)))}if(!await u(a))n.push(s("error","package.missing",`\u627E\u4E0D\u5230 package.json\uFF1A${a}`));else try{let o=await re(a);n.push(...await jr(e,o)?await Pr(e,o):await xr(e,o))}catch(o){n.push(s("error","package.invalid","package.json \u65E0\u6CD5\u89E3\u6790\u3002",String(o)))}let i={ok:!n.some(o=>o.level==="error"),root:e,errors:n.filter(o=>o.level==="error").length,warnings:n.filter(o=>o.level==="warning").length,diagnostics:n};if(t)console.log(JSON.stringify(i,null,2));else{for(let o of n)console.log(`${o.level==="error"?"ERROR":"WARN "} [${o.code}] ${o.message}`);console.log(i.ok?`OK ${e}`:`FAILED ${e}`)}return i}var M=Object.freeze({version:1,capabilityOrder:["@realsee/dnalogel","@realsee/five","three"],intentRoutes:Object.freeze([Object.freeze({intent:"tag|hotspot|anchor",defaultCapability:"PanoTagPlugin",source:"GET /open/v3/hot/list"}),Object.freeze({intent:"tour",defaultCapability:"Five State snapshot",source:"GET /open/v3/observerpicture/search"}),Object.freeze({intent:"model-annotation",defaultCapability:"ModelMakerPlugin",source:"GET /open/v3/annotation/search"}),Object.freeze({intent:"floorplan|house-layout",defaultCapability:"ModelFloorplanPlugin",source:"GET /open/v3/floorplan/plugins -> data.format_floorplan_url"}),Object.freeze({intent:"route",defaultCapability:"GuideLinePlugin + CruisePlugin|MovePlugin",source:"GET /open/v3/route/search"})]),invariants:Object.freeze(["OpenAPI data is fetched by the BFF, validated, then adapted to installed SDK types.","SDK-shaped local data requires an explicit Open Platform opt-out.","A fallback records the missing preset capability before using Five or Three.","Only a completely validated { version, data: FloorplanServerData } wrapper from data.format_floorplan_url may expose the modelFloorplan capability.","Missing, empty, malformed or failed floorplan data is feature-local and leaves the base Viewer usable.","Each feature owns cancellation, registrations, hooks, media and Three resources.","Persistent Work or customer-data mutations require an authoritative write contract and confirmation."])});var Ye=`vr-cli ${j}
|
|
3
3
|
|
|
4
4
|
Usage:
|