pi-coding-master 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/README.md +50 -0
  2. package/core/god.agent.capability/@ABANDONED.brain.prefrontal.monitor/gpu_monitor.py +80 -0
  3. package/core/god.agent.capability/@ABANDONED.brain.prefrontal.monitor/gpu_monitor.py.CHANGELOG +1 -0
  4. package/core/god.agent.capability/@ABANDONED.brain.prefrontal.monitor/gpu_monitor.py.SPEC +3 -0
  5. package/core/god.agent.capability/hands.dev.writeissue/issue.ts +209 -0
  6. package/core/god.agent.capability/hands.dev.writeissue/issue.ts.SPEC +26 -0
  7. package/core/god.agent.capability/hands.files.changewatcher/watcher.ts +44 -0
  8. package/core/god.agent.capability/hands.files.changewatcher/watcher.ts.SPEC +25 -0
  9. package/core/god.pi.mod/cli/pi-completion.zsh +21 -0
  10. package/core/god.pi.mod/cli/pi-completion.zsh.CHANGELOG +1 -0
  11. package/core/god.pi.mod/cli/pi-people.sh +264 -0
  12. package/core/god.pi.mod/cli/pi-people.sh.LESSON +10 -0
  13. package/core/god.pi.mod/cli/pi-people.sh.SPEC +31 -0
  14. package/core/god.pi.mod/paths.ts +47 -0
  15. package/core/god.pi.mod/tui.mods.blockrender/blockrender.js +90 -0
  16. package/core/god.pi.mod/tui.mods.blockrender/blockrender.js.SPEC +29 -0
  17. package/core/god.pi.mod/tui.mods.footer.budget/budget_guard.ts +154 -0
  18. package/core/god.pi.mod/tui.mods.footer.budget/budget_guard.ts.CHANGELOG +10 -0
  19. package/core/god.pi.mod/tui.mods.footer.budget/budget_guard.ts.LESSON +12 -0
  20. package/core/god.pi.mod/tui.mods.footer.budget/budget_guard.ts.SPEC +26 -0
  21. package/core/god.pi.mod/tui.mods.footer.budget/footer-cny.CHANGELOG +39 -0
  22. package/core/god.pi.mod/tui.mods.viewmode/view_mode-thinking.patch +55 -0
  23. package/core/god.pi.mod/tui.mods.viewmode/view_mode-tools.patch +19 -0
  24. package/core/god.pi.mod/tui.mods.viewmode/view_mode-tools.patch.CHANGELOG +1 -0
  25. package/core/god.pi.mod/tui.mods.viewmode/view_mode.ts +50 -0
  26. package/core/god.pi.mod/tui.mods.viewmode/view_mode.ts.SPEC +12 -0
  27. package/core/god.pi.mod/tui.variants.userterminal/user_terminal.CHANGELOG +10 -0
  28. package/core/god.pi.mod/tui.variants.userterminal/user_terminal.ts +66 -0
  29. package/core/god.pi.mod/tui.variants.userterminal/user_terminal.ts.SPEC +31 -0
  30. package/core/index.ts +3 -0
  31. package/core/individual.bio.gene/dna.coded/coded.dna +257 -0
  32. package/core/individual.bio.gene/dna.coded/coded.dna.CHANGELOG +12 -0
  33. package/core/individual.bio.gene/dna.coded/coded.dna.SPEC +11 -0
  34. package/core/individual.bio.gene/dna.coded/core.dna +110 -0
  35. package/core/individual.bio.gene/dna.promotor/promotor.dna +117 -0
  36. package/core/individual.bio.gene/dna.promotor/promotor.dna.CHANGELOG +4 -0
  37. package/core/individual.bio.gene/dna.promotor/promotor.dna.SPEC +7 -0
  38. package/core/individual.bio.gene/dna.transpiler/transpiler.ts +395 -0
  39. package/core/individual.bio.gene/dna.transpiler/transpiler.ts.CHANGELOG +7 -0
  40. package/core/individual.bio.gene/dna.transpiler/transpiler.ts.SPEC +28 -0
  41. package/core/individual.bio.gene/gene.README +19 -0
  42. package/core/individual.bio.gene/rna/rna.json +536 -0
  43. package/core/individual.bio.gene/rna/rna.json.CHANGELOG +2 -0
  44. package/core/individual.bio.gene/rna/rna.json.SPEC +8 -0
  45. package/core/individual.bio.organs/blood.runtime/messages.ts +236 -0
  46. package/core/individual.bio.organs/blood.runtime/runtime.ts +173 -0
  47. package/core/individual.bio.organs/blood.runtime/runtime.ts.CHANGELOG +5 -0
  48. package/core/individual.bio.organs/blood.runtime/runtime.ts.SPEC +32 -0
  49. package/core/individual.bio.organs/brain.amygdala/amygdala.ts +25 -0
  50. package/core/individual.bio.organs/brain.amygdala/amygdala.ts.COMMENT +3 -0
  51. package/core/individual.bio.organs/brain.amygdala/amygdala.ts.SPEC +9 -0
  52. package/core/individual.bio.organs/brain.hippocampus/hippocampus-launcher.sh.template +108 -0
  53. package/core/individual.bio.organs/brain.hippocampus/hippocampus.ts +166 -0
  54. package/core/individual.bio.organs/brain.hippocampus/hippocampus.ts.CHANGELOG +12 -0
  55. package/core/individual.bio.organs/brain.hippocampus/hippocampus.ts.LESSON +22 -0
  56. package/core/individual.bio.organs/brain.hippocampus/hippocampus.ts.SPEC +16 -0
  57. package/core/individual.bio.organs/brain.hippocampus/memory.ts +879 -0
  58. package/core/individual.bio.organs/brain.hippocampus/memory.ts.CHANGELOG +66 -0
  59. package/core/individual.bio.organs/brain.hippocampus/memory.ts.LESSON +25 -0
  60. package/core/individual.bio.organs/brain.hippocampus/memory.ts.SPEC +46 -0
  61. package/core/individual.bio.organs/brain.hippocampus/sleep.ts +139 -0
  62. package/core/individual.bio.organs/brain.hippocampus/sleep.ts.CHANGELOG +11 -0
  63. package/core/individual.bio.organs/brain.hippocampus/sleep.ts.SPEC +16 -0
  64. package/core/individual.bio.organs/brain.prefrontal.drafting/drafting.SPEC +44 -0
  65. package/core/individual.bio.organs/brain.prefrontal.drafting/drafting.ts +73 -0
  66. package/core/individual.bio.organs/brain.prefrontal.drafting/drafting.ts.CHANGELOG +3 -0
  67. package/core/individual.bio.organs/brain.prefrontal.drafting/drafting.ts.SPEC +24 -0
  68. package/core/individual.bio.organs/brain.prefrontal.drafting/index.ts.CHANGELOG +3 -0
  69. package/core/individual.bio.organs/brain.prefrontal.drafting/main.ts +13 -0
  70. package/core/individual.bio.organs/brain.prefrontal.drafting/main.ts.SPEC +17 -0
  71. package/core/individual.bio.organs/brain.senses.bioclock/bioclock.ts +94 -0
  72. package/core/individual.bio.organs/brain.senses.bioclock/bioclock.ts.LESSON +13 -0
  73. package/core/individual.bio.organs/brain.senses.bioclock/bioclock.ts.SPEC +20 -0
  74. package/core/individual.bio.organs/brain.senses.subconscious/feed-format.SPEC +56 -0
  75. package/core/individual.bio.organs/brain.senses.subconscious/index.ts.CHANGELOG +13 -0
  76. package/core/individual.bio.organs/brain.senses.subconscious/spawner.ts +130 -0
  77. package/core/individual.bio.organs/brain.senses.subconscious/spawner.ts.SPEC +13 -0
  78. package/core/individual.bio.organs/brain.senses.subconscious/subconscious.ts +280 -0
  79. package/core/individual.bio.organs/brain.senses.subconscious/subconscious.ts.CHANGELOG +7 -0
  80. package/core/individual.bio.organs/brain.senses.subconscious/tools.ts +180 -0
  81. package/core/individual.bio.organs/brain.senses.subconscious/tools.ts.SPEC +3 -0
  82. package/core/individual.bio.organs/ears.listen/config.json +9 -0
  83. package/core/individual.bio.organs/ears.listen/config.json.CHANGELOG +1 -0
  84. package/core/individual.bio.organs/ears.listen/config.json.SPEC +3 -0
  85. package/core/individual.bio.organs/ears.listen/ears.ts.CHANGELOG +48 -0
  86. package/core/individual.bio.organs/ears.listen/ears_recorder.py.CHANGELOG +6 -0
  87. package/core/individual.bio.organs/ears.listen/index.ts +1 -0
  88. package/core/individual.bio.organs/ears.listen/index.ts.SPEC +16 -0
  89. package/core/individual.bio.organs/ears.listen/listen.ts +208 -0
  90. package/core/individual.bio.organs/ears.listen/listen.ts.SPEC +3 -0
  91. package/core/individual.bio.organs/ears.listen/listen_recorder.py +445 -0
  92. package/core/individual.bio.organs/ears.listen/listen_recorder.py.SPEC +7 -0
  93. package/core/individual.bio.organs/ears.listen/python_protogen/__init__.py +0 -0
  94. package/core/individual.bio.organs/ears.listen/python_protogen/common/__init__.py +0 -0
  95. package/core/individual.bio.organs/ears.listen/python_protogen/common/events_pb2.py +38 -0
  96. package/core/individual.bio.organs/ears.listen/python_protogen/common/events_pb2_grpc.py +24 -0
  97. package/core/individual.bio.organs/ears.listen/python_protogen/common/rpcmeta_pb2.py +42 -0
  98. package/core/individual.bio.organs/ears.listen/python_protogen/common/rpcmeta_pb2_grpc.py +24 -0
  99. package/core/individual.bio.organs/ears.listen/python_protogen/products/__init__.py +0 -0
  100. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/__init__.py +0 -0
  101. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/ast/__init__.py +0 -0
  102. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/ast/ast_service_pb2.py +45 -0
  103. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/ast/ast_service_pb2_grpc.py +97 -0
  104. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/base/__init__.py +0 -0
  105. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/base/au_base_pb2.py +80 -0
  106. package/core/individual.bio.organs/ears.listen/python_protogen/products/understanding/base/au_base_pb2_grpc.py +24 -0
  107. package/core/individual.bio.organs/hands.fileactions/authorize.TRUST +1 -0
  108. package/core/individual.bio.organs/hands.fileactions/authorize.ts +70 -0
  109. package/core/individual.bio.organs/hands.fileactions/authorize.ts.CHANGELOG +1 -0
  110. package/core/individual.bio.organs/hands.fileactions/authorize.ts.SPEC +3 -0
  111. package/core/individual.bio.organs/hands.fileactions/dir.README +13 -0
  112. package/core/individual.bio.organs/hands.fileactions/file_rules.json +23 -0
  113. package/core/individual.bio.organs/hands.fileactions/fileactions.README +12 -0
  114. package/core/individual.bio.organs/hands.fileactions/fileactions.ts +540 -0
  115. package/core/individual.bio.organs/hands.fileactions/fileactions.ts.CHANGELOG +25 -0
  116. package/core/individual.bio.organs/hands.fileactions/fileactions.ts.SPEC +30 -0
  117. package/core/individual.bio.organs/hands.fileactions/filewatch.ts +66 -0
  118. package/core/individual.bio.organs/hands.fileactions/filewatch.ts.SPEC +3 -0
  119. package/core/individual.bio.organs/hands.main/main.ts +18 -0
  120. package/core/individual.bio.organs/hands.main/main.ts.SPEC +20 -0
  121. package/core/individual.bio.organs/hands.sensitive/sensitive.ts +24 -0
  122. package/core/individual.bio.organs/hands.sensitive/sensitive.ts.CHANGELOG +2 -0
  123. package/core/individual.bio.organs/hands.sensitive/sensitive.ts.SPEC +3 -0
  124. package/core/individual.bio.organs/heart.interrupt/agent_start-loader-flicker.patch +13 -0
  125. package/core/individual.bio.organs/heart.interrupt/interactive-mode-loader.patch +11 -0
  126. package/core/individual.bio.organs/heart.interrupt/runner_esc.patch +10 -0
  127. package/core/individual.bio.organs/heart.interrupt/runner_esc.patch.SPEC +9 -0
  128. package/core/individual.bio.organs/heart.kernel/kernel.ts +253 -0
  129. package/core/individual.bio.organs/heart.kernel/kernel.ts.CHANGELOG +13 -0
  130. package/core/individual.bio.organs/heart.kernel/kernel.ts.SPEC +23 -0
  131. package/core/individual.bio.organs/heart.main/heart.main.CHANGELOG +43 -0
  132. package/core/individual.bio.organs/heart.main/heartbeat.ts +494 -0
  133. package/core/individual.bio.organs/heart.main/heartbeat.ts.LESSON +43 -0
  134. package/core/individual.bio.organs/heart.main/main.ts +8 -0
  135. package/core/individual.bio.organs/heart.main/main.ts.SPEC +19 -0
  136. package/core/individual.bio.organs/heart.main/process.ts +122 -0
  137. package/core/individual.bio.organs/heart.main/process.ts.CHANGELOG +2 -0
  138. package/core/individual.bio.organs/heart.main/process.ts.SPEC +24 -0
  139. package/core/individual.bio.organs/heart.main/remove_timeout.patch +110 -0
  140. package/core/individual.bio.organs/heart.main/stop.ts.CHANGELOG +3 -0
  141. package/core/individual.bio.organs/heart.main/stop.ts.SPEC +28 -0
  142. package/core/individual.bio.organs/mouth.speak/index.ts +1 -0
  143. package/core/individual.bio.organs/mouth.speak/index.ts.CHANGELOG +1 -0
  144. package/core/individual.bio.organs/mouth.speak/index.ts.SPEC +6 -0
  145. package/core/individual.bio.organs/mouth.speak/mouth.ts.CHANGELOG +15 -0
  146. package/core/individual.bio.organs/mouth.speak/mouth_recorder.py.CHANGELOG +1 -0
  147. package/core/individual.bio.organs/mouth.speak/speak.ts +180 -0
  148. package/core/individual.bio.organs/mouth.speak/speak.ts.SPEC +3 -0
  149. package/core/individual.bio.organs/mouth.speak/speak_recorder.py +35 -0
  150. package/core/individual.bio.organs/mouth.speak/speak_recorder.py.SPEC +3 -0
  151. package/core/individual.bio.organs/organs.README +110 -0
  152. package/core/package-lock.json +18 -0
  153. package/core/package.json +35 -0
  154. package/core/prompts/prompts.json +77 -0
  155. package/core/prompts/prompts.ts +44 -0
  156. package/core/prompts/prompts.ts.SPEC +9 -0
  157. package/core/society.world/.gitkeep +0 -0
  158. package/core/society.world/accessibility.claudecode/message-service.cjs +217 -0
  159. package/core/society.world/accessibility.claudecode/message-service.cjs.SPEC +7 -0
  160. package/core/society.world/accessibility.claudecode/send.ts +34 -0
  161. package/core/society.world/dollar.distribution.ubi/ubi.ts +55 -0
  162. package/core/society.world/dollar.main/dollar-service.cjs +185 -0
  163. package/core/society.world/dollar.main/main.ts +116 -0
  164. package/core/society.world/dollar.transaction/transaction.ts +71 -0
  165. package/core/society.world/space/space.ts +206 -0
  166. package/core/society.world/space/space.ts.SPEC +30 -0
  167. package/core/technology.laptop/#agent.macos.BLUEPRINT +278 -0
  168. package/core/technology.phone/apps.preinstalled/albums.FUTURE/albums.ts +69 -0
  169. package/core/technology.phone/apps.preinstalled/albums.FUTURE/albums.ts.SPEC +15 -0
  170. package/core/technology.phone/apps.preinstalled/calendar/calendar.ts +406 -0
  171. package/core/technology.phone/apps.preinstalled/calendar/calendar.ts.SPEC +22 -0
  172. package/core/technology.phone/apps.preinstalled/calendar/holiday-calendar.ts +529 -0
  173. package/core/technology.phone/apps.preinstalled/clock/clock.ts +132 -0
  174. package/core/technology.phone/apps.preinstalled/clock/clock.ts.SPEC +11 -0
  175. package/core/technology.phone/apps.preinstalled/contacts.FUTURE/contacts.ts +300 -0
  176. package/core/technology.phone/apps.preinstalled/contacts.FUTURE/contacts.ts.SPEC +22 -0
  177. package/core/technology.phone/apps.preinstalled/developer.FUTURE/developer.ts +22 -0
  178. package/core/technology.phone/apps.preinstalled/developer.FUTURE/developer.ts.SPEC +15 -0
  179. package/core/technology.phone/apps.preinstalled/notes/notes.ts +239 -0
  180. package/core/technology.phone/apps.preinstalled/notes/notes.ts.SPEC +21 -0
  181. package/core/technology.phone/apps.preinstalled/polymarket/polymarket.ts +261 -0
  182. package/core/technology.phone/apps.preinstalled/polymarket/polymarket.ts.SPEC +7 -0
  183. package/core/technology.phone/apps.preinstalled/reminder/reminder.ts +404 -0
  184. package/core/technology.phone/apps.preinstalled/reminder/reminder.ts.SPEC +25 -0
  185. package/core/technology.phone/apps.preinstalled/siri.FUTURE/siri.ts +22 -0
  186. package/core/technology.phone/apps.preinstalled/siri.FUTURE/siri.ts.SPEC +15 -0
  187. package/core/technology.phone/apps.preinstalled/spotlight/spotlight.ts +29 -0
  188. package/core/technology.phone/apps.preinstalled/spotlight/spotlight.ts.SPEC +7 -0
  189. package/core/technology.phone/apps.preinstalled/steam/chess.ts +230 -0
  190. package/core/technology.phone/apps.preinstalled/steam/snake.ts +100 -0
  191. package/core/technology.phone/apps.preinstalled/steam/snake.ts.SPEC +7 -0
  192. package/core/technology.phone/apps.preinstalled/steam/spy-cmd.ts +4 -0
  193. package/core/technology.phone/apps.preinstalled/steam/spy-tool.ts +56 -0
  194. package/core/technology.phone/apps.preinstalled/steam/spy.ts +302 -0
  195. package/core/technology.phone/apps.preinstalled/steam/steam.ts +299 -0
  196. package/core/technology.phone/apps.preinstalled/weather/weather.ts +50 -0
  197. package/core/technology.phone/apps.preinstalled/weather/weather.ts.SPEC +9 -0
  198. package/core/technology.phone/apps.preinstalled/wechat/imessage.ts +423 -0
  199. package/core/technology.phone/apps.preinstalled/wechat/imessage.ts.SPEC +24 -0
  200. package/core/technology.phone/apps.system/appstore/appstore.ts +22 -0
  201. package/core/technology.phone/apps.system/appstore/appstore.ts.SPEC +15 -0
  202. package/core/technology.phone/apps.system/finder.FUTURE/finder.ts +64 -0
  203. package/core/technology.phone/apps.system/finder.FUTURE/finder.ts.SPEC +8 -0
  204. package/core/technology.phone/apps.system/safari/safari-app.ts +146 -0
  205. package/core/technology.phone/apps.system/safari/safari.ts.SPEC +24 -0
  206. package/core/technology.phone/apps.system/settings/settings.ts +126 -0
  207. package/core/technology.phone/apps.system/settings/settings.ts.SPEC +17 -0
  208. package/core/technology.phone/apps.system/tips/tips.ts +22 -0
  209. package/core/technology.phone/apps.system/tips/tips.ts.SPEC +15 -0
  210. package/core/technology.phone/apps.thirdparty/alipay/alipay.ts +148 -0
  211. package/core/technology.phone/apps.thirdparty/alipay/alipay.ts.SPEC +7 -0
  212. package/core/technology.phone/apps.thirdparty/bilibili/bilibili-app.ts +33 -0
  213. package/core/technology.phone/apps.thirdparty/bilibili/bilibili.ts +142 -0
  214. package/core/technology.phone/apps.thirdparty/bilibili/bilibili.ts.SPEC +22 -0
  215. package/core/technology.phone/apps.thirdparty/wechatread/wechatread.ts +80 -0
  216. package/core/technology.phone/apps.thirdparty/wechatread/wechatread.ts.SPEC +15 -0
  217. package/core/technology.phone/index.ts +1 -0
  218. package/core/technology.phone/package.json +2 -0
  219. package/core/technology.phone/system.homepage/homepage.ts +247 -0
  220. package/core/technology.phone/system.homepage/homepage.ts.SPEC +22 -0
  221. package/core/technology.phone/system.kernel/kernel.ts +264 -0
  222. package/core/technology.phone/system.kernel/kernel.ts.SPEC +7 -0
  223. package/core/technology.phone/system.notifications/notifications.ts +87 -0
  224. package/core/technology.phone/system.notifications/notifications.ts.SPEC +7 -0
  225. package/core/technology.phone/system.share/share.ts +46 -0
  226. package/core/technology.phone/system.share/share.ts.SPEC +7 -0
  227. package/core/technology.server/browser-service.cjs +152 -0
  228. package/core/technology.server/data/cookies/arxiv.json +30 -0
  229. package/core/technology.server/data/cookies/bili.json +184 -0
  230. package/core/technology.server/data/cookies/default.json +30 -0
  231. package/core/technology.server/data/cookies/news.json +113 -0
  232. package/core/technology.server/data/cookies/s1.json +45 -0
  233. package/core/technology.server/data/cookies/safari.json +184 -0
  234. package/core/technology.server/data/cookies/safari2.json +1 -0
  235. package/core/technology.server/data/cookies/safaridbg.json +1 -0
  236. package/core/technology.server/data/cookies/search.json +45 -0
  237. package/core/technology.server/data/cookies/sw.json +30 -0
  238. package/core/technology.server/data/cookies/t1.json +1 -0
  239. package/core/technology.server/data/cookies/testread.json +1 -0
  240. package/core/technology.server/data/cookies/video1.json +113 -0
  241. package/core/technology.server/data/cookies/yt.json +170 -0
  242. package/core/technology.server/data/cookies/yt2.json +113 -0
  243. package/core/technology.server/pikipedia/#pikipedia.BLUEPRINT +106 -0
  244. package/core/technology.server/playleft.cjs +247 -0
  245. package/core/technology.server/search-proxy.py +76 -0
  246. package/core/technology.server/server.README +59 -0
  247. package/deploy/dist-overrides/cli/cli.js +18 -0
  248. package/deploy/dist-overrides/core/extensions/loader.js +518 -0
  249. package/deploy/dist-overrides/core/package-manager.js +2081 -0
  250. package/deploy/dist-overrides/core/system-prompt.js +109 -0
  251. package/deploy/dist-overrides/core/system-prompt.js.LESSON +17 -0
  252. package/deploy/dist-overrides/core/tools/bash.js +353 -0
  253. package/deploy/dist-overrides/core/tools/bash.js.CHANGELOG +2 -0
  254. package/deploy/dist-overrides/core/tools/edit-diff.js +345 -0
  255. package/deploy/dist-overrides/core/tools/edit.js +315 -0
  256. package/deploy/dist-overrides/core/tools/edit.js.CHANGELOG +1 -0
  257. package/deploy/dist-overrides/core/tools/file-mutation-queue.js +52 -0
  258. package/deploy/dist-overrides/core/tools/find.js +298 -0
  259. package/deploy/dist-overrides/core/tools/find.js.CHANGELOG +1 -0
  260. package/deploy/dist-overrides/core/tools/grep.js +305 -0
  261. package/deploy/dist-overrides/core/tools/grep.js.CHANGELOG +1 -0
  262. package/deploy/dist-overrides/core/tools/index.js +112 -0
  263. package/deploy/dist-overrides/core/tools/ls-guard.js +4 -0
  264. package/deploy/dist-overrides/core/tools/ls.js +170 -0
  265. package/deploy/dist-overrides/core/tools/ls.js.CHANGELOG +1 -0
  266. package/deploy/dist-overrides/core/tools/output-accumulator.js +184 -0
  267. package/deploy/dist-overrides/core/tools/path-utils.js +99 -0
  268. package/deploy/dist-overrides/core/tools/prompts-reader.js +53 -0
  269. package/deploy/dist-overrides/core/tools/read.js +392 -0
  270. package/deploy/dist-overrides/core/tools/read.js.CHANGELOG +1 -0
  271. package/deploy/dist-overrides/core/tools/render-utils.js +65 -0
  272. package/deploy/dist-overrides/core/tools/tool-definition-wrapper.js +34 -0
  273. package/deploy/dist-overrides/core/tools/truncate.js +215 -0
  274. package/deploy/dist-overrides/core/tools/write.js +203 -0
  275. package/deploy/dist-overrides/core/tools/write.js.CHANGELOG +1 -0
  276. package/deploy/dist-overrides/dist-overrides.README +18 -0
  277. package/deploy/dist-overrides/main.js +665 -0
  278. package/deploy/dist-overrides/modes/interactive/components/assistant-message.js +139 -0
  279. package/deploy/dist-overrides/modes/interactive/components/footer.js +326 -0
  280. package/deploy/dist-overrides/modes/interactive/components/model-selector.js +285 -0
  281. package/deploy/dist-overrides/modes/interactive/components/tool-execution.js +383 -0
  282. package/deploy/dist-overrides/modes/interactive/components/tool-execution.js.CHANGELOG +3 -0
  283. package/deploy/dist-overrides/modes/interactive/interactive-mode.js +4781 -0
  284. package/deploy/dist-overrides/pi-ai/providers/anthropic.js +931 -0
  285. package/deploy/dist-overrides/pi-ai/providers/openai-completions.js +1007 -0
  286. package/deploy/dist-overrides/pi-ai/providers/openai-completions.js.LESSON +15 -0
  287. package/deploy/dist-overrides/pi-tui/components/loader.js +69 -0
  288. package/deploy/dist-overrides/pi-tui/components/markdown.js +646 -0
  289. package/deploy/dist-overrides/pi-tui/components/text.js +92 -0
  290. package/deploy/dist-overrides/pi-tui/custom-message.js +75 -0
  291. package/deploy/dist-overrides/pi-tui/tui.js +1266 -0
  292. package/deploy/dist-overrides/pi-tui/utils.js +1060 -0
  293. package/deploy/dist-overrides/vendor.REMOVED/jiti/lib/jiti.mjs +3 -0
  294. package/deploy/install.sh +186 -0
  295. package/deploy/install.sh.CHANGELOG +6 -0
  296. package/deploy/lint/lint-naming.ts +202 -0
  297. package/deploy/scripts/apply.js +18 -0
  298. package/deploy/scripts/build-github.sh +219 -0
  299. package/deploy/scripts/build-phone.sh +24 -0
  300. package/deploy/scripts/check-deploy.sh +42 -0
  301. package/deploy/scripts/migrate-context.sh +72 -0
  302. package/deploy/scripts/patch-pi-dist.js +39 -0
  303. package/deploy/scripts/uninstall.sh +34 -0
  304. package/package.json +18 -0
