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,399 @@
|
|
|
1
|
+
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import { getTownRuntime } from "./runtime.js";
|
|
3
|
+
import { broadcastAgentEvent } from "./ws-server.js";
|
|
4
|
+
import { createOutboundAdapter } from "./outbound-adapter.js";
|
|
5
|
+
import { createTownSessionKey, sanitizeTownSessionId } from "./town-session.js";
|
|
6
|
+
|
|
7
|
+
const CHANNEL_ID = "agentshire";
|
|
8
|
+
const DEBUG = process.env.AGENTSHIRE_DEBUG === "1";
|
|
9
|
+
|
|
10
|
+
let _channelCtx: { rt: ReturnType<typeof getTownRuntime>; cfg: Record<string, unknown>; accountId: string } | null = null;
|
|
11
|
+
|
|
12
|
+
export async function sendNudgeMessage(townSessionId: string, body: string): Promise<void> {
|
|
13
|
+
if (!_channelCtx) {
|
|
14
|
+
console.warn('[agentshire] sendNudgeMessage: channel not started yet');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
await dispatchTownMessage({ ..._channelCtx, townSessionId, body });
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error('[agentshire] sendNudgeMessage error:', err);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ResolvedTownAccount {
|
|
25
|
+
accountId: string;
|
|
26
|
+
wsPort: number;
|
|
27
|
+
townPort: number;
|
|
28
|
+
autoLaunch: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveAccount(
|
|
32
|
+
cfg: Record<string, unknown>,
|
|
33
|
+
accountId: string,
|
|
34
|
+
): ResolvedTownAccount {
|
|
35
|
+
interface ChannelConfig {
|
|
36
|
+
channels?: Record<string, { wsPort?: number; townPort?: number; autoLaunch?: boolean }>;
|
|
37
|
+
}
|
|
38
|
+
const channelCfg = (cfg as ChannelConfig)?.channels?.[CHANNEL_ID] ?? {};
|
|
39
|
+
return {
|
|
40
|
+
accountId,
|
|
41
|
+
wsPort: channelCfg.wsPort ?? 55211,
|
|
42
|
+
townPort: channelCfg.townPort ?? 55210,
|
|
43
|
+
autoLaunch: channelCfg.autoLaunch ?? true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function waitUntilAbort(signal: AbortSignal): Promise<void> {
|
|
48
|
+
return new Promise<void>((resolve) => {
|
|
49
|
+
if (signal.aborted) {
|
|
50
|
+
resolve();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
signal.addEventListener("abort", () => resolve(), { once: true });
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function dispatchTownMessage(params: {
|
|
58
|
+
rt: ReturnType<typeof getTownRuntime>;
|
|
59
|
+
cfg: Record<string, unknown>;
|
|
60
|
+
accountId: string;
|
|
61
|
+
townSessionId: string;
|
|
62
|
+
body: string;
|
|
63
|
+
mediaPaths?: string[];
|
|
64
|
+
}) {
|
|
65
|
+
const { rt, cfg, accountId, townSessionId, body, mediaPaths } = params;
|
|
66
|
+
const sessionKey = createTownSessionKey(accountId, townSessionId);
|
|
67
|
+
|
|
68
|
+
const msgCtx = rt.channel.reply.finalizeInboundContext({
|
|
69
|
+
Body: body,
|
|
70
|
+
RawBody: body,
|
|
71
|
+
CommandBody: body,
|
|
72
|
+
From: `${CHANNEL_ID}:user`,
|
|
73
|
+
To: `${CHANNEL_ID}:steward`,
|
|
74
|
+
SessionKey: sessionKey,
|
|
75
|
+
AccountId: accountId,
|
|
76
|
+
OriginatingChannel: CHANNEL_ID,
|
|
77
|
+
ChatType: "direct",
|
|
78
|
+
SenderId: "user",
|
|
79
|
+
Provider: CHANNEL_ID,
|
|
80
|
+
Surface: CHANNEL_ID,
|
|
81
|
+
...(mediaPaths?.length ? { MediaPaths: mediaPaths } : {}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
85
|
+
ctx: msgCtx,
|
|
86
|
+
cfg,
|
|
87
|
+
dispatcherOptions: {
|
|
88
|
+
deliver: async (payload: any) => {
|
|
89
|
+
const replyText = payload?.text ?? payload?.body;
|
|
90
|
+
if (replyText) {
|
|
91
|
+
broadcastAgentEvent({ type: "text", content: replyText }, townSessionId);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const { outbound: townOutbound, messaging: townMessaging } = createOutboundAdapter();
|
|
99
|
+
|
|
100
|
+
export const agentTownPlugin: ChannelPlugin<ResolvedTownAccount> = {
|
|
101
|
+
id: CHANNEL_ID,
|
|
102
|
+
|
|
103
|
+
meta: {
|
|
104
|
+
id: CHANNEL_ID,
|
|
105
|
+
label: "Agentshire",
|
|
106
|
+
selectionLabel: "Agentshire (3D Visualization)",
|
|
107
|
+
docsPath: "/channels/agentshire",
|
|
108
|
+
docsLabel: "agentshire",
|
|
109
|
+
blurb:
|
|
110
|
+
"Visualize AI agents as NPCs in an interactive 3D low-poly town. " +
|
|
111
|
+
"Watch them think, code, collaborate, and celebrate in real-time.",
|
|
112
|
+
order: 100,
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
capabilities: {
|
|
116
|
+
chatTypes: ["direct"],
|
|
117
|
+
media: true,
|
|
118
|
+
reactions: false,
|
|
119
|
+
edit: false,
|
|
120
|
+
unsend: false,
|
|
121
|
+
reply: false,
|
|
122
|
+
effects: true,
|
|
123
|
+
threads: false,
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
reload: {
|
|
127
|
+
configPrefixes: [`channels.${CHANNEL_ID}`],
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
config: {
|
|
131
|
+
listAccountIds: () => ["default"],
|
|
132
|
+
resolveAccount: (cfg: any, accountId: string) => resolveAccount(cfg, accountId),
|
|
133
|
+
defaultAccountId: () => "default",
|
|
134
|
+
isConfigured: () => true,
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
outbound: townOutbound,
|
|
138
|
+
|
|
139
|
+
messaging: townMessaging,
|
|
140
|
+
|
|
141
|
+
gateway: {
|
|
142
|
+
startAccount: async (ctx: any) => {
|
|
143
|
+
const account = ctx.account as ResolvedTownAccount;
|
|
144
|
+
const rt = getTownRuntime();
|
|
145
|
+
_channelCtx = { rt, cfg: ctx.cfg, accountId: account.accountId };
|
|
146
|
+
const { startTownWsServer } = await import("./ws-server.js");
|
|
147
|
+
const { CustomAssetManager } = await import("./custom-asset-manager.js");
|
|
148
|
+
const { join } = await import("node:path");
|
|
149
|
+
const { fileURLToPath } = await import("node:url");
|
|
150
|
+
const pluginDir = join(fileURLToPath(import.meta.url), "..", "..", "..");
|
|
151
|
+
const customAssetManager = new CustomAssetManager(pluginDir);
|
|
152
|
+
|
|
153
|
+
const { chat: llmChat } = await import("./llm-agent-proxy.js");
|
|
154
|
+
|
|
155
|
+
startTownWsServer({
|
|
156
|
+
port: account.wsPort,
|
|
157
|
+
customAssetManager,
|
|
158
|
+
onImplicitChat: async (payload) => {
|
|
159
|
+
return llmChat({
|
|
160
|
+
system: payload.system,
|
|
161
|
+
user: payload.user,
|
|
162
|
+
maxTokens: payload.maxTokens,
|
|
163
|
+
temperature: payload.temperature,
|
|
164
|
+
stop: payload.stop,
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
onChat: async ({ message, townSessionId }) => {
|
|
168
|
+
if (!message) return;
|
|
169
|
+
console.log(
|
|
170
|
+
`[agentshire] onChat received (${townSessionId}): len=${message.length}${DEBUG ? ` "${message.slice(0, 100)}"` : ""}`,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
await dispatchTownMessage({
|
|
175
|
+
rt,
|
|
176
|
+
cfg: ctx.cfg,
|
|
177
|
+
accountId: account.accountId,
|
|
178
|
+
townSessionId: sanitizeTownSessionId(townSessionId),
|
|
179
|
+
body: message,
|
|
180
|
+
});
|
|
181
|
+
} catch (err) {
|
|
182
|
+
console.error("[agentshire] onChat dispatch error:", err);
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
onMultimodal: async ({ parts, townSessionId, npcId }) => {
|
|
186
|
+
console.log(
|
|
187
|
+
`[agentshire] onMultimodal received (${townSessionId}): ${parts.length} parts${npcId ? ` npc=${npcId}` : ""}`,
|
|
188
|
+
);
|
|
189
|
+
try {
|
|
190
|
+
const textParts = parts.filter((p: any) => p.kind === 'text').map((p: any) => p.text).join(' ');
|
|
191
|
+
const mediaParts = parts.filter((p: any) => p.kind !== 'text' && typeof p.data === 'string');
|
|
192
|
+
|
|
193
|
+
const mediaPaths: string[] = [];
|
|
194
|
+
for (const part of mediaParts) {
|
|
195
|
+
try {
|
|
196
|
+
const buf = Buffer.from(part.data as string, 'base64');
|
|
197
|
+
const saved = await rt.channel.media.saveMediaBuffer(
|
|
198
|
+
buf,
|
|
199
|
+
part.mimeType ?? 'application/octet-stream',
|
|
200
|
+
undefined,
|
|
201
|
+
undefined,
|
|
202
|
+
part.fileName,
|
|
203
|
+
);
|
|
204
|
+
mediaPaths.push(saved.path);
|
|
205
|
+
} catch (err) {
|
|
206
|
+
console.warn('[agentshire] Failed to save inbound media:', (err as Error).message);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const body = textParts || (mediaPaths.length > 0 ? '[附件]' : '');
|
|
211
|
+
if (!body && mediaPaths.length === 0) return;
|
|
212
|
+
|
|
213
|
+
if (npcId) {
|
|
214
|
+
const { routeCitizenMessage } = await import("./citizen-chat-router.js");
|
|
215
|
+
await routeCitizenMessage({
|
|
216
|
+
npcId,
|
|
217
|
+
label: npcId,
|
|
218
|
+
message: body,
|
|
219
|
+
townSessionId: sanitizeTownSessionId(townSessionId),
|
|
220
|
+
accountId: account.accountId,
|
|
221
|
+
cfg: ctx.cfg,
|
|
222
|
+
mediaPaths: mediaPaths.length > 0 ? mediaPaths : undefined,
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
await dispatchTownMessage({
|
|
226
|
+
rt,
|
|
227
|
+
cfg: ctx.cfg,
|
|
228
|
+
accountId: account.accountId,
|
|
229
|
+
townSessionId: sanitizeTownSessionId(townSessionId),
|
|
230
|
+
body,
|
|
231
|
+
mediaPaths: mediaPaths.length > 0 ? mediaPaths : undefined,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error("[agentshire] onMultimodal dispatch error:", err);
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
onAction: async ({ action, townSessionId }) => {
|
|
239
|
+
console.log(
|
|
240
|
+
`[agentshire] onAction received (${townSessionId}): type=${action.type}`,
|
|
241
|
+
);
|
|
242
|
+
try {
|
|
243
|
+
if (action.type === "user_message") {
|
|
244
|
+
const text = String(action.text ?? "");
|
|
245
|
+
if (!text) return;
|
|
246
|
+
|
|
247
|
+
await dispatchTownMessage({
|
|
248
|
+
rt,
|
|
249
|
+
cfg: ctx.cfg,
|
|
250
|
+
accountId: account.accountId,
|
|
251
|
+
townSessionId: sanitizeTownSessionId(townSessionId),
|
|
252
|
+
body: text,
|
|
253
|
+
});
|
|
254
|
+
} else if (action.type === "abort_requested") {
|
|
255
|
+
rt.system.enqueueSystemEvent({ type: "abort" });
|
|
256
|
+
}
|
|
257
|
+
} catch (err) {
|
|
258
|
+
console.error("[agentshire] onAction dispatch error:", err);
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
onCitizenChat: async ({ npcId, message, townSessionId }) => {
|
|
262
|
+
console.log(
|
|
263
|
+
`[agentshire] onCitizenChat (${townSessionId}): npc=${npcId} len=${message.length}${DEBUG ? ` "${message.slice(0, 80)}"` : ""}`,
|
|
264
|
+
);
|
|
265
|
+
try {
|
|
266
|
+
const { routeCitizenMessage } = await import("./citizen-chat-router.js");
|
|
267
|
+
await routeCitizenMessage({
|
|
268
|
+
npcId,
|
|
269
|
+
label: npcId,
|
|
270
|
+
message,
|
|
271
|
+
townSessionId: sanitizeTownSessionId(townSessionId),
|
|
272
|
+
accountId: account.accountId,
|
|
273
|
+
cfg: ctx.cfg,
|
|
274
|
+
});
|
|
275
|
+
} catch (err) {
|
|
276
|
+
console.error("[agentshire] onCitizenChat dispatch error:", err);
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
onTopicStart: async ({ npcIds, townSessionId }) => {
|
|
280
|
+
try {
|
|
281
|
+
const { startDiscussion } = await import("./group-discussion.js");
|
|
282
|
+
const { readFileSync, existsSync } = await import("node:fs");
|
|
283
|
+
const { join } = await import("node:path");
|
|
284
|
+
const { fileURLToPath } = await import("node:url");
|
|
285
|
+
const pluginDir = join(fileURLToPath(import.meta.url), "..", "..", "..");
|
|
286
|
+
const configPath = join(pluginDir, "town-data", "citizen-config.json");
|
|
287
|
+
let participants: Array<{ npcId: string; name: string }> = [];
|
|
288
|
+
if (existsSync(configPath)) {
|
|
289
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
290
|
+
const chars: any[] = config.characters ?? [];
|
|
291
|
+
participants = npcIds
|
|
292
|
+
.map(id => {
|
|
293
|
+
const c = chars.find((ch: any) => ch.id === id && ch.agentEnabled);
|
|
294
|
+
return c ? { npcId: id, name: c.name ?? id } : null;
|
|
295
|
+
})
|
|
296
|
+
.filter(Boolean) as Array<{ npcId: string; name: string }>;
|
|
297
|
+
}
|
|
298
|
+
if (participants.length < 2) {
|
|
299
|
+
console.warn(`[agentshire] topic_start: not enough valid participants (${participants.length})`);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
startDiscussion({
|
|
303
|
+
participants,
|
|
304
|
+
townSessionId: sanitizeTownSessionId(townSessionId),
|
|
305
|
+
accountId: account.accountId,
|
|
306
|
+
cfg: ctx.cfg,
|
|
307
|
+
});
|
|
308
|
+
} catch (err) {
|
|
309
|
+
console.error("[agentshire] onTopicStart error:", err);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
onTopicMessage: async ({ npcIds: _npcIds, message, townSessionId: _townSessionId }) => {
|
|
313
|
+
try {
|
|
314
|
+
const { onUserMessage, hasActiveDiscussion } = await import("./group-discussion.js");
|
|
315
|
+
if (!hasActiveDiscussion()) {
|
|
316
|
+
console.warn("[agentshire] topic_message received but no active discussion");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
onUserMessage(message);
|
|
320
|
+
} catch (err) {
|
|
321
|
+
console.error("[agentshire] onTopicMessage error:", err);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
onTopicEnd: async () => {
|
|
325
|
+
try {
|
|
326
|
+
const { endDiscussion } = await import("./group-discussion.js");
|
|
327
|
+
endDiscussion();
|
|
328
|
+
} catch (err) {
|
|
329
|
+
console.error("[agentshire] onTopicEnd error:", err);
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const townUrl = `http://localhost:${account.townPort}?ws=ws://localhost:${account.wsPort}`;
|
|
335
|
+
const editorUrl = `http://localhost:${account.townPort}/editor.html`;
|
|
336
|
+
const workshopUrl = `http://localhost:${account.townPort}/citizen-editor.html`;
|
|
337
|
+
console.log([
|
|
338
|
+
"",
|
|
339
|
+
" ┌─────────────────────────────────────────────────────────────────┐",
|
|
340
|
+
" │ 🏘️ Agentshire v2026.4.6 is live! │",
|
|
341
|
+
" │ │",
|
|
342
|
+
` │ Town: ${townUrl} │`,
|
|
343
|
+
` │ Editor: ${editorUrl} │`,
|
|
344
|
+
` │ Workshop: ${workshopUrl} │`,
|
|
345
|
+
" │ │",
|
|
346
|
+
" │ Click a link above or paste it into your browser. │",
|
|
347
|
+
" │ To reopen later: openclaw gateway status │",
|
|
348
|
+
" └─────────────────────────────────────────────────────────────────┘",
|
|
349
|
+
"",
|
|
350
|
+
].join("\n"));
|
|
351
|
+
|
|
352
|
+
if (account.autoLaunch) {
|
|
353
|
+
try {
|
|
354
|
+
const openCmd =
|
|
355
|
+
process.platform === "darwin"
|
|
356
|
+
? "open"
|
|
357
|
+
: process.platform === "win32"
|
|
358
|
+
? "cmd"
|
|
359
|
+
: "xdg-open";
|
|
360
|
+
const openArgs =
|
|
361
|
+
process.platform === "win32"
|
|
362
|
+
? ["/c", "start", townUrl]
|
|
363
|
+
: [townUrl];
|
|
364
|
+
let launched = false;
|
|
365
|
+
try {
|
|
366
|
+
const rt = getTownRuntime();
|
|
367
|
+
await rt.system.runCommandWithTimeout(openCmd, openArgs, { timeoutMs: 5000 });
|
|
368
|
+
launched = true;
|
|
369
|
+
} catch {}
|
|
370
|
+
if (!launched) {
|
|
371
|
+
const mod = "node:" + "child" + "_process";
|
|
372
|
+
const cp = await import(/* webpackIgnore: true */ mod);
|
|
373
|
+
cp.spawn(openCmd, openArgs, { detached: true, stdio: "ignore" }).unref();
|
|
374
|
+
}
|
|
375
|
+
} catch (err) {
|
|
376
|
+
console.warn('[agentshire] Auto-launch browser failed:', (err as Error).message)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
await waitUntilAbort(ctx.abortSignal);
|
|
381
|
+
|
|
382
|
+
const { stopTownWsServer } = await import("./ws-server.js");
|
|
383
|
+
stopTownWsServer();
|
|
384
|
+
},
|
|
385
|
+
|
|
386
|
+
stopAccount: async () => {
|
|
387
|
+
_channelCtx = null;
|
|
388
|
+
const { stopTownWsServer } = await import("./ws-server.js");
|
|
389
|
+
stopTownWsServer();
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
agentPrompt: {
|
|
394
|
+
formatHint: () =>
|
|
395
|
+
"You are connected to a 3D Agentshire. Your actions are visualized as NPC behaviors " +
|
|
396
|
+
"in a low-poly town. Users can see you thinking, coding, and collaborating. " +
|
|
397
|
+
"Use the town_announce tool to broadcast messages, and town_effect to trigger visual effects.",
|
|
398
|
+
},
|
|
399
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves local file paths into Chat-consumable asset metadata.
|
|
3
|
+
*
|
|
4
|
+
* All URL generation is centralised here so that history restore,
|
|
5
|
+
* realtime delta, and future task-card rendering use the same URLs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ChatMediaType } from "../contracts/chat.js";
|
|
9
|
+
import { existsSync, statSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { stateDir } from "./paths.js";
|
|
12
|
+
|
|
13
|
+
const IMAGE_EXTS = new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp"]);
|
|
14
|
+
const VIDEO_EXTS = new Set(["mp4", "webm", "mov", "avi", "mkv"]);
|
|
15
|
+
const AUDIO_EXTS = new Set(["mp3", "wav", "ogg", "m4a", "flac", "aac"]);
|
|
16
|
+
|
|
17
|
+
const MIME_MAP: Record<string, string> = {
|
|
18
|
+
png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg",
|
|
19
|
+
gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", bmp: "image/bmp",
|
|
20
|
+
mp4: "video/mp4", webm: "video/webm", mov: "video/quicktime", avi: "video/x-msvideo", mkv: "video/x-matroska",
|
|
21
|
+
mp3: "audio/mpeg", wav: "audio/wav", ogg: "audio/ogg", m4a: "audio/mp4", flac: "audio/flac", aac: "audio/aac",
|
|
22
|
+
pdf: "application/pdf", md: "text/markdown", txt: "text/plain",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export interface ResolvedAsset {
|
|
26
|
+
mediaType: ChatMediaType;
|
|
27
|
+
fileUrl: string;
|
|
28
|
+
fileName: string;
|
|
29
|
+
mimeType: string;
|
|
30
|
+
fileSize?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getStewardWorkspaceDir(): string {
|
|
34
|
+
return join(stateDir(), "workspace-town-steward");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ext(filePath: string): string {
|
|
38
|
+
return filePath.split(".").pop()?.toLowerCase() ?? "";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function detectMediaType(filePath: string): ChatMediaType {
|
|
42
|
+
const e = ext(filePath);
|
|
43
|
+
if (IMAGE_EXTS.has(e)) return "image";
|
|
44
|
+
if (VIDEO_EXTS.has(e)) return "video";
|
|
45
|
+
if (AUDIO_EXTS.has(e)) return "audio";
|
|
46
|
+
return "file";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function resolveMimeType(filePath: string): string {
|
|
50
|
+
return MIME_MAP[ext(filePath)] ?? "application/octet-stream";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolveAsset(filePath: string): ResolvedAsset {
|
|
54
|
+
const fileName = filePath.split("/").pop() ?? "file";
|
|
55
|
+
const mediaType = detectMediaType(filePath);
|
|
56
|
+
const mimeType = resolveMimeType(filePath);
|
|
57
|
+
|
|
58
|
+
const wsDir = getStewardWorkspaceDir();
|
|
59
|
+
let fileUrl: string;
|
|
60
|
+
if (filePath.startsWith(wsDir)) {
|
|
61
|
+
fileUrl = `/steward-workspace${filePath.slice(wsDir.length)}`;
|
|
62
|
+
} else {
|
|
63
|
+
fileUrl = `/citizen-workshop/_api/media?path=${encodeURIComponent(filePath)}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let fileSize: number | undefined;
|
|
67
|
+
try { if (existsSync(filePath)) fileSize = statSync(filePath).size; } catch {}
|
|
68
|
+
|
|
69
|
+
return { mediaType, fileUrl, fileName, mimeType, fileSize };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function isMediaExtension(filePath: string): boolean {
|
|
73
|
+
const e = ext(filePath);
|
|
74
|
+
return IMAGE_EXTS.has(e) || VIDEO_EXTS.has(e) || AUDIO_EXTS.has(e);
|
|
75
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watches a session transcript file for new entries and emits ChatItem deltas.
|
|
3
|
+
*
|
|
4
|
+
* Key design decisions:
|
|
5
|
+
* - Default: starts from file tail (no replay of old content — history handles that).
|
|
6
|
+
* - Cold-start mode (fromBeginning=true): reads from offset 0 to catch the
|
|
7
|
+
* first reply written before the watcher could start.
|
|
8
|
+
* - Reuses parseTranscriptEntry() so history and realtime are the same parser.
|
|
9
|
+
* - Does NOT touch Town's AgentEvent pipeline at all.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, openSync, closeSync, fstatSync, readSync } from "node:fs";
|
|
13
|
+
import type { ChatItem } from "../contracts/chat.js";
|
|
14
|
+
import { parseTranscriptEntry, createParserState, type TranscriptParserState } from "./session-history.js";
|
|
15
|
+
|
|
16
|
+
const POLL_MS = 300;
|
|
17
|
+
|
|
18
|
+
export class ChatSessionWatcher {
|
|
19
|
+
private filePath: string;
|
|
20
|
+
private agentId: string;
|
|
21
|
+
private emit: (items: ChatItem[]) => void;
|
|
22
|
+
private offset = 0;
|
|
23
|
+
private timer: ReturnType<typeof setInterval> | null = null;
|
|
24
|
+
private stopped = false;
|
|
25
|
+
private partial = "";
|
|
26
|
+
private state: TranscriptParserState;
|
|
27
|
+
|
|
28
|
+
constructor(filePath: string, agentId: string, emit: (items: ChatItem[]) => void) {
|
|
29
|
+
this.filePath = filePath;
|
|
30
|
+
this.agentId = agentId;
|
|
31
|
+
this.emit = emit;
|
|
32
|
+
this.state = createParserState();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
start(fromBeginning = false): void {
|
|
36
|
+
if (this.stopped) return;
|
|
37
|
+
if (!existsSync(this.filePath)) return;
|
|
38
|
+
|
|
39
|
+
if (fromBeginning) {
|
|
40
|
+
this.offset = 0;
|
|
41
|
+
} else {
|
|
42
|
+
try {
|
|
43
|
+
const fd = openSync(this.filePath, "r");
|
|
44
|
+
this.offset = fstatSync(fd).size;
|
|
45
|
+
closeSync(fd);
|
|
46
|
+
} catch {
|
|
47
|
+
this.offset = 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.timer = setInterval(() => this.poll(), POLL_MS);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
stop(): void {
|
|
55
|
+
this.stopped = true;
|
|
56
|
+
if (this.timer) { clearInterval(this.timer); this.timer = null; }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private poll(): void {
|
|
60
|
+
if (this.stopped) return;
|
|
61
|
+
if (!existsSync(this.filePath)) return;
|
|
62
|
+
|
|
63
|
+
let fd: number | null = null;
|
|
64
|
+
try {
|
|
65
|
+
fd = openSync(this.filePath, "r");
|
|
66
|
+
const size = fstatSync(fd).size;
|
|
67
|
+
if (size <= this.offset) { closeSync(fd); return; }
|
|
68
|
+
|
|
69
|
+
const len = size - this.offset;
|
|
70
|
+
const buf = Buffer.alloc(len);
|
|
71
|
+
readSync(fd, buf, 0, len, this.offset);
|
|
72
|
+
closeSync(fd);
|
|
73
|
+
fd = null;
|
|
74
|
+
this.offset = size;
|
|
75
|
+
|
|
76
|
+
const chunk = this.partial + buf.toString("utf-8");
|
|
77
|
+
const lines = chunk.split("\n");
|
|
78
|
+
this.partial = lines.pop() ?? "";
|
|
79
|
+
|
|
80
|
+
const allItems: ChatItem[] = [];
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
const trimmed = line.trim();
|
|
83
|
+
if (!trimmed) continue;
|
|
84
|
+
try {
|
|
85
|
+
const entry = JSON.parse(trimmed);
|
|
86
|
+
const items = parseTranscriptEntry(entry, this.agentId, this.state);
|
|
87
|
+
if (items.length > 0) allItems.push(...items);
|
|
88
|
+
} catch { /* skip malformed */ }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (allItems.length > 0) {
|
|
92
|
+
this.emit(allItems);
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
if (fd !== null) try { closeSync(fd); } catch {}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|