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,540 @@
1
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import { isToolCallEventType, isBashToolResult } from "@mariozechner/pi-coding-agent";
3
+ import { Type } from "@sinclair/typebox";
4
+ import { access, readFile, appendFile, rename as fsRename, mkdir, readdir, stat as fsStat } from "node:fs/promises";
5
+ import { dirname, basename, resolve, join } from "node:path";
6
+ import { readFile as fsReadFile, writeFile as fsWriteFile } from "node:fs/promises";
7
+ import { createHash } from "node:crypto";
8
+
9
+ let FILE_RULES: any[] = [];
10
+ (async () => {
11
+ try {
12
+ const raw = await fsReadFile(resolve(dirname(new URL(import.meta.url).pathname), "file_rules.json"), "utf8");
13
+ FILE_RULES = JSON.parse(raw).rules ?? [];
14
+ } catch {}
15
+ })();
16
+ import { getPrompt } from "#runtime";
17
+ import { loadTrust, checkAuth, getWorkDir, setWorkDir, addTrust, removeTrust } from "./authorize.ts";
18
+ import { startWatcher } from "./filewatch.ts";
19
+ import { sendCustomMessage } from "#messages";
20
+
21
+ const COMPANIONS = [".SPEC", ".CHANGELOG", ".HISTORY", ".NAMETRACE", ".LOCATIONTRACE"];
22
+
23
+ // prompt 来自 coded.dna(coded fileactions.wise + fileactions.rules),由 runtime 取,不再硬编码。
24
+ const PROMPT = getPrompt("fileactions.wise");
25
+ const RULES_PROMPT = (() => { try { return getPrompt("fileactions.rules"); } catch { return ""; } })();
26
+
27
+ function isExempt(path: string): boolean {
28
+ // #human 目录下的 companion 文件也受保护,不豁免
29
+ if (isHumanProtected(path)) return false;
30
+ for (const ext of COMPANIONS) if (path.endsWith(ext)) return true;
31
+ if (path.includes("/.git/") || path.startsWith(".git/")) return true;
32
+ return false;
33
+ }
34
+
35
+ function isHumanProtected(path: string): boolean {
36
+ return path.includes("#human.") || path.includes("#human/");
37
+ }
38
+
39
+ function isWalletProtected(path: string): boolean {
40
+ const base = path.split("/").pop() || "";
41
+ return base === "wallet.json" || base === "wallet.log" || base === "ubi.json";
42
+ }
43
+
44
+ function isSystemProtected(path: string): boolean {
45
+ const p = path.replace(/\\/g, "/");
46
+ return p.includes("/.ssh/") || p.includes("/.ssh") ||
47
+ p.includes("/.pi/agent/auth.json") ||
48
+ p.includes("/.pi/agent/trust.json") ||
49
+ p.includes("/.pi/agent/models.json") ||
50
+ p.includes("/fileactions.ts") ||
51
+ p.includes("/pi-coding-agent/dist/") ||
52
+ p.includes("/pi-coding-master.RELEASE/") ||
53
+ p.includes("/.local/bin/pi") ||
54
+ isWalletProtected(path);
55
+ }
56
+
57
+ function fmt(): string {
58
+ const d = new Date();
59
+ const p2 = (n: number) => String(n).padStart(2, "0");
60
+ return `${d.getFullYear()}-${p2(d.getMonth()+1)}-${p2(d.getDate())} ${p2(d.getHours())}:${p2(d.getMinutes())}:${p2(d.getSeconds())}`;
61
+ }
62
+
63
+ async function exists(path: string): Promise<boolean> {
64
+ try { await access(path); return true; } catch { return false; }
65
+ }
66
+
67
+ // 沿着路径往上找到第一个【真实存在】的目录(要落进去的那个环境)。
68
+ async function nearestExistingDir(path: string): Promise<string> {
69
+ let d = dirname(resolve(path));
70
+ for (let i = 0; i < 60 && d.length > 1; i++) {
71
+ if (await exists(d)) return d;
72
+ d = dirname(d);
73
+ }
74
+ return d;
75
+ }
76
+
77
+ async function nonEmpty(path: string): Promise<boolean> {
78
+ try { const c = await readFile(path, "utf8"); return c.trim().length > 0; } catch { return false; }
79
+ }
80
+
81
+ async function lastLine(path: string): Promise<string> {
82
+ try {
83
+ const c = await readFile(path, "utf8");
84
+ const lines = c.trim().split("\n");
85
+ return lines[lines.length - 1]?.trim() ?? "";
86
+ } catch { return ""; }
87
+ }
88
+
89
+ async function moveCompanions(oldPath: string, newPath: string): Promise<void> {
90
+ for (const ext of COMPANIONS) {
91
+ const from = `${oldPath}${ext}`;
92
+ const to = `${newPath}${ext}`;
93
+ if (await exists(from)) {
94
+ await mkdir(dirname(to), { recursive: true }).catch(() => {});
95
+ await fsRename(from, to).catch(() => {});
96
+ }
97
+ }
98
+ }
99
+
100
+ function parseMv(cmd: string): { src: string; dst: string; isRename: boolean } | null {
101
+ const m = cmd.match(/\bmv\s+(?:-[a-zA-Z]+\s+)*["']?([^\s"']+)["']?\s+["']?([^\s"']+)["']?\s*$/);
102
+ if (!m) return null;
103
+ const src = m[1]!;
104
+ const dst = m[2]!;
105
+ const srcDir = dirname(src);
106
+ const dstDir = dst.endsWith("/") ? dst.slice(0, -1) : dirname(dst);
107
+ const isRename = srcDir === dstDir || dirname(resolve(src)) === dirname(resolve(dst));
108
+ return { src, dst, isRename };
109
+ }
110
+
111
+ export default function (pi: ExtensionAPI) {
112
+ startWatcher();
113
+ loadTrust();
114
+
115
+ const editedThisTurn = new Set<string>();
116
+ const changelogUpdatedThisTurn = new Set<string>();
117
+ const dirsSeen = new Set<string>();
118
+ const readmesSeen = new Set<string>(); // 已读过的 dir.README,resolve 绝对路径
119
+
120
+ // ── prompt ───────────────────────────────────────────────────────
121
+ pi.on("before_agent_start", async (event, _ctx) => {
122
+ return { systemPrompt: event.systemPrompt + "\n\n" + PROMPT + (RULES_PROMPT ? "\n\n" + RULES_PROMPT : "") };
123
+ });
124
+
125
+ // ── tool_call: Write gate (spec required) ────────────────────────
126
+ pi.on("tool_call", async (event, _ctx) => {
127
+ // ── Authorization check: 写/改/bash 必须在 workDir 或 trusted dir ──
128
+ let authPath = (event.input as any).path ?? (event.input as any).file_path ?? "";
129
+ // bash 没有 path 字段 → 从 command 抠目标路径。尽量抠全:重定向 > >> >| / cp mv ln install dest /
130
+ // dd of= / tee / rm rmdir mkdir touch truncate。(以前抠不到就 fail-open 放行 = 沙箱被绕过的根。)
131
+ if (!authPath && event.toolName === "bash") {
132
+ const cmd: string = (event.input as any).command ?? "";
133
+ const m = cmd.match(/(?:>>?|>\|)\s*['"]?([^\s'"&|;]+)/) ??
134
+ cmd.match(/\b(?:cp|mv|ln|install)\s+(?:-\S+\s+)*\S+\s+['"]?([^\s'"&|;]+)/) ??
135
+ cmd.match(/\bdd\s+.*\bof=['"]?([^\s'"&|;]+)/) ??
136
+ cmd.match(/\btee\s+(?:-\S+\s+)*['"]?([^\s'"&|;]+)/) ??
137
+ cmd.match(/\b(?:rm|rmdir|mkdir|touch|truncate)\s+(?:-\S+\s+)*['"]?([^\s'"&|;]+)/);
138
+ if (m) authPath = m[1]!;
139
+ else if (/\b(?:rm|rmdir)\b/.test(cmd)) {
140
+ // 有删除操作却抠不到目标(复杂引号/变量/通配) → 绝不 fail-open。误删工作区外的东西比拦一下严重得多。
141
+ return { block: true, reason: "这条 bash 含 rm/rmdir 删除操作,但抠不到能核对的目标路径 —— 为防误删工作区外的东西,先拦下。把要删的路径写明确(绝对路径)再来。" };
142
+ }
143
+ }
144
+
145
+ // ── 系统保护: SSH密钥/凭证/钱包/自身代码/pi dist ──
146
+ if (authPath && isSystemProtected(authPath)) {
147
+ const isRead = ["read","view","ls","list","glob","grep","find"].includes(event.toolName);
148
+ if (authPath.includes("/.ssh/") || authPath.includes("auth.json") || authPath.includes("models.json")) {
149
+ return { block: true, reason: `系统保护 — ${authPath.split("/").pop()} 是凭证文件,agent 不可访问。` };
150
+ }
151
+ if (authPath.includes("/pi-coding-agent/dist/") && !isRead) {
152
+ return { block: true, reason: `pi dist 保护 — 不要直接改 live dist。改 Codebase/deploy/dist-overrides/ 里的 golden 文件,然后跑 bash install.sh 部署。` };
153
+ }
154
+ if (authPath.includes("/pi-coding-master.RELEASE/") && !isRead) {
155
+ return { block: true, reason: `RELEASE 保护 — 不要改发布版。改 pi-coding-master.DEV/ 下的开发版。` };
156
+ }
157
+ if (!isRead) {
158
+ return { block: true, reason: `系统保护 — ${authPath.split("/").pop()} 由系统管理,agent 不可修改。` };
159
+ }
160
+ }
161
+
162
+ // ── #human 保护: agent 默认不可修改 #human 目录下的任何文件(含 companion) ──
163
+ if (authPath && isHumanProtected(authPath) && !["read","view","ls","list","glob","grep","find"].includes(event.toolName)) {
164
+ return { block: true, reason: `#human 保护 — ${authPath} 位于 #human 目录,agent 默认不可修改。如需允许,请确认。` };
165
+ }
166
+
167
+ if (authPath && !["read","view","ls","list","glob","grep","find"].includes(event.toolName)) {
168
+ const authReason = checkAuth(authPath);
169
+ if (authReason) {
170
+ return { block: true, reason: authReason + "\n可用命令请求授权: web auth.ask <目录> [分钟数]" };
171
+ }
172
+ }
173
+
174
+ // ── dir.README gate ─────────────
175
+ const dirREADME = async (targetPath: string) => {
176
+ if (!targetPath || isExempt(targetPath)) return;
177
+ const parentDir = (await exists(targetPath)) ? targetPath : dirname(targetPath);
178
+ const readmePath = join(resolve(parentDir), "dir.README");
179
+ try {
180
+ if ((await exists(readmePath)) && !readmesSeen.has(readmePath)) {
181
+ return { block: true, reason: `${parentDir} 下有 dir.README。先 read 它了解目录规则,再操作。` };
182
+ }
183
+ } catch {}
184
+ };
185
+
186
+ if (isToolCallEventType("ls", event)) return await dirREADME((event.input as any).path ?? (event.input as any).dir ?? "");
187
+ if (isToolCallEventType("read", event)) {
188
+ const rp = (event.input as any).path ?? (event.input as any).file_path ?? "";
189
+ if (basename(rp) === "dir.README") return; // 允许读 README 本身
190
+ return await dirREADME(dirname(rp));
191
+ }
192
+
193
+ // ── FILE_RULES enforcement ─────────────────────────────────
194
+ for (const rule of FILE_RULES) {
195
+ const tn = event.toolName;
196
+ if (rule.on !== tn) continue;
197
+ if (rule.pattern) {
198
+ const cmd = tn === "bash" ? ((event.input as any).command ?? "") : "";
199
+ if (new RegExp(rule.pattern).test(cmd)) {
200
+ return { block: true, reason: rule.block };
201
+ }
202
+ }
203
+ }
204
+
205
+ // ── tool_call: Write gate (spec required) ────────────────────────
206
+ if (isToolCallEventType("write", event)) {
207
+ const path = (event.input as any).path ?? (event.input as any).file_path;
208
+ if (!path || isExempt(path)) return;
209
+
210
+ // 建新文件前看过目录的要求暂时关闭——模型被这个拦截搞得太痛苦。
211
+ // if (!(await exists(path))) {
212
+ // const dir = await nearestExistingDir(path);
213
+ // if (dir && !dirsSeen.has(dir)) {
214
+ // return { block: true, reason: `先 ls 一下目录再建文件。` };
215
+ // }
216
+ // }
217
+
218
+ if (path.endsWith(".CHANGELOG")) {
219
+ return { block: true, reason: `Cannot overwrite ${basename(path)}. CHANGELOG is append-only — use edit to add lines.` };
220
+ }
221
+
222
+ const specPath = `${path}.SPEC`;
223
+ if (!(await exists(specPath))) {
224
+ return { block: true, reason: `No spec found. Write ${specPath} first (any format, non-empty), then retry.` };
225
+ }
226
+ if (!(await nonEmpty(specPath))) {
227
+ return { block: true, reason: `${specPath} is empty. Write your design/plan in it, then retry.` };
228
+ }
229
+ return;
230
+ }
231
+
232
+ // ── tool_call: Edit gate (CHANGELOG append-only + SPEC hash protection) ──
233
+ if (isToolCallEventType("edit", event)) {
234
+ const path = (event.input as any).path ?? (event.input as any).file_path;
235
+ if (!path) return;
236
+
237
+ if (path.endsWith(".CHANGELOG")) {
238
+ const oldStr = (event.input as any).old_string ?? (event.input as any).oldText ?? "";
239
+ const newStr = (event.input as any).new_string ?? (event.input as any).newText ?? "";
240
+ if (newStr.split("\n").length < oldStr.split("\n").length) {
241
+ return { block: true, reason: `CHANGELOG is append-only. You removed lines. Only add.` };
242
+ }
243
+ }
244
+
245
+ if (path.endsWith(".SPEC")) {
246
+ const oldStr = (event.input as any).old_string ?? (event.input as any).oldText ?? "";
247
+ const newStr = (event.input as any).new_string ?? (event.input as any).newText ?? "";
248
+ if (/^source:\s*\S+\s*@\s*[a-f0-9]/.test(oldStr) || /^source:\s*\S+\s*@\s*[a-f0-9]/.test(newStr)) {
249
+ return { block: true, reason: `source hash 行由系统自动维护,不能手动编辑。修改 SPEC 内容即可,hash 会在写入后自动更新。` };
250
+ }
251
+ }
252
+ return;
253
+ }
254
+
255
+ // ── tool_call: Bash gate (rename/move checks) ───────────────────
256
+ if (isToolCallEventType("bash", event)) {
257
+ const cmd = (event.input as any).command;
258
+ if (!cmd) return;
259
+
260
+ // 禁止 rm——只能用 remove 工具标记为 .REMOVED,不能直接删
261
+ if (/\brm\b/.test(cmd) && !cmd.includes("UNREGULATED")) {
262
+ return { block: true, reason: "禁止 rm!用 remove({action:'mark', path:'...'}) 工具把文件标记为 .REMOVED(重命名)。" };
263
+ }
264
+
265
+ // 检查 bash 新建文件——不拦截(管道数据不能丢),但事后补 .SPEC
266
+ // (拦截在 tool_result 里自动处理)
267
+
268
+ const mv = parseMv(cmd);
269
+ if (!mv) return;
270
+ if (isExempt(mv.src)) return;
271
+
272
+ if (mv.isRename) {
273
+ const tracePath = `${mv.src}.NAMETRACE`;
274
+ if (!(await exists(tracePath))) {
275
+ return { block: true, reason: `Rename blocked. Write ${tracePath} with the new name on the last line, then retry.` };
276
+ }
277
+ const last = await lastLine(tracePath);
278
+ const newName = basename(mv.dst.endsWith("/") ? mv.src : mv.dst);
279
+ if (!last.includes(newName)) {
280
+ return { block: true, reason: `${tracePath} last line doesn't contain "${newName}". Update it, then retry.` };
281
+ }
282
+ } else {
283
+ const tracePath = `${mv.src}.LOCATIONTRACE`;
284
+ if (!(await exists(tracePath))) {
285
+ return { block: true, reason: `Move blocked. Write ${tracePath} with the new path on the last line, then retry.` };
286
+ }
287
+ const last = await lastLine(tracePath);
288
+ const dstDir = mv.dst.endsWith("/") ? mv.dst : dirname(mv.dst);
289
+ if (!last.includes(dstDir.replace(/\/$/, ""))) {
290
+ return { block: true, reason: `${tracePath} last line doesn't contain "${dstDir}". Update it, then retry.` };
291
+ }
292
+ }
293
+ return;
294
+ }
295
+ });
296
+
297
+ // ── tool_result: track edits for changelog ───────────────────────
298
+ pi.on("tool_result", async (event, _ctx) => {
299
+ try { sendCustomMessage(pi, "tool-result-debug", `tool_result: ${event.toolName}`); } catch {}
300
+ // 记录"看过哪些目录":ls/read/grep/glob、bash 里的 ls/find,以及成功写过的目录(写过就算看过了)。
301
+ if (!event.isError) {
302
+ const inp = (event.input as any) || {};
303
+ const ip = inp.path ?? inp.file_path ?? inp.dir ?? "";
304
+ const mark = (p: string) => { try { dirsSeen.add(resolve(p)); } catch {} };
305
+ const tn = event.toolName;
306
+ if (tn === "read" || tn === "view") { if (ip) mark(dirname(ip)); const readme = join(dirname(ip), "dir.README"); if (ip && basename(ip) === "dir.README") { try { readmesSeen.add(resolve(ip)); } catch {} } }
307
+ else if (tn === "ls" || tn === "list" || tn === "glob" || tn === "grep" || tn === "find") { if (ip) mark(ip); }
308
+ else if (tn === "write") { if (ip) mark(dirname(ip)); }
309
+ else if (tn === "bash") {
310
+ const m = (inp.command || "").match(/\b(?:ls|find|tree|cat)\b[^|;&<>]*?\s(\/?[\w.~@/+-]+)/);
311
+ if (m) mark(m[1]);
312
+ }
313
+ }
314
+
315
+ // ── 语法检查(edit/write 共用)──
316
+ async function syntaxCheck(filePath: string, result: any) {
317
+ require("fs").appendFileSync("/tmp/syntax-check.log", `SC:${filePath}\n`);
318
+ const ext = filePath.split(".").pop()?.toLowerCase();
319
+ const checker = ext === "ts" ? "bun --check" : ext === "js" ? "node --check" : ext === "py" ? "python3 -m py_compile" : null;
320
+ if (checker) {
321
+ try {
322
+ const { execSync } = await import("node:child_process");
323
+ execSync(`${checker} "${filePath}"`, { encoding: "utf8", timeout: 5000, stdio: ["ignore", "pipe", "pipe"] });
324
+ } catch (e: any) {
325
+ const stderr = (e.stderr || e.stdout || e.message || "").toString().slice(0, 500);
326
+ result.content.push({ type: "text", text: `WARN: 语法错误:\n${stderr}\n请立即修复。` });
327
+ try { sendCustomMessage(pi, "syntax-error", `WARN: 语法错误 ${basename(filePath)}:\n${stderr}`); } catch {}
328
+ }
329
+ }
330
+ }
331
+
332
+ // ── write 后语法检查 ──
333
+ if (event.toolName === "write" && !event.isError) {
334
+ const path = (event.input as any)?.path ?? (event.input as any)?.file_path;
335
+ if (path && !isExempt(path)) await syntaxCheck(path, event);
336
+ }
337
+
338
+ if (event.toolName === "edit" && !event.isError) {
339
+ const path = (event.input as any)?.path ?? (event.input as any)?.file_path;
340
+ if (!path || isExempt(path)) return;
341
+
342
+ await syntaxCheck(path, event);
343
+
344
+ // 编辑 DNA 文件后自动编译
345
+ if (path.endsWith("coded.dna") || path.endsWith("promotor.dna")) {
346
+ try {
347
+ const { execSync } = await import("node:child_process");
348
+ const root = resolve(dirname(new URL(import.meta.url).pathname), "../../..");
349
+ const out = execSync(`cd ${root} && bun Codebase/core/individual.bio.gene/dna.transpiler/transpiler.ts`, { encoding: "utf8", timeout: 10000 });
350
+ if (out.includes("✗ error") || out.includes("WARN:")) {
351
+ // 直接追加到 event 结果,模型立即可见
352
+ const lines = out.split("\n").filter((l: string) => l.includes("✗") || l.includes("WARN:"));
353
+ event.result.content.unshift({ type: "text", text: `\nDNA 编译反馈:\n${lines.join("\n")}` });
354
+ }
355
+ } catch (e: any) {
356
+ event.result.content.unshift({ type: "text", text: `\nDNA 编译失败: ${e.message}` });
357
+ }
358
+ }
359
+
360
+ if (path.endsWith(".HISTORY") || path.endsWith(".CHANGELOG")) {
361
+ // 不记录对 HISTORY/CHANGELOG 本身的编辑
362
+ } else {
363
+ const ts = new Date().toISOString().slice(0, 16).replace("T", " ");
364
+ const oldStr = (event.input as any)?.old_string ?? (event.input as any)?.oldText ?? "";
365
+ const newStr = (event.input as any)?.new_string ?? (event.input as any)?.newText ?? "";
366
+ const diffLines: string[] = [`[${ts}] edit ${basename(path)}`];
367
+ if (oldStr || newStr) {
368
+ for (const l of oldStr.split("\n")) diffLines.push(` - ${l}`);
369
+ for (const l of newStr.split("\n")) diffLines.push(` + ${l}`);
370
+ }
371
+ diffLines.push("");
372
+ mkdir(dirname(path + ".HISTORY"), { recursive: true }).catch(() => {});
373
+ appendFile(path + ".HISTORY", diffLines.join("\n"), "utf8").catch(() => {});
374
+ changelogUpdatedThisTurn.add(path);
375
+ editedThisTurn.add(path);
376
+ }
377
+ }
378
+
379
+ // ── tool_result: auto-compute SPEC source hash ────────────────
380
+ if ((event.toolName === "write" || event.toolName === "edit") && !event.isError) {
381
+ const path = (event.input as any)?.path ?? (event.input as any)?.file_path;
382
+ if (path && path.endsWith(".SPEC")) {
383
+ const srcPath = path.slice(0, -".SPEC".length);
384
+ try {
385
+ const srcContent = await fsReadFile(srcPath);
386
+ const hash = createHash("sha256").update(srcContent).digest("hex").slice(0, 8);
387
+ const srcName = basename(srcPath);
388
+ const hashLine = `source: ${srcName} @ ${hash}`;
389
+ let specContent = await fsReadFile(path, "utf8");
390
+ if (/^source:\s*\S+\s*@\s*[a-f0-9]+/.test(specContent)) {
391
+ specContent = specContent.replace(/^source:\s*\S+\s*@\s*[a-f0-9]+/, hashLine);
392
+ } else {
393
+ specContent = hashLine + "\n\n" + specContent;
394
+ }
395
+ await fsWriteFile(path, specContent, "utf8");
396
+ } catch {}
397
+ }
398
+ }
399
+
400
+ // ── tool_result: auto-create CHANGELOG on write ─────────────────
401
+ if (event.toolName === "write" && !event.isError) {
402
+ const path = (event.input as any)?.path ?? (event.input as any)?.file_path;
403
+ if (!path || isExempt(path)) return;
404
+
405
+ const clPath = `${path}.CHANGELOG`;
406
+ if (!(await exists(clPath))) {
407
+ await appendFile(clPath, `[${fmt()}] created\n`, "utf8").catch(() => {});
408
+ }
409
+ }
410
+
411
+ // ── tool_result: auto-move companions after mv ──────────────────
412
+ if (event.toolName === "bash" && !event.isError) {
413
+ // 检查 bash 是否创建了没有 .SPEC 的新文件
414
+ const cmd = (event.input as any)?.command ?? "";
415
+ const catMatch = cmd.match(/(?:cat|echo|tee)\s+>+\s*(\S+)/);
416
+ const cpMatch = cmd.match(/\bcp\s+\S+\s+(\S+)/);
417
+ const newFilePath = catMatch?.[1] ?? cpMatch?.[1];
418
+ if (newFilePath && !isExempt(newFilePath)) {
419
+ const filePath = resolve(newFilePath);
420
+ if (!(await exists(`${filePath}.SPEC`))) {
421
+ // 不 block——文件已创建——但追加 warn
422
+ await appendFile(`${filePath}.SPEC`, "(auto-created: no spec provided)\n", "utf8").catch(() => {});
423
+ }
424
+ }
425
+
426
+ const mv = parseMv(cmd);
427
+ if (!mv || isExempt(mv.src)) return;
428
+
429
+ // 禁止从 UNREGULATED 移出(绕过 SPEC 检查)
430
+ if (mv.src.includes("/UNREGULATED/") || mv.src.includes(".UNREGULATED")) {
431
+ return { block: true, reason: `${mv.src} 在 UNREGULATED 中。不能通过 mv 绕过 SPEC。先写 .SPEC 再用 write 工具重建。` };
432
+ }
433
+
434
+ const newPath = mv.dst.endsWith("/")
435
+ ? join(mv.dst, basename(mv.src))
436
+ : mv.dst;
437
+
438
+ await moveCompanions(mv.src, newPath);
439
+
440
+ const clPath = `${newPath}.CHANGELOG`;
441
+ const action = mv.isRename ? "renamed" : "moved";
442
+ await appendFile(clPath, `[${fmt()}] ${action} from ${mv.src}\n`, "utf8").catch(() => {});
443
+
444
+ if (mv.isRename) {
445
+ const ntPath = `${newPath}.NAMETRACE`;
446
+ await appendFile(ntPath, `[${fmt()}] ${basename(mv.src)} → ${basename(newPath)}\n`, "utf8").catch(() => {});
447
+ } else {
448
+ const ltPath = `${newPath}.LOCATIONTRACE`;
449
+ await appendFile(ltPath, `[${fmt()}] ${dirname(mv.src)} → ${dirname(newPath)}\n`, "utf8").catch(() => {});
450
+ }
451
+ }
452
+ });
453
+
454
+ // ── remove tool: move file to bin/ with .REMOVED suffix, or scan/clean ──
455
+ pi.registerTool({
456
+ name: "remove",
457
+ label: "Remove",
458
+ messageDescription:
459
+ "Remove files safely: mark for removal or move to bin/. " +
460
+ "Three modes: (1) action=mark: rename <path> to <path>.REMOVED (in-place, reversible). " +
461
+ "(2) action=scan: list all .REMOVED files under <dir>. " +
462
+ "(3) action=clean: move all .REMOVED files under <dir> to <dir>/bin/. ",
463
+ promptSnippet: "Remove: mark|scan|clean files via .REMOVED suffix",
464
+ parameters: Type.Object({
465
+ action: Type.String({ messageDescription: "'mark'=rename to .REMOVED, 'scan'=list .REMOVED, 'clean'=move to bin/" }),
466
+ path: Type.Optional(Type.String({ messageDescription: "File path (for mark) or project dir (for scan/clean)" })),
467
+ }),
468
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
469
+ const action = params.action;
470
+ const p = params.path || "";
471
+
472
+ if (action === "mark") {
473
+ if (!p) return { content: [{ type: "text", text: `mark 需要指定文件路径` }], details: {}, isError: true };
474
+ if (!(await exists(p))) return { content: [{ type: "text", text: `文件不存在: ${p}` }], details: {}, isError: true };
475
+ const markedPath = p + ".REMOVED";
476
+ if (await exists(markedPath)) return { content: [{ type: "text", text: `${markedPath} 已存在` }], details: {}, isError: true };
477
+ await fsRename(p, markedPath);
478
+ return { content: [{ type: "text", text: `${p} -> ${markedPath}` }], details: { markedPath } };
479
+ }
480
+
481
+ if (action === "scan" || action === "clean") {
482
+ const baseDir = resolve(p || ".");
483
+ if (!(await exists(baseDir))) return { content: [{ type: "text", text: `目录不存在: ${baseDir}` }], details: {}, isError: true };
484
+
485
+ // 递归扫描所有 .REMOVED 文件
486
+ const found: string[] = [];
487
+ async function walk(dir: string) {
488
+ let entries: string[];
489
+ try { entries = await readdir(dir); } catch { return; }
490
+ for (const entry of entries) {
491
+ const full = join(dir, entry);
492
+ try {
493
+ const s = await fsStat(full);
494
+ if (s.isDirectory() && !entry.startsWith(".") && entry !== "bin") {
495
+ await walk(full);
496
+ } else if (entry.endsWith(".REMOVED")) {
497
+ found.push(full);
498
+ }
499
+ } catch {}
500
+ }
501
+ }
502
+ await walk(baseDir);
503
+
504
+ if (action === "scan") {
505
+ if (found.length === 0) return { content: [{ type: "text", text: `没有找到 .REMOVED 文件` }], details: { count: 0 } };
506
+ return { content: [{ type: "text", text: `找到 ${found.length} 个 .REMOVED 文件:\n${found.map(f=>` ${f}`).join("\n")}` }], details: { count: found.length, files: found } };
507
+ }
508
+
509
+ if (action === "clean") {
510
+ if (found.length === 0) return { content: [{ type: "text", text: `没有 .REMOVED 文件需要清理` }], details: { count: 0 } };
511
+ const binDir = join(baseDir, "bin");
512
+ await mkdir(binDir, { recursive: true });
513
+ let moved = 0;
514
+ for (const f of found) {
515
+ const dest = join(binDir, basename(f));
516
+ try {
517
+ await fsRename(f, dest);
518
+ moved++;
519
+ } catch {}
520
+ }
521
+ return { content: [{ type: "text", text: `已移动 ${moved}/${found.length} 个 .REMOVED 文件到 ${binDir}` }], details: { moved, total: found.length, binDir } };
522
+ }
523
+ }
524
+
525
+ return { content: [{ type: "text", text: `未知 action: ${action}。用 mark / scan / clean。` }], details: {}, isError: true };
526
+ },
527
+ });
528
+
529
+ // ── turn_end: auto-append changelog for missed edits ─────────────
530
+ pi.on("turn_end", async (_event, _ctx) => {
531
+ for (const path of editedThisTurn) {
532
+ if (changelogUpdatedThisTurn.has(path)) continue;
533
+ const clPath = `${path}.CHANGELOG`;
534
+ await mkdir(dirname(clPath), { recursive: true }).catch(() => {});
535
+ await appendFile(clPath, `[${fmt()}] edited (auto-logged, no messageDescription)\n`, "utf8").catch(() => {});
536
+ }
537
+ editedThisTurn.clear();
538
+ changelogUpdatedThisTurn.clear();
539
+ });
540
+ }
@@ -0,0 +1,25 @@
1
+ [2026-06-15] by Claude Code
2
+ - 重命名 file_actions.ts → fileactions.ts:func 入口 = func 名最后一段,kernel 直接 import 它,去掉空壳 index.ts。
3
+ - PROMPT(WISE-FILE 规则) 改为 getPrompt("fileactions.wise"),从 coded.dna 取,不再硬编码。
4
+ [2026-06-16 05:06:42] edited (auto-logged, no messageDescription)
5
+ [2026-06-16 05:06:47] edited (auto-logged, no messageDescription)
6
+ [2026-06-16 05:06:54] edited (auto-logged, no messageDescription)
7
+ [2026-06-16 05:11:52] edited (auto-logged, no messageDescription)
8
+ [2026-06-16 05:11:58] edited (auto-logged, no messageDescription)
9
+ [2026-06-16 05:14:29] edited (auto-logged, no messageDescription)
10
+ [2026-06-16 05:14:39] edited (auto-logged, no messageDescription)
11
+ [2026-06-16 05:18:36] edited (auto-logged, no messageDescription)
12
+ [2026-06-16 05:26:49] edited (auto-logged, no messageDescription)
13
+ [2026-06-16 05:27:34] edited (auto-logged, no messageDescription)
14
+ [2026-06-16 05:38:44] edited (auto-logged, no messageDescription)
15
+ [2026-06-16 05:38:51] edited (auto-logged, no messageDescription)
16
+ [2026-06-16 05:40:36] edited (auto-logged, no messageDescription)
17
+ [2026-06-16 05:40:45] edited (auto-logged, no messageDescription)
18
+ [2026-06-16 05:42:59] edited (auto-logged, no messageDescription)
19
+ [2026-06-16 05:43:04] edited (auto-logged, no messageDescription)
20
+ [2026-06-16 05:43:18] edited (auto-logged, no messageDescription)
21
+ [2026-06-16 05:45:36] edited (auto-logged, no messageDescription)
22
+ [2026-06-16 05:46:09] edited (auto-logged, no messageDescription)
23
+ [2026-06-16 05:49:46] edited (auto-logged, no messageDescription)
24
+ [2026-06-16 05:49:53] edited (auto-logged, no messageDescription)
25
+ [2026-06-16 05:50:16] edited (auto-logged, no messageDescription)
@@ -0,0 +1,30 @@
1
+ source: fileactions.ts @ 5f6aaab2
2
+
3
+ # fileactions.ts — File operation interception: gates, changelogs, companions
4
+
5
+ ## 职责
6
+ Intercepts all file write/edit/bash tool calls to enforce governance rules: SPEC-before-write, CHANGELOG auto-append, authorization checks (workDir/trusted dirs), dir.README gate (must read before operating), rename/move trace requirements, rm prohibition (mv to .REMOVED only), and companion file (.SPEC/.CHANGELOG/.NAMETRACE/.LOCATIONTRACE) auto-migration on mv.
7
+
8
+ ## 接口
9
+ - `default(pi: ExtensionAPI): void` — func entry called by kernel
10
+
11
+ ## 依赖
12
+ - `#runtime` (getPrompt for "fileactions.wise", "fileactions.rules")
13
+ - `./authorize.js` (loadTrust, checkAuth, getWorkDir, setWorkDir, addTrust, removeTrust)
14
+ - `./filewatch.js` (startWatcher)
15
+ - `./file_rules.json` (runtime-loaded rule patterns)
16
+ - `@mariozechner/pi-coding-agent` (ExtensionAPI, isToolCallEventType, isBashToolResult)
17
+ - `node:fs/promises`, `node:path`
18
+
19
+ ## 行为要点
20
+ - **Write gate**: blocks write if .SPEC doesn't exist or is empty; blocks if target dir not yet ls'd
21
+ - **Edit gate**: CHANGELOG is append-only (cannot reduce line count)
22
+ - **Bash gate**: blocks rm (except in UNREGULATED); blocks mv/rename without NAMETRACE/LOCATIONTRACE
23
+ - **Authorization**: write/edit/bash targets must be in workDir or trusted; bash with unparseable rm/rmdir paths blocked (no fail-open)
24
+ - **dir.README gate**: must read dir.README before any operation in that directory
25
+ - **FILE_RULES**: loaded from file_rules.json, pattern-matched against bash commands
26
+ - **Auto-changelog**: appends timestamped entry on edit/write; auto-creates on first write
27
+ - **Companion migration**: on mv, moves .SPEC/.CHANGELOG/.NAMETRACE/.LOCATIONTRACE alongside
28
+ - **DNA auto-compile**: editing coded.dna or promotor.dna triggers transpiler and surfaces errors/warnings
29
+ - Exempt paths: .SPEC/.CHANGELOG/.NAMETRACE/.LOCATIONTRACE extensions + .git/
30
+ - Tracks seen directories and read dir.READMEs per session
@@ -0,0 +1,66 @@
1
+ import { watch } from "node:fs";
2
+ import { readdir, stat, appendFile, access } from "node:fs/promises";
3
+ import { resolve, dirname, relative } from "node:path";
4
+
5
+ const LOG_DIRS = [
6
+ resolve("gut-lm"),
7
+ resolve(dirname(new URL(import.meta.url).pathname), ".."),
8
+ ];
9
+ const DEBOUNCE_MS = 500;
10
+
11
+ const pending = new Map<string, NodeJS.Timeout>();
12
+
13
+ function fmt(): string {
14
+ const d = new Date();
15
+ return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")} ${String(d.getHours()).padStart(2,"0")}:${String(d.getMinutes()).padStart(2,"0")}:${String(d.getSeconds()).padStart(2,"0")}`;
16
+ }
17
+
18
+ async function logChange(filePath: string, action: string) {
19
+ try {
20
+ const clPath = `${filePath}.CHANGELOG`;
21
+ await appendFile(clPath, `[${fmt()}] ${action}\n`, "utf8");
22
+ } catch {}
23
+ }
24
+
25
+ async function scanDir(dir: string) {
26
+ try {
27
+ const entries = await readdir(dir, { withFileTypes: true });
28
+ for (const e of entries) {
29
+ if (e.name.startsWith(".")) continue;
30
+ const full = resolve(dir, e.name);
31
+ if (e.isDirectory()) await scanDir(full);
32
+ }
33
+ } catch {}
34
+ }
35
+
36
+ export function startWatcher() {
37
+ for (const dir of LOG_DIRS) {
38
+ // 递归 watch
39
+ watch(dir, { recursive: true, persistent: false }, async (event, filename) => {
40
+ if (!filename || filename.startsWith(".")) return;
41
+ const fullPath = resolve(dir, filename);
42
+
43
+ // debounce
44
+ const existing = pending.get(fullPath);
45
+ if (existing) clearTimeout(existing);
46
+
47
+ pending.set(fullPath, setTimeout(async () => {
48
+ pending.delete(fullPath);
49
+ try {
50
+ await stat(fullPath);
51
+ // File exists now - created or modified
52
+ if (event === "rename") {
53
+ await logChange(fullPath, "created/modified");
54
+ } else {
55
+ await logChange(fullPath, "modified");
56
+ }
57
+ } catch {
58
+ // File gone - deleted
59
+ await logChange(fullPath, "deleted");
60
+ }
61
+ }, DEBOUNCE_MS));
62
+ }).unref(); // don't keep process alive
63
+ }
64
+
65
+ console.log("[filewatch] watching", LOG_DIRS.map(d => relative(process.cwd(), d)));
66
+ }
@@ -0,0 +1,3 @@
1
+ source: filewatch.ts @ 36a0d5c7
2
+
3
+ 文件监听器。实时追踪gut-lm和individual.bio.organs下所有文件变动(创建/修改/删除),自动追加.CHANGELOG。命令解析不可靠,文件系统watch全覆盖。