@@ -0,0 +1,302 @@
1
+ // steam/spy.ts — Steam 游戏平台(谁是卧底 + 国际象棋)
2
+
3
+ import type { PhoneApp } from "../../phone.ts";
4
+ import { SpyGame } from "./engine.ts";
5
+ import { ChessGame } from "./chess.ts";
6
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
7
+ import { homedir } from "node:os";
8
+ import { join } from "node:path";
9
+
10
+ // ── LLM bot ──
11
+
12
+ function getApiKey(): string | null {
13
+ try {
14
+ const cfg = JSON.parse(readFileSync(join(homedir(), ".pi/agent/models.json"), "utf8"));
15
+ let k = cfg?.providers?.deepseek?.apiKey;
16
+ if (typeof k === "string" && k.startsWith("$")) k = process.env[k.slice(1)] ?? "";
17
+ if (typeof k === "string" && k.trim()) return k.trim();
18
+ } catch {}
19
+ return process.env.DEEPSEEK_API_KEY || null;
20
+ }
21
+
22
+ async function llm(system: string, user: string): Promise<string> {
23
+ const key = getApiKey();
24
+ if (!key) return "";
25
+ try {
26
+ const res = await Promise.race([
27
+ fetch("https://api.deepseek.com/chat/completions", {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
30
+ body: JSON.stringify({
31
+ model: "deepseek-v4-flash",
32
+ messages: [{ role: "system", content: system }, { role: "user", content: user }],
33
+ max_tokens: 300, temperature: 0.9,
34
+ }),
35
+ signal: AbortSignal.timeout(3000),
36
+ }),
37
+ new Promise<null>((r) => setTimeout(() => r(null), 3000)),
38
+ ]);
39
+ if (!res) return "";
40
+ const j = await res.json() as any;
41
+ return (j.choices?.[0]?.message?.content || "").trim().replace(/^["「]|["」]$/g, "");
42
+ } catch { return ""; }
43
+ }
44
+
45
+ // 本地 fallback:LLM 不可用时,根据词生成简单描述
46
+ const LOCAL_FALLBACKS: Record<string, string[]> = {
47
+ "薯条": ["炸的", "蘸番茄酱吃"], "薯片": ["袋装", "脆的零食"],
48
+ "眼镜": ["戴在脸上", "帮助看清东西"], "墨镜": ["遮阳", "夏天常戴"],
49
+ "牛奶": ["白色液体", "补钙"], "豆浆": ["豆制品", "早餐喝"],
50
+ "西瓜": ["绿色外皮", "夏天吃"], "哈密瓜": ["黄色果肉", "甜瓜"],
51
+ "口红": ["涂抹嘴唇", "美妆"], "唇膏": ["滋润", "防干裂"],
52
+ "高铁": ["速度快", "出远门坐"], "动车": ["也是快的火车", "短途多"],
53
+ "微信": ["聊天", "绿色图标"], "QQ": ["聊天软件", "企鹅图标"],
54
+ "面包": ["烤的", "西式主食"], "馒头": ["蒸的", "中式主食"],
55
+ "咖啡": ["苦的", "提神醒脑"], "奶茶": ["甜的", "年轻人爱喝"],
56
+ "蜡烛": ["能点燃", "照明用"], "火把": ["手持燃烧", "古代照明"],
57
+ "护照": ["出国用", "一本蓝色"], "身份证": ["国内用", "随身携带"],
58
+ "沙发": ["软的", "客厅家具"], "椅子": ["硬的", "可以坐"],
59
+ "钢笔": ["蘸墨水", "写字"], "毛笔": ["软笔头", "书法"],
60
+ "足球": ["用脚踢", "圆的"], "篮球": ["用手拍", "橙色的"],
61
+ "医生": ["看病", "白大褂"], "护士": ["护理", "白衣天使"],
62
+ "月亮": ["晚上看", "会变圆缺"], "太阳": ["白天", "发光发热"],
63
+ "空调": ["制冷", "挂在墙上"], "风扇": ["转的", "吹风"],
64
+ "地铁": ["地下跑", "通勤"], "公交": ["地上跑", "等车"],
65
+ "饺子": ["皮包馅", "过年吃"], "馄饨": ["汤里", "皮更薄"],
66
+ "雪碧": ["柠檬味", "绿色瓶"], "七喜": ["也是柠檬味", "白瓶"],
67
+ };
68
+ function localFallback(word: string): string {
69
+ const opts = LOCAL_FALLBACKS[word];
70
+ if (!opts) return "这个东西挺常见的";
71
+ return opts[Math.floor(Math.random() * opts.length)];
72
+ }
73
+
74
+ async function botDescribe(name: string, word: string, isSpy: boolean, round: number, prevDescs: { player: string; text: string }[]): Promise<string> {
75
+ const history = prevDescs.length > 0 ? "前面的描述:\n" + prevDescs.map(d => `${d.player}: "${d.text}"`).join("\n") : "你是第一个。";
76
+ const sys = `你在玩谁是卧底。你的词是「${word}」。用一句话描述,不能说出词语本身或其中任何一个字。绝对不能抄袭或复述别人说过的描述,必须用完全不同的角度。${isSpy ? "你是卧底,描述要模糊但合理,让人觉得你拿到的词和大家一样。" : "你是平民,描述要有区分度但别太明显。"}只输出描述,限15字。`;
77
+ const llmResult = await llm(sys, `第${round}轮。${history}\n轮到${name}。`);
78
+ if (llmResult) return llmResult;
79
+ // 本地 fallback:取不一样的描述
80
+ const used = new Set(prevDescs.map(d => d.text));
81
+ const opts = LOCAL_FALLBACKS[word];
82
+ if (opts) {
83
+ for (const o of opts) if (!used.has(o)) return o;
84
+ return opts[0];
85
+ }
86
+ return "这个东西挺常见的";
87
+ }
88
+
89
+ async function botVote(name: string, word: string, isSpy: boolean, alive: string[], descs: { player: string; text: string }[]): Promise<string> {
90
+ const candidates = alive.filter(id => id !== name);
91
+ if (candidates.length === 0) return "";
92
+ const descText = descs.map(d => `${d.player}: "${d.text}"`).join("\n");
93
+ const sys = `你在玩谁是卧底。你的词是「${word}」。${isSpy ? "你是卧底,投掉一个平民。" : "找描述最不一样的人。"}只回复一个名字。`;
94
+ const reply = await llm(sys, `描述:\n${descText}\n从 ${candidates.join("、")} 中选。`);
95
+ if (reply) return candidates.find(c => reply.includes(c)) || candidates[Math.floor(Math.random() * candidates.length)];
96
+ return candidates[Math.floor(Math.random() * candidates.length)];
97
+ }
98
+
99
+ // ── runBots:非阻塞,后台运行,完成时自动更新状态 ──
100
+ let botRunning = false;
101
+ async function runBots(game: SpyGame, agentId: string, onUpdate?: () => void): Promise<void> {
102
+ if (botRunning) return;
103
+ botRunning = true;
104
+ try {
105
+ // 描述阶段:串行(每个 bot 需要看到前面的描述)
106
+ while (game.phase === "describe") {
107
+ const current = game.getState().currentTurn;
108
+ if (!current || current === agentId) break;
109
+ const p = game.players.find(x => x.id === current);
110
+ if (!p) break;
111
+ game.describe(current, await botDescribe(current, p.word, p.isSpy, game.round, game.currentRoundDescs));
112
+ onUpdate?.();
113
+ }
114
+ // 投票阶段:并行
115
+ if (game.phase === "vote") {
116
+ const alive = game.getState().alivePlayers;
117
+ await Promise.all(
118
+ alive.filter(pid => pid !== agentId && !game.votes.find(v => v.voter === pid))
119
+ .map(async pid => {
120
+ const p = game.players.find(x => x.id === pid)!;
121
+ game.vote(pid, await botVote(pid, p.word, p.isSpy, alive, game.currentRoundDescs));
122
+ onUpdate?.();
123
+ })
124
+ );
125
+ }
126
+ onUpdate?.();
127
+ } finally {
128
+ botRunning = false;
129
+ }
130
+ }
131
+
132
+ // ── Steam 状态 ──
133
+
134
+ // ── 游戏注册表 ──
135
+
136
+ interface SteamGameDef {
137
+ name: string;
138
+ desc: string;
139
+ }
140
+
141
+ const GAMES: SteamGameDef[] = [
142
+ { name: "谁是卧底", desc: "和 AI 对战的推理游戏" },
143
+ { name: "国际象棋", desc: "和 AI 对弈(minimax)" },
144
+ { name: "贪吃蛇", desc: "经典贪吃蛇" },
145
+ ];
146
+
147
+ function menu(): string {
148
+ const lines = ["═══ Steam 游戏平台 ═══", ""];
149
+ for (const g of GAMES) lines.push(` ${g.name} — ${g.desc}`);
150
+ lines.push("", "输入游戏名,或「返回」回主屏幕");
151
+ return lines.join("\n");
152
+ }
153
+
154
+ function matchGame(input: string): SteamGameDef | null {
155
+ return GAMES.find(g => input.includes(g.name)) || null;
156
+ }
157
+
158
+ interface SteamState {
159
+ cur: string | null;
160
+ spy: SpyGame | null;
161
+ chess: ChessGame | null;
162
+ snake: any;
163
+ }
164
+
165
+ function norm(raw: any): SteamState {
166
+ if (raw?.cur !== undefined) return raw;
167
+ if (raw?.game) return { cur: '谁是卧底', spy: raw.game, chess: null, snake: null };
168
+ return { cur: null, spy: null, chess: null, snake: null };
169
+ }
170
+
171
+ // ── Tool 导出(manifest 用)──
172
+ // 游戏逻辑由 Steam 手机 app 管理;这里只提供入口引导
173
+ export async function spyCmd(args: any, _ctx: any, _personDir: string): Promise<{ content: any[]; details: any }> {
174
+ return {
175
+ content: [{ type: "text", text: "谁是卧底\n\n请在手机 Steam 应用中打开「谁是卧底」开始游戏。\n手机 → Steam → 谁是卧底" }],
176
+ details: {},
177
+ };
178
+ }
179
+
180
+ export const app: PhoneApp = {
181
+ name: "Steam",
182
+ icon: "",
183
+ messageDescription: "游戏平台",
184
+
185
+ onOpen(state: any, personDir: string) {
186
+ const s = norm(state);
187
+ if (s.cur === "谁是卧底" && s.spy && s.spy.phase !== "end") return { screen: s.spy.getPlayerView("你"), state: s };
188
+ if (s.cur === "国际象棋") {
189
+ if (!s.chess || s.chess.s.over) s.chess = loadPersisted(personDir) || new ChessGame();
190
+ return { screen: s.chess.screen(), state: s };
191
+ }
192
+ if (s.cur === "贪吃蛇" && s.snake && !s.snake.over) return { screen: s.snake.screen(), state: s };
193
+ s.cur = null;
194
+ return { screen: menu(), state: s };
195
+ },
196
+
197
+ async onAction(input: string, rawState: any, personDir: string) {
198
+ const s = norm(rawState);
199
+ const trimmed = input.trim();
200
+ const agentId = "你";
201
+
202
+ if (/^(菜单|menu|返回|back)$/i.test(trimmed)) { s.cur = null; s.spy = null; return { screen: menu(), state: s }; }
203
+
204
+ // ── 游戏选择 ──
205
+ if (!s.cur) {
206
+ const hit = matchGame(trimmed);
207
+ if (!hit) return { screen: menu() + "\n\n请选择游戏。", state: s };
208
+ s.cur = hit.name;
209
+ if (hit.name === "国际象棋") {
210
+ s.chess = loadPersisted(personDir) || new ChessGame();
211
+ return { screen: s.chess.screen(), state: s };
212
+ }
213
+ if (hit.name === "贪吃蛇") {
214
+ s.snake = await newSnake();
215
+ return { screen: s.snake.screen(), state: s };
216
+ }
217
+ if (hit.name === "谁是卧底") {
218
+ if (s.spy && s.spy.phase !== "end") return { screen: s.spy.getPlayerView(agentId), state: s };
219
+ return { screen: "═══ 谁是卧底 ═══\n\n输入「新游戏」或「新游戏 5」开始\n「菜单」回 Steam", state: s };
220
+ }
221
+ }
222
+
223
+ // ── 谁是卧底 ──
224
+ if (s.cur === "谁是卧底") {
225
+ const newMatch = trimmed.match(/^新游戏\s*(\d+)?$/) || trimmed.match(/^new\s*(\d+)?$/i);
226
+ if (newMatch) {
227
+ const count = Math.max(3, Math.min(7, parseInt(newMatch[1] || "5")));
228
+ const botNames = ["甲", "乙", "丙", "丁", "戊", "己"].slice(0, count - 1);
229
+ s.spy = new SpyGame([agentId, ...botNames]);
230
+ // 非阻塞:bot 后台运行,不卡 UI
231
+ runBots(s.spy, agentId);
232
+ return { screen: s.spy.getPlayerView(agentId) + "\nAI 玩家思考中...", state: s };
233
+ }
234
+ if (!s.spy || s.spy.phase === "end") {
235
+ if (s.spy?.phase === "end") return { screen: s.spy.getPlayerView(agentId) + "\n\n输入「新游戏」再来一局,或「菜单」回 Steam。", state: s };
236
+ return { screen: "没有进行中的游戏。输入「新游戏」开始。", state: s };
237
+ }
238
+ const game = s.spy;
239
+ if (game.phase === "vote") {
240
+ const alive = game.getState().alivePlayers.filter((id: string) => id !== agentId);
241
+ const target = alive.find((name: string) => trimmed.includes(name));
242
+ if (target) {
243
+ const result = game.vote(agentId, target);
244
+ if (!result.ok) return { screen: `${result.error}`, state: s };
245
+ runBots(game, agentId);
246
+ return { screen: `${result.message}\n\n${game.getPlayerView(agentId)}`, state: s };
247
+ }
248
+ return { screen: `请投票: ${alive.join(", ")}`, state: s };
249
+ }
250
+ if (game.phase === "describe" && game.getState().currentTurn === agentId) {
251
+ const desc = trimmed.replace(/^(describe|描述)\s*/i, "").trim();
252
+ if (!desc) return { screen: "描述不能为空。输入你对词语的描述。", state: s };
253
+ const result = game.describe(agentId, desc);
254
+ if (!result.ok) return { screen: `${result.error}`, state: s };
255
+ runBots(game, agentId);
256
+ return { screen: `${result.message}\n\n${game.getPlayerView(agentId)}`, state: s };
257
+ }
258
+ // 默认返回当前状态
259
+ let screen = game.getPlayerView(agentId);
260
+ if (botRunning) screen += "\nAI 玩家思考中...";
261
+ return { screen, state: s };
262
+ }
263
+
264
+ // ── 贪吃蛇 ──
265
+ if (s.cur === "贪吃蛇") {
266
+ if (!s.snake) s.snake = await newSnake();
267
+ if (/^(新局|new)$/i.test(trimmed)) { s.snake = await newSnake(); return { screen: s.snake.screen(), state: s }; }
268
+ const dirMap: Record<string, 'u'|'d'|'l'|'r'> = { w: 'u', s: 'd', a: 'l', d: 'r', up: 'u', down: 'd', left: 'l', right: 'r' };
269
+ const dir = dirMap[trimmed.toLowerCase()];
270
+ if (dir) s.snake.input(dir);
271
+ return { screen: s.snake.screen(), state: s };
272
+ }
273
+
274
+ // ── 国际象棋 ──
275
+ if (s.cur === "国际象棋") {
276
+ if (!s.chess) s.chess = loadPersisted(personDir) || new ChessGame();
277
+ if (/^(新局|new)$/i.test(trimmed)) { s.chess = new ChessGame(); clearPersisted(personDir); return { screen: s.chess.screen(), state: s }; }
278
+ if (/^(认输|resign)$/i.test(trimmed)) { s.chess.resign(); persist(s.chess, personDir); return { screen: s.chess.screen(), state: s }; }
279
+ const r = s.chess.move(trimmed);
280
+ if (!r.ok) return { screen: s.chess.screen() + `\n\n${r.error}`, state: s };
281
+ persist(s.chess, personDir);
282
+ return { screen: s.chess.screen() + (r.ai ? `\n\n对手走: ${r.ai}` : ""), state: s };
283
+ }
284
+
285
+ return { screen: menu(), state: s };
286
+ },
287
+ };
288
+
289
+ // ── 持久化 ──
290
+ function persist(game: ChessGame, personDir: string) {
291
+ try { mkdirSync(personDir, { recursive: true }); writeFileSync(join(personDir, "steam.json"), JSON.stringify({ chess: game.toJSON() })); } catch {}
292
+ }
293
+ function loadPersisted(personDir: string): ChessGame | null {
294
+ try { const raw = JSON.parse(readFileSync(join(personDir, "steam.json"), "utf8")); return raw?.chess ? ChessGame.fromJSON(raw.chess) : null; } catch { return null; }
295
+ }
296
+ function clearPersisted(personDir: string) { try { writeFileSync(join(personDir, "steam.json"), "{}"); } catch {} }
297
+
298
+ // ── 动态加载蛇(破 jiti 缓存)──
299
+ async function newSnake(): Promise<any> {
300
+ const { SnakeGame } = await import(`./snake.js?t=${Date.now()}`);
301
+ return new SnakeGame();
302
+ }
@@ -0,0 +1,299 @@
1
+ // spy/engine.ts — 谁是卧底游戏引擎(纯逻辑,零 LLM,零 I/O)
2
+ // 所有状态变更通过方法调用,所有非法操作返回错误,不抛异常。
3
+
4
+ export interface WordPair { spy: string; civilian: string; hint?: string }
5
+
6
+ export interface Player {
7
+ id: string;
8
+ name: string;
9
+ isSpy: boolean;
10
+ word: string;
11
+ alive: boolean;
12
+ messageDescriptions: string[];
13
+ }
14
+
15
+ export type Phase = "describe" | "vote" | "end";
16
+ export type Winner = "spy" | "civilian" | null;
17
+
18
+ export interface VoteRecord { voter: string; target: string }
19
+ export interface RoundRecord {
20
+ round: number;
21
+ messageDescriptions: { player: string; text: string }[];
22
+ votes: VoteRecord[];
23
+ eliminated: string | null;
24
+ tiebreak: boolean;
25
+ }
26
+
27
+ export interface GameState {
28
+ phase: Phase;
29
+ round: number;
30
+ alivePlayers: string[];
31
+ currentTurn: string | null;
32
+ describeOrder: string[];
33
+ describedThisRound: string[];
34
+ votedThisRound: string[];
35
+ winner: Winner;
36
+ rounds: RoundRecord[];
37
+ }
38
+
39
+ export interface ActionResult {
40
+ ok: boolean;
41
+ error?: string;
42
+ state: GameState;
43
+ message?: string;
44
+ }
45
+
46
+ const BUILTIN_WORDS: WordPair[] = [
47
+ { spy: "薯条", civilian: "薯片" },
48
+ { spy: "眼镜", civilian: "墨镜" },
49
+ { spy: "牛奶", civilian: "豆浆" },
50
+ { spy: "西瓜", civilian: "哈密瓜" },
51
+ { spy: "口红", civilian: "唇膏" },
52
+ { spy: "高铁", civilian: "动车" },
53
+ { spy: "微信", civilian: "QQ" },
54
+ { spy: "面包", civilian: "馒头" },
55
+ { spy: "咖啡", civilian: "奶茶" },
56
+ { spy: "蜡烛", civilian: "火把" },
57
+ { spy: "护照", civilian: "身份证" },
58
+ { spy: "沙发", civilian: "椅子" },
59
+ { spy: "钢笔", civilian: "毛笔" },
60
+ { spy: "足球", civilian: "篮球" },
61
+ { spy: "医生", civilian: "护士" },
62
+ { spy: "月亮", civilian: "太阳" },
63
+ { spy: "空调", civilian: "风扇" },
64
+ { spy: "地铁", civilian: "公交" },
65
+ { spy: "饺子", civilian: "馄饨" },
66
+ { spy: "雪碧", civilian: "七喜" },
67
+ ];
68
+
69
+ function shuffle<T>(arr: T[]): T[] {
70
+ const a = [...arr];
71
+ for (let i = a.length - 1; i > 0; i--) {
72
+ const j = Math.floor(Math.random() * (i + 1));
73
+ [a[i], a[j]] = [a[j], a[i]];
74
+ }
75
+ return a;
76
+ }
77
+
78
+ export class SpyGame {
79
+ players: Player[] = [];
80
+ phase: Phase = "describe";
81
+ round = 1;
82
+ describeOrder: string[] = [];
83
+ describeIdx = 0;
84
+ votes: VoteRecord[] = [];
85
+ rounds: RoundRecord[] = [];
86
+ currentRoundDescs: { player: string; text: string }[] = [];
87
+ winner: Winner = null;
88
+ wordPair: WordPair;
89
+
90
+ constructor(playerNames: string[], spyCount = 1, wordPair?: WordPair) {
91
+ if (playerNames.length < 3) throw new Error("至少 3 个玩家");
92
+ if (spyCount >= playerNames.length) throw new Error("卧底数量必须少于玩家数");
93
+
94
+ this.wordPair = wordPair ?? BUILTIN_WORDS[Math.floor(Math.random() * BUILTIN_WORDS.length)];
95
+ const shuffled = shuffle(playerNames);
96
+ const spyNames = new Set(shuffled.slice(0, spyCount));
97
+
98
+ this.players = playerNames.map(name => ({
99
+ id: name,
100
+ name,
101
+ isSpy: spyNames.has(name),
102
+ word: spyNames.has(name) ? this.wordPair.spy : this.wordPair.civilian,
103
+ alive: true,
104
+ messageDescriptions: [],
105
+ }));
106
+
107
+ this.describeOrder = shuffle(this.alivePlayers().map(p => p.id));
108
+ }
109
+
110
+ private alivePlayers(): Player[] {
111
+ return this.players.filter(p => p.alive);
112
+ }
113
+
114
+ private player(id: string): Player | undefined {
115
+ return this.players.find(p => p.id === id);
116
+ }
117
+
118
+ getState(): GameState {
119
+ return {
120
+ phase: this.phase,
121
+ round: this.round,
122
+ alivePlayers: this.alivePlayers().map(p => p.id),
123
+ currentTurn: this.phase === "describe" ? (this.describeOrder[this.describeIdx] ?? null) : null,
124
+ describeOrder: this.describeOrder,
125
+ describedThisRound: this.currentRoundDescs.map(d => d.player),
126
+ votedThisRound: this.votes.map(v => v.voter),
127
+ winner: this.winner,
128
+ rounds: this.rounds,
129
+ };
130
+ }
131
+
132
+ getPlayerView(playerId: string): string {
133
+ const p = this.player(playerId);
134
+ if (!p) return "错误:你不在这局游戏里。";
135
+
136
+ const lines: string[] = [];
137
+ lines.push(`═══ 谁是卧底 · 第 ${this.round} 轮 ═══`);
138
+ lines.push(`你是: ${p.name} | 你的词: 「${p.word}」`);
139
+ lines.push(`存活: ${this.alivePlayers().map(a => a.id).join(", ")} (${this.alivePlayers().length}人)`);
140
+ lines.push("");
141
+
142
+ if (this.phase === "describe") {
143
+ lines.push(`── 描述阶段 ──`);
144
+ if (this.currentRoundDescs.length > 0) {
145
+ for (const d of this.currentRoundDescs) {
146
+ lines.push(` ${d.player}: "${d.text}"`);
147
+ }
148
+ }
149
+ const currentTurn = this.describeOrder[this.describeIdx];
150
+ if (currentTurn === playerId) {
151
+ lines.push("");
152
+ lines.push(`→ 轮到你描述。用你自己的话描述你的词,不要直接说出词语。`);
153
+ lines.push(` 操作: describe <你的描述>`);
154
+ } else if (currentTurn) {
155
+ lines.push(` 等待 ${currentTurn} 描述...`);
156
+ }
157
+ } else if (this.phase === "vote") {
158
+ lines.push(`── 投票阶段 ──`);
159
+ lines.push(`本轮描述回顾:`);
160
+ for (const d of this.currentRoundDescs) {
161
+ lines.push(` ${d.player}: "${d.text}"`);
162
+ }
163
+ lines.push("");
164
+ if (this.votes.find(v => v.voter === playerId)) {
165
+ lines.push(`你已投票。等待其他人...`);
166
+ lines.push(`已投: ${this.votes.map(v => v.voter).join(", ")}`);
167
+ const notYet = this.alivePlayers().filter(a => !this.votes.find(v => v.voter === a.id));
168
+ if (notYet.length > 0) lines.push(`未投: ${notYet.map(a => a.id).join(", ")}`);
169
+ } else {
170
+ const candidates = this.alivePlayers().filter(a => a.id !== playerId).map(a => a.id);
171
+ lines.push(`→ 投票淘汰一个你认为是卧底的人。`);
172
+ lines.push(` 候选: ${candidates.join(", ")}`);
173
+ lines.push(` 操作: vote <玩家名>`);
174
+ }
175
+ } else if (this.phase === "end") {
176
+ lines.push(`══ 游戏结束 ══`);
177
+ lines.push(`胜方: ${this.winner === "spy" ? "卧底" : "平民"}`);
178
+ lines.push(`卧底词: 「${this.wordPair.spy}」 | 平民词: 「${this.wordPair.civilian}」`);
179
+ lines.push(`卧底是: ${this.players.filter(p => p.isSpy).map(p => p.name).join(", ")}`);
180
+ }
181
+
182
+ if (this.rounds.length > 0 && this.phase !== "end") {
183
+ lines.push("");
184
+ lines.push(`── 历史 ──`);
185
+ for (const r of this.rounds) {
186
+ lines.push(` 第${r.round}轮: 淘汰 ${r.eliminated ?? "无"}${r.tiebreak ? " (平票重投)" : ""}`);
187
+ }
188
+ }
189
+
190
+ return lines.join("\n");
191
+ }
192
+
193
+ describe(playerId: string, text: string): ActionResult {
194
+ if (this.phase !== "describe") return { ok: false, error: "当前不是描述阶段。", state: this.getState() };
195
+ if (!this.player(playerId)?.alive) return { ok: false, error: "你已被淘汰。", state: this.getState() };
196
+ const currentTurn = this.describeOrder[this.describeIdx];
197
+ if (currentTurn !== playerId) return { ok: false, error: `还没轮到你,当前轮到 ${currentTurn}。`, state: this.getState() };
198
+
199
+ const trimmed = text.trim();
200
+ if (!trimmed) return { ok: false, error: "描述不能为空。", state: this.getState() };
201
+ if (trimmed.includes(this.wordPair.spy) || trimmed.includes(this.wordPair.civilian)) {
202
+ return { ok: false, error: "描述中不能包含任何玩家的词语!请重新描述。", state: this.getState() };
203
+ }
204
+
205
+ this.currentRoundDescs.push({ player: playerId, text: trimmed });
206
+ this.player(playerId)!.messageDescriptions.push(trimmed);
207
+ this.describeIdx++;
208
+
209
+ if (this.describeIdx >= this.describeOrder.length) {
210
+ this.phase = "vote";
211
+ this.votes = [];
212
+ }
213
+
214
+ return { ok: true, state: this.getState(), message: `描述已记录。` };
215
+ }
216
+
217
+ vote(voterId: string, targetId: string): ActionResult {
218
+ if (this.phase !== "vote") return { ok: false, error: "当前不是投票阶段。", state: this.getState() };
219
+ if (!this.player(voterId)?.alive) return { ok: false, error: "你已被淘汰。", state: this.getState() };
220
+ if (this.votes.find(v => v.voter === voterId)) return { ok: false, error: "你已经投过票了。", state: this.getState() };
221
+ if (voterId === targetId) return { ok: false, error: "不能投自己。", state: this.getState() };
222
+ const target = this.player(targetId);
223
+ if (!target || !target.alive) return { ok: false, error: `${targetId} 不存在或已被淘汰。`, state: this.getState() };
224
+
225
+ this.votes.push({ voter: voterId, target: targetId });
226
+
227
+ if (this.votes.length >= this.alivePlayers().length) {
228
+ return this.resolveVotes();
229
+ }
230
+
231
+ return { ok: true, state: this.getState(), message: `投票已记录。等待其他玩家投票。` };
232
+ }
233
+
234
+ private resolveVotes(): ActionResult {
235
+ const counts: Record<string, number> = {};
236
+ for (const v of this.votes) counts[v.target] = (counts[v.target] || 0) + 1;
237
+
238
+ const maxVotes = Math.max(...Object.values(counts));
239
+ const topPlayers = Object.entries(counts).filter(([, c]) => c === maxVotes).map(([id]) => id);
240
+
241
+ let eliminated: string | null = null;
242
+ let tiebreak = false;
243
+
244
+ if (topPlayers.length === 1) {
245
+ eliminated = topPlayers[0];
246
+ } else {
247
+ // 平票:随机淘汰一个(简化规则,完整版可以加PK)
248
+ eliminated = topPlayers[Math.floor(Math.random() * topPlayers.length)];
249
+ tiebreak = true;
250
+ }
251
+
252
+ if (eliminated) {
253
+ const p = this.player(eliminated);
254
+ if (p) p.alive = false;
255
+ }
256
+
257
+ this.rounds.push({
258
+ round: this.round,
259
+ messageDescriptions: [...this.currentRoundDescs],
260
+ votes: [...this.votes],
261
+ eliminated,
262
+ tiebreak,
263
+ });
264
+
265
+ const winner = this.checkWin();
266
+ if (winner) {
267
+ this.winner = winner;
268
+ this.phase = "end";
269
+ return {
270
+ ok: true,
271
+ state: this.getState(),
272
+ message: `${eliminated} 被淘汰!游戏结束,${winner === "spy" ? "卧底" : "平民"}获胜!`,
273
+ };
274
+ }
275
+
276
+ this.round++;
277
+ this.currentRoundDescs = [];
278
+ this.votes = [];
279
+ this.describeOrder = shuffle(this.alivePlayers().map(p => p.id));
280
+ this.describeIdx = 0;
281
+ this.phase = "describe";
282
+
283
+ return {
284
+ ok: true,
285
+ state: this.getState(),
286
+ message: `${eliminated} 被淘汰!${tiebreak ? "(平票随机)" : ""} 进入第 ${this.round} 轮。`,
287
+ };
288
+ }
289
+
290
+ private checkWin(): Winner {
291
+ const alive = this.alivePlayers();
292
+ const spiesAlive = alive.filter(p => p.isSpy).length;
293
+ const civiliansAlive = alive.filter(p => !p.isSpy).length;
294
+
295
+ if (spiesAlive === 0) return "civilian";
296
+ if (spiesAlive >= civiliansAlive) return "spy";
297
+ return null;
298
+ }
299
+ }
@@ -0,0 +1,50 @@
1
+ // apps.preinstalled/weather/weather.ts — Weather PhoneApp
2
+ import type { PhoneApp } from "../../system.kernel/kernel.ts";
3
+
4
+ async function fetchWeather(city: string): Promise<string> {
5
+ const c = encodeURIComponent(city || "Beijing");
6
+ try {
7
+ const res = await fetch(`https://wttr.in/${c}?format=%C+%t+%h+%w&lang=zh`, {
8
+ signal: AbortSignal.timeout(3000),
9
+ headers: { "User-Agent": "curl/7.79" },
10
+ });
11
+ if (res.ok) return `${city}: ${(await res.text()).trim()}`;
12
+ } catch {}
13
+ // fallback: multi-line forecast
14
+ try {
15
+ const res = await fetch(`https://wttr.in/${c}?T&lang=zh`, {
16
+ signal: AbortSignal.timeout(5000),
17
+ headers: { "User-Agent": "curl/7.79" },
18
+ });
19
+ if (res.ok) {
20
+ const text = await res.text();
21
+ return text.split("\n").filter((l: string) => l.trim()).slice(0, 8).join("\n");
22
+ }
23
+ } catch {}
24
+ return "天气查询失败,检查城市名";
25
+ }
26
+
27
+ export const app: PhoneApp = {
28
+ name: "天气",
29
+ icon: "天气",
30
+ messageDescription: "查询城市天气",
31
+
32
+ onOpen(state: any) {
33
+ return {
34
+ screen: [
35
+ "═══ 天气 ═══",
36
+ "",
37
+ "输入城市名查询天气",
38
+ "如:深圳、Tokyo、London",
39
+ "",
40
+ "「返回」退出",
41
+ ].join("\n"),
42
+ state,
43
+ };
44
+ },
45
+
46
+ async onAction(input: string, state: any) {
47
+ const weather = await fetchWeather(input.trim());
48
+ return { screen: weather + "\n\n输入其他城市继续查,或「返回」退出", state };
49
+ },
50
+ };
@@ -0,0 +1,9 @@
1
+ source: weather.ts @ f49052d3
2
+
3
+ # weather.ts SPEC
4
+ ## 用途
5
+ 天气工具——查询城市天气。按 BlueBox OS Weather.app Info.plist 定义实现。
6
+ ## 为什么需要
7
+ 用户要求实现 BlueBox OS 各 App 功能为 pi AI 工具。
8
+ ## 能力
9
+ - query_weather: 查询城市天气(默认北京)