agentshire 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.md +437 -0
- package/README.zh-CN.md +441 -0
- package/ROADMAP.md +207 -0
- package/THIRD_PARTY_NOTICES.md +49 -0
- package/VISION.md +101 -0
- package/index.ts +386 -0
- package/openclaw.plugin.json +27 -0
- package/package.json +100 -0
- package/src/bridge/AGENTS.md +136 -0
- package/src/bridge/ActivityStream.ts +184 -0
- package/src/bridge/CitizenManager.ts +280 -0
- package/src/bridge/DirectorBridge.ts +1076 -0
- package/src/bridge/EventTranslator.ts +142 -0
- package/src/bridge/NpcEventQueue.ts +61 -0
- package/src/bridge/ReconnectManager.ts +42 -0
- package/src/bridge/RouteManager.ts +270 -0
- package/src/bridge/StateTracker.ts +100 -0
- package/src/bridge/ToolVfxMapper.ts +94 -0
- package/src/bridge/__tests__/ActivityStream.test.ts +156 -0
- package/src/bridge/__tests__/CitizenManager.test.ts +174 -0
- package/src/bridge/__tests__/EventTranslator.test.ts +292 -0
- package/src/bridge/__tests__/NpcEventQueue.test.ts +92 -0
- package/src/bridge/__tests__/RouteManager.test.ts +106 -0
- package/src/bridge/data/route-config.json +36 -0
- package/src/bridge/data/route-config.ts +19 -0
- package/src/bridge/implicit-chat.ts +192 -0
- package/src/bridge/index.ts +12 -0
- package/src/contracts/agent-state.ts +87 -0
- package/src/contracts/agui.ts +212 -0
- package/src/contracts/chat.ts +67 -0
- package/src/contracts/events.ts +170 -0
- package/src/contracts/index.ts +71 -0
- package/src/contracts/media.ts +77 -0
- package/src/contracts/registry.ts +32 -0
- package/src/plugin/AGENTS.md +192 -0
- package/src/plugin/__tests__/editor-serve-megapack.test.ts +150 -0
- package/src/plugin/__tests__/hook-translator.test.ts +197 -0
- package/src/plugin/auto-config.ts +131 -0
- package/src/plugin/channel.ts +399 -0
- package/src/plugin/chat-asset-resolver.ts +75 -0
- package/src/plugin/chat-session-watcher.ts +98 -0
- package/src/plugin/citizen-agent-manager.ts +178 -0
- package/src/plugin/citizen-chat-router.ts +83 -0
- package/src/plugin/citizen-workshop-manager.ts +96 -0
- package/src/plugin/custom-asset-manager.ts +250 -0
- package/src/plugin/editor-serve.ts +1368 -0
- package/src/plugin/group-discussion.ts +223 -0
- package/src/plugin/hook-translator.ts +202 -0
- package/src/plugin/llm-agent-proxy.ts +193 -0
- package/src/plugin/outbound-adapter.ts +187 -0
- package/src/plugin/paths.ts +33 -0
- package/src/plugin/plan-manager.ts +594 -0
- package/src/plugin/runtime.ts +9 -0
- package/src/plugin/session-history.ts +838 -0
- package/src/plugin/session-log-watcher.ts +221 -0
- package/src/plugin/soul-prompt-template.ts +290 -0
- package/src/plugin/subagent-tracker.ts +205 -0
- package/src/plugin/tools.ts +493 -0
- package/src/plugin/town-session.ts +40 -0
- package/src/plugin/ws-server.ts +680 -0
- package/src/town-souls.ts +134 -0
- package/town-frontend/dist/assets/CustomAssetStore-oi8aIurt.js +2 -0
- package/town-frontend/dist/assets/GLTFLoader-BA5RqSME.js +3804 -0
- package/town-frontend/dist/assets/OrbitControls-ZmySp9sQ.js +2 -0
- package/town-frontend/dist/assets/SettingsPanel-BO52reJe.js +2 -0
- package/town-frontend/dist/assets/SkeletonUtils-BCVmgslc.js +2 -0
- package/town-frontend/dist/assets/SkillLearnCard-Dk38iDpy.js +6 -0
- package/town-frontend/dist/assets/TopicSetupPanel-DLaLHB_Z.js +2 -0
- package/town-frontend/dist/assets/Trap-Bold-CT0JBE39.woff2 +0 -0
- package/town-frontend/dist/assets/Trap-SemiBold-R4_-Ld0j.woff2 +0 -0
- package/town-frontend/dist/assets/WeatherSystem-Cb3BvHes.js +550 -0
- package/town-frontend/dist/assets/avatars/char-female-a.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-female-b.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-female-c.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-female-d.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-female-e.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-female-f.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-male-a.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-male-b.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-male-c.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-male-d.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-male-e.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-male-f.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-beaver.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-bee.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-bunny.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-cat.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-caterpillar.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-chick.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-cow.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-crab.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-deer.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-dog.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-elephant.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-fish.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-fox.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-giraffe.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-hog.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-koala.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-lion.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-monkey.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-panda.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-parrot.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-penguin.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-pig.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-polar.webp +0 -0
- package/town-frontend/dist/assets/avatars/char-pet-tiger.webp +0 -0
- package/town-frontend/dist/assets/character-catalog-DSmLtlNC.js +2 -0
- package/town-frontend/dist/assets/citizenEditor-DubGSJOQ.js +296 -0
- package/town-frontend/dist/assets/command-parser-BUd15Bmv.js +12 -0
- package/town-frontend/dist/assets/editor-B5QO0OtX.js +258 -0
- package/town-frontend/dist/assets/editor-Bk8g1NCD.css +1 -0
- package/town-frontend/dist/assets/index-BWfrufil.js +2 -0
- package/town-frontend/dist/assets/index-faS20RJk.js +6 -0
- package/town-frontend/dist/assets/logo-DJI6EtST.png +0 -0
- package/town-frontend/dist/assets/logo-title-AdKPZX5E.png +0 -0
- package/town-frontend/dist/assets/main-CqsN43aT.js +224 -0
- package/town-frontend/dist/assets/main-D7neuy3w.css +1 -0
- package/town-frontend/dist/assets/models/buildings/base.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/base.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/bench.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/bench.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/box_A.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/box_A.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/box_B.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/box_B.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_A.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_A.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_A_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_A_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_B.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_B.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_B_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_B_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_C.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_C.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_C_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_C_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_D.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_D.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_D_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_D_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_E.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_E.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_E_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_E_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_F.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_F.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_F_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_F_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_G.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_G.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_G_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_G_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_H.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_H.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/building_H_withoutBase.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/building_H_withoutBase.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/bush.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/bush.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/car_hatchback.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/car_hatchback.gltf +442 -0
- package/town-frontend/dist/assets/models/buildings/car_police.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/car_police.gltf +442 -0
- package/town-frontend/dist/assets/models/buildings/car_sedan.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/car_sedan.gltf +442 -0
- package/town-frontend/dist/assets/models/buildings/car_stationwagon.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/car_stationwagon.gltf +442 -0
- package/town-frontend/dist/assets/models/buildings/car_taxi.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/car_taxi.gltf +442 -0
- package/town-frontend/dist/assets/models/buildings/citybits_texture.png +0 -0
- package/town-frontend/dist/assets/models/buildings/dumpster.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/dumpster.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/firehydrant.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/firehydrant.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/road_corner.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/road_corner.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/road_corner_curved.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/road_corner_curved.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/road_junction.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/road_junction.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/road_straight.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/road_straight.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/road_straight_crossing.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/road_straight_crossing.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/road_tsplit.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/road_tsplit.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/streetlight.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/streetlight.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/trafficlight_A.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/trafficlight_A.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/trafficlight_B.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/trafficlight_B.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/trafficlight_C.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/trafficlight_C.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/trash_A.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/trash_A.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/trash_B.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/trash_B.gltf +136 -0
- package/town-frontend/dist/assets/models/buildings/watertower.bin +0 -0
- package/town-frontend/dist/assets/models/buildings/watertower.gltf +136 -0
- package/town-frontend/dist/assets/models/characters/Textures/colormap.png +0 -0
- package/town-frontend/dist/assets/models/characters/character-female-a.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-female-b.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-female-c.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-female-d.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-female-e.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-female-f.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-male-a.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-male-b.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-male-c.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-male-d.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-male-e.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-male-f.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-beaver.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-bee.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-bunny.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-cat.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-caterpillar.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-chick.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-cow.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-crab.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-deer.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-dog.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-elephant.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-fish.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-fox.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-giraffe.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-hog.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-koala.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-lion.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-monkey.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-panda.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-parrot.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-penguin.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-pig.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-polar.glb +0 -0
- package/town-frontend/dist/assets/models/characters/character-pet-tiger.glb +0 -0
- package/town-frontend/dist/assets/models/characters/colormap.png +0 -0
- package/town-frontend/dist/assets/models/furniture/armchair.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/armchair.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/armchair_pillows.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/armchair_pillows.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/bed_double_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/bed_double_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/bed_double_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/bed_double_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/bed_single_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/bed_single_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/bed_single_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/bed_single_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/book_set.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/book_set.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/book_single.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/book_single.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_medium.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_medium.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_medium_decorated.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_medium_decorated.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_small.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_small.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_small_decorated.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cabinet_small_decorated.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cactus_medium_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cactus_medium_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cactus_medium_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cactus_medium_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cactus_small_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cactus_small_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/cactus_small_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/cactus_small_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_A_wood.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_A_wood.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_B_wood.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_B_wood.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_C.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_C.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_stool.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_stool.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/chair_stool_wood.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/chair_stool_wood.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/couch.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/couch.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/couch_pillows.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/couch_pillows.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/furniturebits_texture.png +0 -0
- package/town-frontend/dist/assets/models/furniture/lamp_standing.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/lamp_standing.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/lamp_table.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/lamp_table.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_large_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_large_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_large_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_large_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_medium.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_medium.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_small_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_small_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_small_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_small_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_small_C.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_small_C.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_standing_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_standing_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_standing_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pictureframe_standing_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pillow_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pillow_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/pillow_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/pillow_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/rug_oval_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/rug_oval_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/rug_oval_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/rug_oval_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_stripes_A.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_stripes_A.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_stripes_B.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/rug_rectangle_stripes_B.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/shelf_A_big.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/shelf_A_big.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/shelf_A_small.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/shelf_A_small.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_large.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_large.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_large_decorated.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_large_decorated.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_small.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_small.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_small_decorated.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/shelf_B_small_decorated.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/table_low.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/table_low.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/table_medium.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/table_medium.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/table_medium_long.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/table_medium_long.gltf +136 -0
- package/town-frontend/dist/assets/models/furniture/table_small.bin +0 -0
- package/town-frontend/dist/assets/models/furniture/table_small.gltf +136 -0
- package/town-frontend/dist/assets/models/props/bench.bin +0 -0
- package/town-frontend/dist/assets/models/props/bench.gltf +136 -0
- package/town-frontend/dist/assets/models/props/bush.bin +0 -0
- package/town-frontend/dist/assets/models/props/bush.gltf +136 -0
- package/town-frontend/dist/assets/models/props/capybara.glb +0 -0
- package/town-frontend/dist/assets/models/props/car_hatchback.bin +0 -0
- package/town-frontend/dist/assets/models/props/car_hatchback.gltf +442 -0
- package/town-frontend/dist/assets/models/props/car_sedan.bin +0 -0
- package/town-frontend/dist/assets/models/props/car_sedan.gltf +442 -0
- package/town-frontend/dist/assets/models/props/car_taxi.bin +0 -0
- package/town-frontend/dist/assets/models/props/car_taxi.gltf +442 -0
- package/town-frontend/dist/assets/models/props/citybits_texture.png +0 -0
- package/town-frontend/dist/assets/models/props/dumpster.bin +0 -0
- package/town-frontend/dist/assets/models/props/dumpster.gltf +136 -0
- package/town-frontend/dist/assets/models/props/firehydrant.bin +0 -0
- package/town-frontend/dist/assets/models/props/firehydrant.gltf +136 -0
- package/town-frontend/dist/assets/models/props/streetlight.bin +0 -0
- package/town-frontend/dist/assets/models/props/streetlight.gltf +136 -0
- package/town-frontend/dist/assets/models/props/trafficlight_A.bin +0 -0
- package/town-frontend/dist/assets/models/props/trafficlight_A.gltf +136 -0
- package/town-frontend/dist/assets/models/props/trash_A.bin +0 -0
- package/town-frontend/dist/assets/models/props/trash_A.gltf +136 -0
- package/town-frontend/dist/assets/models/props/watertower.bin +0 -0
- package/town-frontend/dist/assets/models/props/watertower.gltf +136 -0
- package/town-frontend/dist/assets/models/stage-deco/Flowers_1_D.glb +0 -0
- package/town-frontend/dist/assets/models/stage-deco/Flowers_2_B.glb +0 -0
- package/town-frontend/dist/assets/models/stage-deco/Grass_A_1.glb +0 -0
- package/town-frontend/dist/assets/models/stage-deco/Park_GrassHill_A.glb +0 -0
- package/town-frontend/dist/assets/models/stage-deco/Pebles_1_A_2.glb +0 -0
- package/town-frontend/dist/assets/music/bgm_day.mp3 +0 -0
- package/town-frontend/dist/assets/music/bgm_dusk.mp3 +0 -0
- package/town-frontend/dist/assets/music/bgm_night.mp3 +0 -0
- package/town-frontend/dist/assets/music/bgm_work.mp3 +0 -0
- package/town-frontend/dist/assets/office-whiteboard-idle-CyEwBrq_.webp +0 -0
- package/town-frontend/dist/assets/preview-B6hYEQij.js +2 -0
- package/town-frontend/dist/assets/town-BKesnERP.js +8888 -0
- package/town-frontend/dist/assets/town-BnswKsjF.css +1 -0
- package/town-frontend/dist/citizen-editor.html +166 -0
- package/town-frontend/dist/editor.html +227 -0
- package/town-frontend/dist/index.html +22 -0
- package/town-frontend/dist/preview.html +56 -0
- package/town-frontend/dist/town.html +165 -0
- package/town-frontend/dist/viewer.html +91 -0
- package/town-souls/CHEN.md +130 -0
- package/town-souls/CHENGZI.md +92 -0
- package/town-souls/CITIZEN_tpl.md +16 -0
- package/town-souls/DIANDIAN.md +92 -0
- package/town-souls/HAITANG.md +94 -0
- package/town-souls/QIQI.md +119 -0
- package/town-souls/SOUL.md +141 -0
- package/town-souls/SOUL_tpl.md +135 -0
- package/town-souls/XIAOLIE.md +107 -0
- package/town-souls/YAN.md +107 -0
- package/town-workspace/IDENTITY.md +5 -0
- package/town-workspace/SOUL.md +141 -0
- package/town-workspace/project-workflow.md +81 -0
- package/town-workspace/town-defaults.json +92 -0
- package/town-workspace/town-guide.md +45 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// @desc AgentEvent union type — the canonical event contract for all consumers
|
|
2
|
+
//
|
|
3
|
+
// 来源: OpenClaw 的 agentLoop() 通过 onEvent 回调发射这些事件
|
|
4
|
+
// 消费者: CLI (TerminalRenderer / App.tsx), Server (ws-handler 透传), Frontend (stream-display)
|
|
5
|
+
//
|
|
6
|
+
// 迁移注意:
|
|
7
|
+
// - src/core/types.ts 的 AgentEvent 已改为从本文件 re-export
|
|
8
|
+
// - 旧的 audio_delta / asr_result 已重命名为 media_delta / media_result
|
|
9
|
+
// - state_snapshot 是新增事件, OpenClaw 核心尚未发射, 预留给状态推送
|
|
10
|
+
// - tool_use.input 从 Record<string, any> 收紧为 Record<string, unknown>
|
|
11
|
+
|
|
12
|
+
import type { AudioContent, VideoContent, ContentKind } from './media.js';
|
|
13
|
+
import type { AgentStateSnapshot } from './agent-state.js';
|
|
14
|
+
|
|
15
|
+
// ── Shared sub-types ──
|
|
16
|
+
|
|
17
|
+
export interface MediaOutputMeta {
|
|
18
|
+
width?: number;
|
|
19
|
+
height?: number;
|
|
20
|
+
durationMs?: number;
|
|
21
|
+
filename?: string;
|
|
22
|
+
sizeBytes?: number;
|
|
23
|
+
alt?: string;
|
|
24
|
+
format?: string;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AgentStats {
|
|
29
|
+
tokensIn: number;
|
|
30
|
+
tokensOut: number;
|
|
31
|
+
contextPercent: number;
|
|
32
|
+
toolCalls: number;
|
|
33
|
+
agentSpawns: number;
|
|
34
|
+
skillCalls: number;
|
|
35
|
+
workflowCalls: number;
|
|
36
|
+
durationMs: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ToolResultMeta {
|
|
40
|
+
pid?: number;
|
|
41
|
+
exitCode?: number;
|
|
42
|
+
durationMs?: number;
|
|
43
|
+
filePath?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface TokenUsage {
|
|
47
|
+
inputTokens: number;
|
|
48
|
+
outputTokens: number;
|
|
49
|
+
thinkingTokens?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ASRSegment {
|
|
53
|
+
text: string;
|
|
54
|
+
start: number;
|
|
55
|
+
end: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── AgentEvent ──
|
|
59
|
+
|
|
60
|
+
export type AgentEvent =
|
|
61
|
+
// System lifecycle
|
|
62
|
+
| { type: 'system'; subtype: 'init'; sessionId: string; model: string; persona?: string }
|
|
63
|
+
| { type: 'system'; subtype: 'done'; result: string; sessionId: string }
|
|
64
|
+
| { type: 'system'; subtype: 'heartbeat'; elapsedSec: number; waiting: boolean }
|
|
65
|
+
| { type: 'system'; subtype: 'compacting'; reason: 'auto' | 'manual' | 'micro' }
|
|
66
|
+
| { type: 'system'; subtype: 'hot_reload_requested'; reason?: string }
|
|
67
|
+
|
|
68
|
+
// Text stream
|
|
69
|
+
| { type: 'text_delta'; delta: string }
|
|
70
|
+
| { type: 'text'; content: string }
|
|
71
|
+
|
|
72
|
+
// Tool calls
|
|
73
|
+
| { type: 'tool_input_delta'; toolUseId: string; name: string; delta: string }
|
|
74
|
+
| { type: 'tool_use'; toolUseId: string; name: string; input: Record<string, unknown> }
|
|
75
|
+
| { type: 'tool_result'; toolUseId: string; name: string; output: string;
|
|
76
|
+
displayOutput?: string; meta?: ToolResultMeta }
|
|
77
|
+
|
|
78
|
+
// Context & turn
|
|
79
|
+
| { type: 'context_update'; tokens: { used: number; limit: number; percent: number };
|
|
80
|
+
usage?: TokenUsage; messagesCount: number; iteration: number; maxIterations: number }
|
|
81
|
+
| { type: 'turn_end'; usage: TokenUsage; toolCalls: number; durationMs: number }
|
|
82
|
+
|
|
83
|
+
// Sub-agents
|
|
84
|
+
| { type: 'sub_agent'; subtype: 'started'; agentId: string; agentType: string;
|
|
85
|
+
parentToolUseId: string; task: string; model: string; displayName?: string }
|
|
86
|
+
| { type: 'sub_agent'; subtype: 'progress'; agentId: string; event: AgentEvent }
|
|
87
|
+
| { type: 'sub_agent'; subtype: 'done'; agentId: string;
|
|
88
|
+
result: string; toolCalls: number; status: 'completed' | 'failed' | 'killed';
|
|
89
|
+
stats?: AgentStats }
|
|
90
|
+
|
|
91
|
+
// State snapshot
|
|
92
|
+
| { type: 'state_snapshot'; state: AgentStateSnapshot }
|
|
93
|
+
|
|
94
|
+
// Multimodal media
|
|
95
|
+
| { type: 'media_delta'; streamId: string; content: AudioContent | VideoContent; final?: boolean }
|
|
96
|
+
| { type: 'media_result'; kind: 'asr'; text: string; confidence?: number; segments?: ASRSegment[] }
|
|
97
|
+
| { type: 'media_status'; stage: 'asr' | 'tts' | 'vlm';
|
|
98
|
+
status: 'processing' | 'done' | 'error'; detail?: string }
|
|
99
|
+
|
|
100
|
+
// Thinking / reasoning stream (parallel to text_delta)
|
|
101
|
+
| { type: 'thinking_delta'; delta: string }
|
|
102
|
+
|
|
103
|
+
// LLM call lifecycle
|
|
104
|
+
| { type: 'llm_call'; subtype: 'start';
|
|
105
|
+
model: string; iteration: number; maxIterations: number;
|
|
106
|
+
messagesCount: number; toolCount: number;
|
|
107
|
+
systemPromptPreview?: string }
|
|
108
|
+
| { type: 'llm_call'; subtype: 'end';
|
|
109
|
+
iteration: number; durationMs: number;
|
|
110
|
+
stopReason: string; retryCount: number;
|
|
111
|
+
usage: TokenUsage }
|
|
112
|
+
|
|
113
|
+
// Agent-to-agent messaging
|
|
114
|
+
| { type: 'bus_message'; from: string; to: string;
|
|
115
|
+
summary: string; contentPreview: string; timestamp: number }
|
|
116
|
+
| { type: 'bus_drain'; agentName: string;
|
|
117
|
+
messageCount: number; summaries: string[] }
|
|
118
|
+
|
|
119
|
+
// Hook execution
|
|
120
|
+
| { type: 'hook'; hookType: 'pre_tool' | 'post_tool';
|
|
121
|
+
toolName: string; toolUseId: string;
|
|
122
|
+
action: 'allow' | 'block' | 'modify';
|
|
123
|
+
reason?: string }
|
|
124
|
+
| { type: 'hook'; hookType: 'stop' | 'pre_compact' | 'session_start' | 'session_end';
|
|
125
|
+
action: 'executed';
|
|
126
|
+
reason?: string }
|
|
127
|
+
|
|
128
|
+
// Hook activity state (for UI rendering)
|
|
129
|
+
| { type: 'hook_activity';
|
|
130
|
+
event: string;
|
|
131
|
+
status: 'running' | 'success' | 'error' | 'blocked';
|
|
132
|
+
icon: string;
|
|
133
|
+
toolName?: string;
|
|
134
|
+
detail?: string;
|
|
135
|
+
durationMs?: number }
|
|
136
|
+
|
|
137
|
+
// Context compaction detail (follows system.compacting)
|
|
138
|
+
| { type: 'compaction_detail';
|
|
139
|
+
reason: 'auto' | 'manual' | 'micro';
|
|
140
|
+
tokensBefore: number; tokensAfter: number;
|
|
141
|
+
messagesRemoved: number;
|
|
142
|
+
transcriptPath?: string }
|
|
143
|
+
|
|
144
|
+
// Debug catch-all
|
|
145
|
+
| { type: 'debug'; category: string; message: string;
|
|
146
|
+
data?: Record<string, unknown> }
|
|
147
|
+
|
|
148
|
+
// Token usage (streaming)
|
|
149
|
+
| { type: 'streaming_usage'; usage: TokenUsage }
|
|
150
|
+
|
|
151
|
+
// Media output (unified: images, audio, video, files)
|
|
152
|
+
| { type: 'media_output';
|
|
153
|
+
kind: ContentKind;
|
|
154
|
+
mimeType: string;
|
|
155
|
+
path: string;
|
|
156
|
+
data?: string;
|
|
157
|
+
role: 'assistant' | 'user';
|
|
158
|
+
source?: string;
|
|
159
|
+
meta?: MediaOutputMeta }
|
|
160
|
+
|
|
161
|
+
// Frontend tool awaiting result (AG-UI frontend-defined tools)
|
|
162
|
+
| { type: 'awaiting_frontend_tool'; toolCallId: string; toolName: string;
|
|
163
|
+
args: Record<string, unknown> }
|
|
164
|
+
|
|
165
|
+
// World control (time & weather)
|
|
166
|
+
| { type: 'world_control'; target: 'time'; action: 'set' | 'pause' | 'resume'; hour?: number }
|
|
167
|
+
| { type: 'world_control'; target: 'weather'; action: 'set' | 'reset'; weather?: string }
|
|
168
|
+
|
|
169
|
+
// Error
|
|
170
|
+
| { type: 'error'; message: string; recoverable: boolean };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// @desc Public entry — re-exports all contract types
|
|
2
|
+
//
|
|
3
|
+
// ─── Architecture ───
|
|
4
|
+
//
|
|
5
|
+
// contracts/ <-- 你在这里:所有层的唯一类型真理之源
|
|
6
|
+
// │
|
|
7
|
+
// ├── media.ts 多模态内容块 (text/image/audio/video/file)
|
|
8
|
+
// ├── agent-state.ts Agent 状态机 & 递归快照树
|
|
9
|
+
// ├── events.ts AgentEvent 联合类型 (OpenClaw 核心对外契约)
|
|
10
|
+
// ├── registry.ts 中央注册表 (session ↔ project 关联)
|
|
11
|
+
// └── index.ts 本文件:公共导出入口
|
|
12
|
+
//
|
|
13
|
+
// ─── 消费者 ───
|
|
14
|
+
//
|
|
15
|
+
// CLI 层 → events.ts + agent-state.ts + media.ts
|
|
16
|
+
// OpenClaw 层 → events.ts + agent-state.ts (src/core/types.ts re-export)
|
|
17
|
+
//
|
|
18
|
+
// ─── 已移除 (Phase 0 清理, 2026-03) ───
|
|
19
|
+
//
|
|
20
|
+
// messages.ts — WS 新格式类型,从未被消费,已删除
|
|
21
|
+
// envelope.ts — 传输信封类型,从未被消费,已删除
|
|
22
|
+
//
|
|
23
|
+
|
|
24
|
+
// Media
|
|
25
|
+
export type {
|
|
26
|
+
ContentKind,
|
|
27
|
+
InlineSource,
|
|
28
|
+
UrlSource,
|
|
29
|
+
StreamSource,
|
|
30
|
+
TextContent,
|
|
31
|
+
ImageContent,
|
|
32
|
+
AudioContent,
|
|
33
|
+
VideoStreamSource,
|
|
34
|
+
VideoContent,
|
|
35
|
+
FileContent,
|
|
36
|
+
MediaContent,
|
|
37
|
+
MultimodalBody,
|
|
38
|
+
} from './media.js';
|
|
39
|
+
|
|
40
|
+
// Agent state
|
|
41
|
+
export type {
|
|
42
|
+
AgentPhase,
|
|
43
|
+
AgentActivity,
|
|
44
|
+
AgentResources,
|
|
45
|
+
AgentSnapStats,
|
|
46
|
+
AgentStateSnapshot,
|
|
47
|
+
SessionStatus,
|
|
48
|
+
SessionState,
|
|
49
|
+
} from './agent-state.js';
|
|
50
|
+
|
|
51
|
+
// Chat
|
|
52
|
+
export type {
|
|
53
|
+
ChatMediaType,
|
|
54
|
+
ChatItemKind,
|
|
55
|
+
ChatItem,
|
|
56
|
+
ChatTextItem,
|
|
57
|
+
ChatMediaItem,
|
|
58
|
+
ChatToolItem,
|
|
59
|
+
ChatStatusItem,
|
|
60
|
+
ChatItemHistoryResult,
|
|
61
|
+
} from './chat.js';
|
|
62
|
+
|
|
63
|
+
// Events
|
|
64
|
+
export type {
|
|
65
|
+
AgentStats,
|
|
66
|
+
ToolResultMeta,
|
|
67
|
+
TokenUsage,
|
|
68
|
+
ASRSegment,
|
|
69
|
+
AgentEvent,
|
|
70
|
+
MediaOutputMeta,
|
|
71
|
+
} from './events.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// @desc Multimodal content types: text, image, audio, video, file
|
|
2
|
+
//
|
|
3
|
+
// source 使用判别联合 (type: 'base64' | 'url' | 'stream'), 与传输层解耦
|
|
4
|
+
// 同一个 AudioContent 可以在 WS JSON (base64) 或 HTTP 上传 (url) 中使用
|
|
5
|
+
//
|
|
6
|
+
// 迁移注意:
|
|
7
|
+
// - VideoContent / VideoStreamSource 已定义但尚无实现
|
|
8
|
+
// - MediaPipeline TTS 输出已使用 AudioContent + InlineSource (base64)
|
|
9
|
+
// - 旧的 ContentBlock (src/core/types.ts) 是 LLM 内部格式, 与本文件的
|
|
10
|
+
// MediaContent 是不同抽象层: ContentBlock = LLM API, MediaContent = 传输契约
|
|
11
|
+
|
|
12
|
+
export type ContentKind = 'text' | 'image' | 'audio' | 'video' | 'file';
|
|
13
|
+
|
|
14
|
+
// ── Source discriminated union (transport-agnostic) ──
|
|
15
|
+
|
|
16
|
+
export type InlineSource = { type: 'base64'; data: string };
|
|
17
|
+
export type UrlSource = { type: 'url'; url: string };
|
|
18
|
+
export type StreamSource = { type: 'stream'; streamId: string };
|
|
19
|
+
|
|
20
|
+
// ── Content blocks ──
|
|
21
|
+
|
|
22
|
+
export interface TextContent {
|
|
23
|
+
kind: 'text';
|
|
24
|
+
text: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ImageContent {
|
|
28
|
+
kind: 'image';
|
|
29
|
+
mimeType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';
|
|
30
|
+
source: InlineSource | UrlSource;
|
|
31
|
+
width?: number;
|
|
32
|
+
height?: number;
|
|
33
|
+
alt?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface AudioContent {
|
|
37
|
+
kind: 'audio';
|
|
38
|
+
format: 'mp3' | 'pcm' | 'wav' | 'webm' | 'opus';
|
|
39
|
+
source: InlineSource | UrlSource | StreamSource;
|
|
40
|
+
sampleRate?: number;
|
|
41
|
+
channels?: number;
|
|
42
|
+
durationMs?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type VideoStreamSource = {
|
|
46
|
+
type: 'stream';
|
|
47
|
+
streamId: string;
|
|
48
|
+
protocol: 'webrtc' | 'hls' | 'ws-binary';
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export interface VideoContent {
|
|
52
|
+
kind: 'video';
|
|
53
|
+
format: 'mp4' | 'webm';
|
|
54
|
+
source: InlineSource | UrlSource | VideoStreamSource;
|
|
55
|
+
mimeType?: string;
|
|
56
|
+
width?: number;
|
|
57
|
+
height?: number;
|
|
58
|
+
durationMs?: number;
|
|
59
|
+
thumbnail?: ImageContent;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface FileContent {
|
|
63
|
+
kind: 'file';
|
|
64
|
+
filename: string;
|
|
65
|
+
mimeType: string;
|
|
66
|
+
source: InlineSource | UrlSource;
|
|
67
|
+
sizeBytes?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type MediaContent =
|
|
71
|
+
| TextContent
|
|
72
|
+
| ImageContent
|
|
73
|
+
| AudioContent
|
|
74
|
+
| VideoContent
|
|
75
|
+
| FileContent;
|
|
76
|
+
|
|
77
|
+
export type MultimodalBody = MediaContent[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// @desc Central registry types for session ↔ project associations
|
|
2
|
+
//
|
|
3
|
+
// registry.json lives in .openclaw/ and tracks all projects (games + workspace apps).
|
|
4
|
+
// It is the single source of truth for:
|
|
5
|
+
// - Server API endpoints (/projects, /sessions enrichment)
|
|
6
|
+
// - Frontend project listing and session switching
|
|
7
|
+
// - Future network service mapping (game sharing platform)
|
|
8
|
+
//
|
|
9
|
+
// Projects are keyed by their directory name (which already contains timestamp + random suffix).
|
|
10
|
+
|
|
11
|
+
export type ProjectType = 'game' | 'app';
|
|
12
|
+
export type ProjectStatus = 'active' | 'archived' | 'error';
|
|
13
|
+
|
|
14
|
+
export interface ProjectEntry {
|
|
15
|
+
type: ProjectType;
|
|
16
|
+
name: string;
|
|
17
|
+
dir: string;
|
|
18
|
+
template?: string;
|
|
19
|
+
engine?: string;
|
|
20
|
+
port?: number;
|
|
21
|
+
vite: boolean;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
sessionId: string;
|
|
24
|
+
status: ProjectStatus;
|
|
25
|
+
description?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Registry {
|
|
29
|
+
version: number;
|
|
30
|
+
projects: Record<string, ProjectEntry>;
|
|
31
|
+
activeGameDir?: string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Plugin 层架构指南
|
|
2
|
+
|
|
3
|
+
> OpenClaw 插件的 Node.js 端:Hook 监听、WebSocket 广播、AI 工具、编辑器 API、居民 Agent 管理。
|
|
4
|
+
|
|
5
|
+
## 目录结构
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/plugin/
|
|
9
|
+
├── channel.ts # ChannelPlugin 实现(startAccount启动WS/注册回调)
|
|
10
|
+
├── hook-translator.ts # 纯函数:OpenClaw Hook名 → AgentEvent
|
|
11
|
+
├── ws-server.ts # WebSocket服务器 + 会话绑定 + 消息路由
|
|
12
|
+
├── tools.ts # AI工具注册(11个工具)
|
|
13
|
+
├── auto-config.ts # 零配置:自动创建town-steward Agent + Binding
|
|
14
|
+
├── plan-manager.ts # 多Agent计划状态机(步骤/批次/enriched task)
|
|
15
|
+
├── citizen-agent-manager.ts # 独立居民Agent CRUD(写openclaw.json)
|
|
16
|
+
├── citizen-chat-router.ts # 用户↔居民Agent消息路由
|
|
17
|
+
├── citizen-workshop-manager.ts # 居民工坊配置持久化(citizen-config.json)
|
|
18
|
+
├── editor-serve.ts # 编辑器HTTP API(1176行,资产/工坊/发布)
|
|
19
|
+
├── llm-agent-proxy.ts # LLM代理(走OpenClaw embedded agent runtime,2并发+10队列)
|
|
20
|
+
├── session-history.ts # 跨会话聊天历史加载(管家+居民)
|
|
21
|
+
├── soul-prompt-template.ts # 灵魂文件AI生成模板
|
|
22
|
+
├── outbound-adapter.ts # 出站适配(text→AgentEvent, media→deliverable_card)
|
|
23
|
+
├── subagent-tracker.ts # 子Agent会话日志实时转发
|
|
24
|
+
├── session-log-watcher.ts # JSONL日志增量读取(300ms轮询)
|
|
25
|
+
├── custom-asset-manager.ts # 自定义GLB资产管理(最多20个,10MB限制)
|
|
26
|
+
├── town-session.ts # Session ID标准化/解析
|
|
27
|
+
└── runtime.ts # Runtime注入(getter/setter)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 核心数据流
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
index.ts register(api)
|
|
34
|
+
├─ api.registerChannel(agentTownPlugin) → channel.ts
|
|
35
|
+
├─ registerHooks(api) → 监听8种Hook
|
|
36
|
+
├─ api.registerTool(createTownTools()) → tools.ts
|
|
37
|
+
├─ ensureTownAgentConfig() → auto-config.ts
|
|
38
|
+
├─ subagent_spawning hook → town-souls.ts 注入灵魂
|
|
39
|
+
└─ api.registerService("agentshire-frontend") → HTTP服务器(:55210)
|
|
40
|
+
└─ handleEditorRequest() → editor-serve.ts
|
|
41
|
+
|
|
42
|
+
Hook事件流:
|
|
43
|
+
OpenClaw Hook → isStewardDirect() 判断
|
|
44
|
+
├─ 管家直接事件 → dispatchSteward() → hookToAgentEvent() → broadcastAgentEvent()
|
|
45
|
+
└─ 居民Agent事件 → dispatchCitizen() → 附加npcId → broadcastAgentEvent()
|
|
46
|
+
|
|
47
|
+
子Agent生命周期:
|
|
48
|
+
subagent_spawned → pendingSpawnTasks缓存task → onSubagentSpawned()
|
|
49
|
+
→ SessionLogWatcher监听JSONL → broadcastAgentEvent(子事件)
|
|
50
|
+
subagent_ended → onSubagentEnded() → plan-manager.onAgentCompleted()
|
|
51
|
+
→ 批次完成?→ scheduleNudge(10s后提醒next_step)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Hook 翻译表(hook-translator.ts)
|
|
55
|
+
|
|
56
|
+
| Hook名 | AgentEvent类型 | 备注 |
|
|
57
|
+
|--------|---------------|------|
|
|
58
|
+
| `before_agent_start` | `system.init` | sessionId/model/persona |
|
|
59
|
+
| `agent_end` | `turn_end` (+可选error) | usage/toolCalls/durationMs |
|
|
60
|
+
| `llm_input` | `thinking_delta` | 提取thinking/reasoning字段 |
|
|
61
|
+
| `llm_output` | `text` | assistantTexts最后一项 |
|
|
62
|
+
| `before_tool_call` | `tool_use` | name/input |
|
|
63
|
+
| `after_tool_call` | `tool_result` (+可选media_output) | 自动检测媒体文件 |
|
|
64
|
+
| `subagent_spawned` | `sub_agent.started` | label/task/agentId |
|
|
65
|
+
| `subagent_ended` | `sub_agent.done` | outcome→status映射 |
|
|
66
|
+
| `message_sending` | `text` | 发送中的消息 |
|
|
67
|
+
| `session_end` | `system.done` | — |
|
|
68
|
+
|
|
69
|
+
## AI 工具(tools.ts)
|
|
70
|
+
|
|
71
|
+
| 工具名 | 功能 | 发出的事件 |
|
|
72
|
+
|--------|------|-----------|
|
|
73
|
+
| `town_announce` | 广播消息 | `text` |
|
|
74
|
+
| `town_spawn_npc` | 生成NPC | `sub_agent.started`(模拟) |
|
|
75
|
+
| `town_effect` | 触发VFX | `fx` |
|
|
76
|
+
| `town_set_time` | 控制时钟 | `world_control.time` |
|
|
77
|
+
| `town_set_weather` | 控制天气 | `world_control.weather` |
|
|
78
|
+
| `town_status` | 查看状态 | —(返回文本) |
|
|
79
|
+
| `register_project` | 注册项目 | — |
|
|
80
|
+
| `create_project` | 创建项目目录 | — |
|
|
81
|
+
| `create_plan` | 创建多Agent计划 | — |
|
|
82
|
+
| `next_step` | 获取下一步指令 | — |
|
|
83
|
+
| `project_complete` | 宣布完成 | `tool_result`(触发publishing) |
|
|
84
|
+
|
|
85
|
+
## plan-manager:多 Agent 计划编排
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
create_plan(steps) → 验证(多Agent步骤必须有files且不重叠)
|
|
89
|
+
→ 存储计划(追加隐含_complete步骤)
|
|
90
|
+
|
|
91
|
+
next_step() → 生成当前进度报告 + 下一批spawn指令
|
|
92
|
+
→ buildEnrichedTask(角色人设+项目目录+文件边界+通用规则)
|
|
93
|
+
|
|
94
|
+
onAgentStarted(label) → 标记agent为active
|
|
95
|
+
onAgentCompleted(label, success) → 标记完成 → isCurrentBatchDone()?
|
|
96
|
+
→ 是 → index.ts scheduleNudge(10s后提醒管家)
|
|
97
|
+
|
|
98
|
+
支持 parallel 标记:步骤可与前一步并行执行
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## editor-serve:编辑器 HTTP API
|
|
102
|
+
|
|
103
|
+
路由结构(全部走 `handleEditorRequest()`):
|
|
104
|
+
|
|
105
|
+
| 路径前缀 | 功能 |
|
|
106
|
+
|---------|------|
|
|
107
|
+
| `/ext-assets/*` | 角色/地图资产静态文件 |
|
|
108
|
+
| `/citizen-workshop/avatars/*` | 用户上传头像 |
|
|
109
|
+
| `/custom-assets/_api/{action}` | 自定义资产CRUD + GLB优化(@gltf-transform) |
|
|
110
|
+
| `/custom-assets/*` | 自定义资产静态文件 |
|
|
111
|
+
| `/citizen-workshop/_api/load` | 加载工坊草稿配置 |
|
|
112
|
+
| `/citizen-workshop/_api/save` | 保存工坊草稿 |
|
|
113
|
+
| `/citizen-workshop/_api/publish` | **发布**:changeset检测→Agent CRUD→同步town-defaults |
|
|
114
|
+
| `/citizen-workshop/_api/load-published` | 加载已发布配置 |
|
|
115
|
+
| `/citizen-workshop/_api/generate-soul` | AI生成灵魂文件 |
|
|
116
|
+
| `/citizen-workshop/_api/upload-avatar` | 上传头像 |
|
|
117
|
+
| `/citizen-workshop/_api/upload-anim` | 上传动画文件 |
|
|
118
|
+
| `/citizen-workshop/_api/agents` | 查询Agent列表 |
|
|
119
|
+
| `/citizen-workshop/_api/buildings` | 查询建筑列表 |
|
|
120
|
+
| `/citizen-workshop/_api/media` | 媒体文件代理 |
|
|
121
|
+
|
|
122
|
+
**发布流程**:
|
|
123
|
+
1. 构建 `PublishedCitizenConfig`(bake所有URL)
|
|
124
|
+
2. 比较新旧配置,检测 changeset(create/disable/update_soul)
|
|
125
|
+
3. 调用 `citizen-agent-manager.applyAgentChanges()` 执行Agent CRUD
|
|
126
|
+
4. 管家人设变更时更新管家SOUL.md
|
|
127
|
+
5. 同步 `town-defaults.json`
|
|
128
|
+
|
|
129
|
+
## citizen-agent-manager:独立居民 Agent
|
|
130
|
+
|
|
131
|
+
居民不只是子Agent(工作时),也可以是独立Agent(有自己的工作区和会话)。
|
|
132
|
+
|
|
133
|
+
| 操作 | 行为 |
|
|
134
|
+
|------|------|
|
|
135
|
+
| `create` | 创建 `~/.openclaw/workspace-citizen-{id}/` + SOUL.md + 注册到openclaw.json |
|
|
136
|
+
| `disable` | 从 openclaw.json agents.list 中移除 |
|
|
137
|
+
| `update_soul` | 更新 SOUL.md 文件 |
|
|
138
|
+
|
|
139
|
+
`citizen-chat-router.ts` 路由用户消息到居民Agent的独立会话(SessionKey = `agent:{agentId}:main`)。
|
|
140
|
+
|
|
141
|
+
## WebSocket 协议(ws-server.ts)
|
|
142
|
+
|
|
143
|
+
**浏览器 → 服务端**:
|
|
144
|
+
|
|
145
|
+
| 消息类型 | 说明 |
|
|
146
|
+
|---------|------|
|
|
147
|
+
| `town_session_init` | 绑定会话,回复 `town_session_bound` + `work_snapshot` |
|
|
148
|
+
| `chat` | 用户消息 → onChat回调 → 管家Agent |
|
|
149
|
+
| `multimodal` | 多模态消息(图片/视频/音频) |
|
|
150
|
+
| `citizen_chat` | 居民聊天 → citizen-chat-router |
|
|
151
|
+
| `implicit_chat_request` | 前端隐式LLM请求 → llm-agent-proxy |
|
|
152
|
+
| `chat_history_request` | 请求历史消息 → session-history |
|
|
153
|
+
| `command` | 命令消息(`/xxx`) |
|
|
154
|
+
| `abort` | 中止当前请求 |
|
|
155
|
+
|
|
156
|
+
**服务端 → 浏览器**:
|
|
157
|
+
|
|
158
|
+
| 消息类型 | 说明 |
|
|
159
|
+
|---------|------|
|
|
160
|
+
| `agent_event` | 主事件流(AgentEvent) |
|
|
161
|
+
| `work_snapshot` | 工作状态快照(子Agent列表+活动日志) |
|
|
162
|
+
| `chat_new_messages` | 新消息增量推送 |
|
|
163
|
+
| `chat_history` | 历史消息(含分页cursor) |
|
|
164
|
+
| `implicit_chat_response` | 隐式LLM响应 |
|
|
165
|
+
|
|
166
|
+
## Nudge 机制(index.ts)
|
|
167
|
+
|
|
168
|
+
当一批子Agent全部完成(`isCurrentBatchDone()`)但管家 10 秒内未响应时,自动发送系统通知"请调用 next_step()"。管家恢复活动(`before_agent_start` / `before_tool_call` / `llm_input`)时自动取消。
|
|
169
|
+
|
|
170
|
+
## 常见改动
|
|
171
|
+
|
|
172
|
+
| 要做的事 | 改哪里 |
|
|
173
|
+
|---------|--------|
|
|
174
|
+
| 新增Hook→AgentEvent映射 | `hook-translator.ts` |
|
|
175
|
+
| 新增AI工具 | `tools.ts` |
|
|
176
|
+
| 修改计划编排/enriched task | `plan-manager.ts` |
|
|
177
|
+
| 修改编辑器API | `editor-serve.ts` |
|
|
178
|
+
| 修改居民Agent创建/销毁 | `citizen-agent-manager.ts` |
|
|
179
|
+
| 修改居民聊天路由 | `citizen-chat-router.ts` |
|
|
180
|
+
| 修改隐式LLM调用格式 | `llm-agent-proxy.ts` |
|
|
181
|
+
| 修改聊天历史解析 | `session-history.ts` |
|
|
182
|
+
| 修改灵魂文件生成模板 | `soul-prompt-template.ts` |
|
|
183
|
+
| 修改WS消息路由 | `ws-server.ts` |
|
|
184
|
+
| 修改出站消息格式 | `outbound-adapter.ts` |
|
|
185
|
+
| 修改自定义资产限制 | `custom-asset-manager.ts` |
|
|
186
|
+
|
|
187
|
+
## 测试
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
src/plugin/__tests__/
|
|
191
|
+
└── hook-translator.test.ts # Hook名 → AgentEvent 映射
|
|
192
|
+
```
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs'
|
|
4
|
+
|
|
5
|
+
const TEST_PLUGIN_DIR = join(import.meta.dirname, '__fixtures_megapack__')
|
|
6
|
+
const MAP1_DIR = join(TEST_PLUGIN_DIR, 'assets', 'Map_1')
|
|
7
|
+
|
|
8
|
+
function createMockRes() {
|
|
9
|
+
const res: any = {
|
|
10
|
+
_status: 0,
|
|
11
|
+
_headers: {} as Record<string, string>,
|
|
12
|
+
_body: null as Buffer | string | null,
|
|
13
|
+
writeHead(status: number, headers?: Record<string, string>) {
|
|
14
|
+
res._status = status
|
|
15
|
+
if (headers) Object.assign(res._headers, headers)
|
|
16
|
+
},
|
|
17
|
+
end(body?: any) {
|
|
18
|
+
res._body = body ?? null
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
return res
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function createMockReq(method: string, url: string): any {
|
|
25
|
+
return { method, url }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('editor-serve megapack route', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
mkdirSync(join(MAP1_DIR, 'Buildings', 'Building 1'), { recursive: true })
|
|
31
|
+
writeFileSync(
|
|
32
|
+
join(MAP1_DIR, 'Buildings', 'Building 1', 'Building_1.gltf'),
|
|
33
|
+
'{"asset":{"version":"2.0"}}',
|
|
34
|
+
)
|
|
35
|
+
writeFileSync(
|
|
36
|
+
join(MAP1_DIR, 'Buildings', 'Building 1', 'Building_1.bin'),
|
|
37
|
+
Buffer.from([0x00, 0x01, 0x02]),
|
|
38
|
+
)
|
|
39
|
+
mkdirSync(join(MAP1_DIR, 'Roads'), { recursive: true })
|
|
40
|
+
writeFileSync(
|
|
41
|
+
join(MAP1_DIR, 'Roads', 'Road_Straight.gltf'),
|
|
42
|
+
'{"asset":{"version":"2.0"}}',
|
|
43
|
+
)
|
|
44
|
+
mkdirSync(join(TEST_PLUGIN_DIR, 'town-data', 'custom-assets', 'models'), { recursive: true })
|
|
45
|
+
mkdirSync(join(TEST_PLUGIN_DIR, 'town-data', 'custom-assets', 'characters'), { recursive: true })
|
|
46
|
+
mkdirSync(join(TEST_PLUGIN_DIR, 'town-data', 'custom-assets', 'animations'), { recursive: true })
|
|
47
|
+
mkdirSync(join(TEST_PLUGIN_DIR, 'town-data', 'souls'), { recursive: true })
|
|
48
|
+
mkdirSync(join(TEST_PLUGIN_DIR, 'town-souls'), { recursive: true })
|
|
49
|
+
mkdirSync(join(TEST_PLUGIN_DIR, 'town-data', 'citizen-workshop', 'avatars'), { recursive: true })
|
|
50
|
+
if (!existsSync(join(TEST_PLUGIN_DIR, 'town-data', 'custom-assets', '_catalog.json'))) {
|
|
51
|
+
writeFileSync(
|
|
52
|
+
join(TEST_PLUGIN_DIR, 'town-data', 'custom-assets', '_catalog.json'),
|
|
53
|
+
'{"version":1,"assets":[]}',
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
rmSync(TEST_PLUGIN_DIR, { recursive: true, force: true })
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
async function handle(method: string, url: string) {
|
|
63
|
+
const { handleEditorRequest } = await import('../editor-serve.js')
|
|
64
|
+
const req = createMockReq(method, url)
|
|
65
|
+
const res = createMockRes()
|
|
66
|
+
const handled = await handleEditorRequest(req, res, TEST_PLUGIN_DIR)
|
|
67
|
+
return { handled, res }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
it('serves megapack gltf file when assets exist', async () => {
|
|
71
|
+
const { handled, res } = await handle(
|
|
72
|
+
'GET',
|
|
73
|
+
'/assets/models/megapack/gltf/Buildings/Building%201/Building_1.gltf',
|
|
74
|
+
)
|
|
75
|
+
expect(handled).toBe(true)
|
|
76
|
+
expect(res._status).toBe(200)
|
|
77
|
+
expect(res._headers['Content-Type']).toContain('gltf')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('serves megapack bin file when assets exist', async () => {
|
|
81
|
+
const { handled, res } = await handle(
|
|
82
|
+
'GET',
|
|
83
|
+
'/assets/models/megapack/gltf/Buildings/Building%201/Building_1.bin',
|
|
84
|
+
)
|
|
85
|
+
expect(handled).toBe(true)
|
|
86
|
+
expect(res._status).toBe(200)
|
|
87
|
+
expect(res._headers['Content-Type']).toBe('application/octet-stream')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('returns 404 for non-existent megapack file', async () => {
|
|
91
|
+
const { handled, res } = await handle(
|
|
92
|
+
'GET',
|
|
93
|
+
'/assets/models/megapack/gltf/Buildings/NoSuch/model.gltf',
|
|
94
|
+
)
|
|
95
|
+
expect(handled).toBe(true)
|
|
96
|
+
expect(res._status).toBe(404)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('correctly decodes URL-encoded paths with spaces', async () => {
|
|
100
|
+
const { handled, res } = await handle(
|
|
101
|
+
'GET',
|
|
102
|
+
'/assets/models/megapack/gltf/Buildings/Building%201/Building_1.gltf',
|
|
103
|
+
)
|
|
104
|
+
expect(handled).toBe(true)
|
|
105
|
+
expect(res._status).toBe(200)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('blocks path traversal attempts', async () => {
|
|
109
|
+
const { handled, res } = await handle(
|
|
110
|
+
'GET',
|
|
111
|
+
'/assets/models/megapack/gltf/../../../../../../etc/passwd',
|
|
112
|
+
)
|
|
113
|
+
expect(handled).toBe(true)
|
|
114
|
+
expect(res._status).toBe(404)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('does not intercept non-megapack asset requests', async () => {
|
|
118
|
+
const { handled } = await handle(
|
|
119
|
+
'GET',
|
|
120
|
+
'/assets/models/buildings/building_A.gltf',
|
|
121
|
+
)
|
|
122
|
+
expect(handled).toBe(false)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('does not intercept ext-assets requests (existing route)', async () => {
|
|
126
|
+
const { handled, res } = await handle(
|
|
127
|
+
'GET',
|
|
128
|
+
'/ext-assets/Characters_1/gLTF/Animations/Animations.glb',
|
|
129
|
+
)
|
|
130
|
+
expect(handled).toBe(true)
|
|
131
|
+
expect(res._status).toBe(404)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('serves simple path without URL encoding', async () => {
|
|
135
|
+
const { handled, res } = await handle(
|
|
136
|
+
'GET',
|
|
137
|
+
'/assets/models/megapack/gltf/Roads/Road_Straight.gltf',
|
|
138
|
+
)
|
|
139
|
+
expect(handled).toBe(true)
|
|
140
|
+
expect(res._status).toBe(200)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('sets cache header on megapack responses', async () => {
|
|
144
|
+
const { res } = await handle(
|
|
145
|
+
'GET',
|
|
146
|
+
'/assets/models/megapack/gltf/Roads/Road_Straight.gltf',
|
|
147
|
+
)
|
|
148
|
+
expect(res._headers['Cache-Control']).toBe('public, max-age=86400')
|
|
149
|
+
})
|
|
150
|
+
})
|