@tequila99/githuman 0.11.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (325) hide show
  1. package/README.md +74 -2
  2. package/dist/cli/commands/mcp.js +112 -0
  3. package/dist/cli/commands/pi-acp.js +21 -0
  4. package/dist/cli/config.js +10 -1
  5. package/dist/cli/index.js +19 -8
  6. package/dist/cli/server-runtime.js +5 -0
  7. package/dist/server/adapters/agents/artifact-permission.js +88 -0
  8. package/dist/server/adapters/pi-acp/agent.js +98 -0
  9. package/dist/server/adapters/pi-acp/compatibility.js +57 -0
  10. package/dist/server/adapters/pi-acp/control.js +76 -0
  11. package/dist/server/adapters/pi-acp/errors.js +17 -0
  12. package/dist/server/adapters/pi-acp/extension.js +255 -0
  13. package/dist/server/adapters/pi-acp/launch.js +16 -0
  14. package/dist/server/adapters/pi-acp/mcp.js +153 -0
  15. package/dist/server/adapters/pi-acp/process.js +199 -0
  16. package/dist/server/adapters/pi-acp/session.js +409 -0
  17. package/dist/server/adapters/pi-acp/vendor/LICENSE +21 -0
  18. package/dist/server/adapters/pi-acp/vendor/README.md +29 -0
  19. package/dist/server/adapters/pi-acp/vendor/prompt.js +56 -0
  20. package/dist/server/app.js +95 -5
  21. package/dist/server/config/agents.js +4 -6
  22. package/dist/server/db/artifact-graph-migrations.js +56 -0
  23. package/dist/server/db/artifact-migrations.js +70 -0
  24. package/dist/server/db/artifact-review-migrations.js +24 -0
  25. package/dist/server/db/artifact-search-migrations.js +31 -0
  26. package/dist/server/db/artifact-validation-migrations.js +70 -0
  27. package/dist/server/db/index.js +3 -0
  28. package/dist/server/db/migrations.js +10 -0
  29. package/dist/server/db/sqlite-error.js +15 -0
  30. package/dist/server/db/transaction.js +40 -0
  31. package/dist/server/errors/artifacts.js +28 -0
  32. package/dist/server/errors/database.js +2 -0
  33. package/dist/server/hooks/access/local-request.js +5 -0
  34. package/dist/server/hooks/access/require-access.js +13 -2
  35. package/dist/server/repositories/artifact-catalog.repo.js +283 -0
  36. package/dist/server/repositories/artifact-files.repo.js +181 -0
  37. package/dist/server/repositories/artifact-graph.repo.js +50 -0
  38. package/dist/server/repositories/artifact-search.repo.js +192 -0
  39. package/dist/server/repositories/artifact-transition.repo.js +85 -0
  40. package/dist/server/repositories/artifact-validation.repo.js +157 -0
  41. package/dist/server/repositories/notes-catalog.repo.js +2 -10
  42. package/dist/server/repositories/task.repo.js +114 -0
  43. package/dist/server/routes/agent.js +8 -1
  44. package/dist/server/routes/artifact-actions.js +129 -0
  45. package/dist/server/routes/artifact-agent.js +199 -0
  46. package/dist/server/routes/artifact-definitions.js +163 -0
  47. package/dist/server/routes/artifact-transitions.js +80 -0
  48. package/dist/server/routes/artifacts.js +111 -0
  49. package/dist/server/routes/events.js +5 -1
  50. package/dist/server/services/agent/agent-session.js +180 -10
  51. package/dist/server/services/agent/context-builder.js +30 -2
  52. package/dist/server/services/agent/session-registry.js +136 -10
  53. package/dist/server/services/agent/turn-task-context.js +1 -0
  54. package/dist/server/services/artifact-authorization.service.js +199 -0
  55. package/dist/server/services/artifact-definition.service.js +96 -0
  56. package/dist/server/services/artifact-export.service.js +44 -0
  57. package/dist/server/services/artifact-graph-validation.js +541 -0
  58. package/dist/server/services/artifact-graph.service.js +81 -0
  59. package/dist/server/services/artifact-lifecycle.service.js +431 -0
  60. package/dist/server/services/artifact-maintenance.service.js +55 -0
  61. package/dist/server/services/artifact-search.service.js +331 -0
  62. package/dist/server/services/artifact-storage.service.js +646 -0
  63. package/dist/server/services/artifact-transition.service.js +608 -0
  64. package/dist/server/services/artifact-type.service.js +74 -0
  65. package/dist/server/services/artifact-validation-jobs.service.js +848 -0
  66. package/dist/server/services/device-connections.js +9 -1
  67. package/dist/server/services/review.service.js +6 -5
  68. package/dist/server/services/task.service.js +225 -0
  69. package/dist/server/utils/artifact-actor.js +13 -0
  70. package/dist/server/utils/artifact-page.js +42 -0
  71. package/dist/server/utils/take-within-bytes.js +16 -0
  72. package/dist/server/utils/text.js +7 -0
  73. package/dist/shared/agents/schemas.js +30 -0
  74. package/dist/shared/app/storage-constants.js +2 -0
  75. package/dist/shared/artifact-tools/descriptions.js +17 -0
  76. package/dist/shared/artifact-tools/instructions.js +14 -0
  77. package/dist/shared/artifact-tools/schemas.js +124 -0
  78. package/dist/shared/artifact-transitions/constants.js +21 -0
  79. package/dist/shared/artifact-transitions/schemas.js +111 -0
  80. package/dist/shared/artifact-transitions/transitions.js +61 -0
  81. package/dist/shared/artifact-transitions/types.js +1 -0
  82. package/dist/shared/artifacts/constants.js +34 -0
  83. package/dist/shared/artifacts/mcp-constants.js +24 -0
  84. package/dist/shared/artifacts/normalize.js +9 -0
  85. package/dist/shared/artifacts/schemas.js +874 -0
  86. package/dist/shared/artifacts/search.js +101 -0
  87. package/dist/shared/artifacts/types.js +1 -0
  88. package/dist/shared/events/schemas.js +1 -1
  89. package/dist/shared/events/types.js +1 -0
  90. package/dist/shared/tasks/schemas.js +261 -0
  91. package/dist/shared/tasks/types.js +1 -0
  92. package/dist/shared/utils/artifact-body.js +10 -0
  93. package/dist/shared/utils/canonical-json.js +22 -0
  94. package/dist/shared/utils/is-safe-prefixed-filename.js +10 -0
  95. package/dist/shared/utils/is-uuid.js +4 -2
  96. package/dist/shared/utils/is-valid-artifact-type-id.js +9 -0
  97. package/dist/shared/utils/is-valid-filename-prefix.js +13 -0
  98. package/dist/web/assets/AccessPage-D9xfFUBC.js +1 -0
  99. package/dist/web/assets/AddButton-DKNKmS1i.js +4 -0
  100. package/dist/web/assets/AddToAgentButton-wC1dzbDE.js +1 -0
  101. package/dist/web/assets/AppPage-Cozv2vqG.js +1 -0
  102. package/dist/web/assets/ArtifactsPage-IHUO7SbH.js +2 -0
  103. package/dist/web/assets/ArtifactsPage-nRD9XiRm.css +1 -0
  104. package/dist/web/assets/CancelButton-mkxRHwoZ.js +1 -0
  105. package/dist/web/assets/ClosePopup-Bd5a-Lu_.js +1 -0
  106. package/dist/web/assets/CreateButton-zCmb7snC.js +1 -0
  107. package/dist/web/assets/CreateReviewFabButton-D58IHr36.js +1 -0
  108. package/dist/web/assets/DialogHeader-BVrtb0Ri.js +1 -0
  109. package/dist/web/assets/DialogHeader-CPL9OtDV.css +1 -0
  110. package/dist/web/assets/{ErrorNotFound-DucDzOUJ.js → ErrorNotFound-fXS367lZ.js} +1 -1
  111. package/dist/web/assets/{IndexPage-D5PvyGrX.css → IndexPage-5V5GLtgi.css} +1 -1
  112. package/dist/web/assets/IndexPage-BJ1EQdlT.js +1 -0
  113. package/dist/web/assets/MainLayout-C3Ie5yOo.css +1 -0
  114. package/dist/web/assets/MainLayout-CeogGMHH.js +7 -0
  115. package/dist/web/assets/{NoteVisualEditor-CawpxEFB.css → NoteVisualEditor-DE4ACTRJ.css} +1 -1
  116. package/dist/web/assets/NoteVisualEditor-DqAZZig1.js +1054 -0
  117. package/dist/web/assets/NotesPage-C_eoCUl7.css +1 -0
  118. package/dist/web/assets/NotesPage-DXgI-kwN.js +4 -0
  119. package/dist/web/assets/{PdfPreview-rlkcqoMF.js → PdfPreview-ByeBjQMQ.js} +2 -2
  120. package/dist/web/assets/ProjectFilePage-DV1anYfN.js +1 -0
  121. package/dist/web/assets/QBtn-V3VXtJXi.js +1 -0
  122. package/dist/web/assets/QFab-DJhLqo9i.js +1 -0
  123. package/dist/web/assets/{QForm-Be8-ucuJ.js → QForm-ClpSneeD.js} +1 -1
  124. package/dist/web/assets/QInput-BnqLJGXl.js +1 -0
  125. package/dist/web/assets/QScrollArea-qf2G1s2r.js +1 -0
  126. package/dist/web/assets/QSeparator-B8uLaDiI.js +1 -0
  127. package/dist/web/assets/QSpace-CVp0CPR_.js +1 -0
  128. package/dist/web/assets/QSplitter-K2LjbupZ.js +1 -0
  129. package/dist/web/assets/QTabs-Bl_rIz4_.js +1 -0
  130. package/dist/web/assets/QVirtualScroll-BeEkuL6x.js +1 -0
  131. package/dist/web/assets/ReviewDetailPage-BgxcsTqY.css +1 -0
  132. package/dist/web/assets/ReviewDetailPage-CL4Dmz0L.js +1 -0
  133. package/dist/web/assets/ReviewsPage-BPJFTulG.js +1 -0
  134. package/dist/web/assets/SaveButton-D1q2suzR.js +3 -0
  135. package/dist/web/assets/SaveButton-Vtjvcbt0.css +1 -0
  136. package/dist/web/assets/SearchInput-DapVXrFj.js +1 -0
  137. package/dist/web/assets/StatusSwitcher-BtbSIr5q.js +1 -0
  138. package/dist/web/assets/{StatusSwitcher-D6i8_OfR.css → StatusSwitcher-DaE1ufAA.css} +1 -1
  139. package/dist/web/assets/TagFilterField-CPl-BxtL.js +1 -0
  140. package/dist/web/assets/TagFilterField-DjUH0m3_.css +1 -0
  141. package/dist/web/assets/{TerminalView-D4elkzN4.js → TerminalView-B56cEx8g.js} +12 -12
  142. package/dist/web/assets/{TerminalView-617DZuPt.css → TerminalView-BCeke4xd.css} +1 -1
  143. package/dist/web/assets/{abnfDiagram-O67JEVCF-Cugru96L.js → abnfDiagram-O67JEVCF-D_6l0gCA.js} +1 -1
  144. package/dist/web/assets/{access-store-Cdg8oRAM.js → access-store-CwkOl71l.js} +1 -1
  145. package/dist/web/assets/{agent-store-D_W7iD_B.js → agent-store-Cs-hu1v1.js} +5 -5
  146. package/dist/web/assets/architecture-7GRP2DOG-KT2-_RA5.js +1 -0
  147. package/dist/web/assets/{architectureDiagram-NJMV4G6O-7rMsE4Wt.js → architectureDiagram-NJMV4G6O-BFgjp9nL.js} +1 -1
  148. package/dist/web/assets/{blockDiagram-BEXU5L5S-BvSnwUrI.js → blockDiagram-BEXU5L5S-BWfbJk26.js} +1 -1
  149. package/dist/web/assets/{c4Diagram-YGBWAQC7-CgmQlCVx.js → c4Diagram-YGBWAQC7-oIqgOwQa.js} +1 -1
  150. package/dist/web/assets/channel-CAhty-fl.js +1 -0
  151. package/dist/web/assets/{chunk-3FUC2YCW-_i8udThz.js → chunk-3FUC2YCW-WI2pliXT.js} +1 -1
  152. package/dist/web/assets/{chunk-5DYCD2WN-Mhk2LlLk.js → chunk-5DYCD2WN-DYvaF8o2.js} +1 -1
  153. package/dist/web/assets/{chunk-742MDFTN-CDVcwgEp.js → chunk-742MDFTN-xd7B3x5h.js} +1 -1
  154. package/dist/web/assets/{chunk-7INBJB4K-C2c1fi9s.js → chunk-7INBJB4K-nsyx3RGB.js} +1 -1
  155. package/dist/web/assets/{chunk-7M6MHVWA-BeGkoIBL.js → chunk-7M6MHVWA-BxPQ9AEv.js} +1 -1
  156. package/dist/web/assets/{chunk-7PRAP22T-BVWTh9sT.js → chunk-7PRAP22T-CvHw2y-F.js} +1 -1
  157. package/dist/web/assets/{chunk-GTNCS2PH-gVhX7NZP.js → chunk-GTNCS2PH-DIfN1SOI.js} +1 -1
  158. package/dist/web/assets/{chunk-GWA4HPMP-BPdnIcQH.js → chunk-GWA4HPMP-2WZX1fG-.js} +1 -1
  159. package/dist/web/assets/{chunk-MBY4JIJT-B2VfO_06.js → chunk-MBY4JIJT-BL7akw7q.js} +1 -1
  160. package/dist/web/assets/{chunk-NETBCI7D-DZF_gITO.js → chunk-NETBCI7D-CQX1tY3W.js} +1 -1
  161. package/dist/web/assets/{chunk-O7XYJQB3-CDpBWiLq.js → chunk-O7XYJQB3-CtGXf4J6.js} +1 -1
  162. package/dist/web/assets/{chunk-UA2S7LBM-Iv7TSRE_.js → chunk-UA2S7LBM-C_3M_IIp.js} +1 -1
  163. package/dist/web/assets/{chunk-WEXAMYUT-Ce6goZ2Y.js → chunk-WEXAMYUT-6MO559WJ.js} +1 -1
  164. package/dist/web/assets/{chunk-Z7XXMR3K-CY6E6_Ux.js → chunk-Z7XXMR3K-CHJ55IlF.js} +1 -1
  165. package/dist/web/assets/{chunk-ZIGJFQKS-BLzsXZBc.js → chunk-ZIGJFQKS-533qcfPb.js} +1 -1
  166. package/dist/web/assets/{classDiagram-v2-NBCMYWYE-Dz0kD9P6.js → classDiagram-v2-NBCMYWYE-CFySVswx.js} +1 -1
  167. package/dist/web/assets/copy-code-XoEu_Yh6.js +1 -0
  168. package/dist/web/assets/create-DedXY-KP.js +1 -0
  169. package/dist/web/assets/{cynefin-OW5HDTMX-DWIx3wRm.js → cynefin-OW5HDTMX-Dfg_2VTu.js} +1 -1
  170. package/dist/web/assets/{cynefinDiagram-VND7K2PF-2D80uocv.js → cynefinDiagram-VND7K2PF-DaSXiPph.js} +1 -1
  171. package/dist/web/assets/{dagre-6A5THRUB-BLBhukn-.js → dagre-6A5THRUB-D7d1gbRO.js} +1 -1
  172. package/dist/web/assets/date-snFAXn1W.js +1 -0
  173. package/dist/web/assets/{devices-store-BfZKPOhg.js → devices-store-DB_tWC1Q.js} +1 -1
  174. package/dist/web/assets/{diagram-22UHCM2B-DY8dMLZ3.js → diagram-22UHCM2B-CNuTss_x.js} +1 -1
  175. package/dist/web/assets/{diagram-3UASUU5V-Bf6Od1NH.js → diagram-3UASUU5V--Rt3-ARV.js} +1 -1
  176. package/dist/web/assets/{diagram-ATOU4E4O-CjLGcYD5.js → diagram-ATOU4E4O-BP79L-gP.js} +1 -1
  177. package/dist/web/assets/{diagram-CDSNMT55-gIvaVNvs.js → diagram-CDSNMT55-CRO5cocs.js} +1 -1
  178. package/dist/web/assets/{diagram-MLGK6HIB-VR5kiCi5.js → diagram-MLGK6HIB-Difu0Zmh.js} +1 -1
  179. package/dist/web/assets/{diagram-MPIPVDR6-CdAdj25I.js → diagram-MPIPVDR6-grQ3ie17.js} +1 -1
  180. package/dist/web/assets/diff-store-D4XiTkfi.js +93 -0
  181. package/dist/web/assets/{dist-CBGyhCYv.js → dist-75uxNoTf.js} +1 -1
  182. package/dist/web/assets/{dist-CIMEaJAX.js → dist-9rzCziV2.js} +1 -1
  183. package/dist/web/assets/{dist-CEl-Ko94.js → dist-B9i6cUYu.js} +1 -1
  184. package/dist/web/assets/{dist-yzAhvE-V.js → dist-BU-fZfEv.js} +1 -1
  185. package/dist/web/assets/{dist-CTd7Kuqx.js → dist-BeUB43Ur.js} +1 -1
  186. package/dist/web/assets/{dist-C85t5q3z.js → dist-BxIdk5Al.js} +1 -1
  187. package/dist/web/assets/{dist-joQDFmfy.js → dist-By534Syk.js} +1 -1
  188. package/dist/web/assets/{dist-C54FrSb8.js → dist-DFjLCq-0.js} +1 -1
  189. package/dist/web/assets/{dist-lgw4kcVA.js → dist-DNrP7O-J.js} +1 -1
  190. package/dist/web/assets/{dist-BU8erXQF.js → dist-Du5VPTAq.js} +1 -1
  191. package/dist/web/assets/{dist-DLuI1PxH.js → dist-DyBqP777.js} +1 -1
  192. package/dist/web/assets/{ebnfDiagram-ZINNZB2B-irTAlMFO.js → ebnfDiagram-ZINNZB2B-DX2rcvMK.js} +1 -1
  193. package/dist/web/assets/{elk-276RUBZZ-Dj5ligvC.js → elk-276RUBZZ-DSHIl9hv.js} +1 -1
  194. package/dist/web/assets/{erDiagram-OPXOYQCR-Bvn6rbL1.js → erDiagram-OPXOYQCR-BIZVJO8N.js} +1 -1
  195. package/dist/web/assets/eventmodeling-NTZA5JFV-Bh_xDKx6.js +1 -0
  196. package/dist/web/assets/flowDiagram-KWPJA3E3-DXkIxaXL.js +1 -0
  197. package/dist/web/assets/{ganttDiagram-FUAMR5RP-BNGAUF5H.js → ganttDiagram-FUAMR5RP-D4kPfh4X.js} +1 -1
  198. package/dist/web/assets/{gitGraph-4MIJSDKK-DYSHOl72.js → gitGraph-4MIJSDKK-B41R-oAb.js} +1 -1
  199. package/dist/web/assets/{gitGraphDiagram-X574FWY7-BGwRHrPq.js → gitGraphDiagram-X574FWY7-xXrZiSJI.js} +1 -1
  200. package/dist/web/assets/i18n-Cfw_OfRR.js +1 -0
  201. package/dist/web/assets/icons-BIOTvmdT.js +1 -0
  202. package/dist/web/assets/index-B1Bugudn.js +2 -0
  203. package/dist/web/assets/index-BQU3KK1E.css +1 -0
  204. package/dist/web/assets/{info-A6RAGUB7-DNWR20pW.js → info-A6RAGUB7-CgSmK-La.js} +1 -1
  205. package/dist/web/assets/{infoDiagram-VRGFBTTK-BhNwJLY5.js → infoDiagram-VRGFBTTK-CDNEJ_R-.js} +1 -1
  206. package/dist/web/assets/{init-app-cg-B_TFN.js → init-app-C3tD3faT.js} +1 -1
  207. package/dist/web/assets/{is-D0waCELe.js → is-B1kBQ5Va.js} +1 -1
  208. package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-CSkDpn64.js → ishikawaDiagram-OU5B5YK6-ZcU1IxFn.js} +1 -1
  209. package/dist/web/assets/{journeyDiagram-ZHPQQLJL-D2CEecC3.js → journeyDiagram-ZHPQQLJL-g-8ZRhJj.js} +1 -1
  210. package/dist/web/assets/{kanban-definition-PNTS6WVX-CQHlo4Hh.js → kanban-definition-PNTS6WVX-nfsfxVOE.js} +1 -1
  211. package/dist/web/assets/{line-C-izH1ks.js → line-BpuX_ban.js} +1 -1
  212. package/dist/web/assets/markdown-ogvtoQzt.js +16 -0
  213. package/dist/web/assets/mdi-Du7sIqtH.js +1 -0
  214. package/dist/web/assets/{mermaid-parser.core-CAGwq6D-.js → mermaid-parser.core-BBj_ep7Z.js} +3 -3
  215. package/dist/web/assets/{mermaid.core--xlI_0tK.js → mermaid.core-DP4USVSM.js} +4 -4
  216. package/dist/web/assets/{mindmap-definition-NLK3R4M7-BuCxhlwy.js → mindmap-definition-NLK3R4M7-C5GhUvi3.js} +1 -1
  217. package/dist/web/assets/{packet-AYTQ26CC-Bi7x5lJK.js → packet-AYTQ26CC-BIdb-vfg.js} +1 -1
  218. package/dist/web/assets/{pegDiagram-GJSIUBJH-qWzBPkCQ.js → pegDiagram-GJSIUBJH-DH-SdKj6.js} +1 -1
  219. package/dist/web/assets/{pie-WAS4IAKB-Di0wC4XB.js → pie-WAS4IAKB-Du3-jRjK.js} +1 -1
  220. package/dist/web/assets/{pieDiagram-5QR66LMP-BCDVY9q2.js → pieDiagram-5QR66LMP-CJh2ngqY.js} +1 -1
  221. package/dist/web/assets/pinia-BfqEuvsi.js +1 -0
  222. package/dist/web/assets/pinia-mdReENsc.js +1 -0
  223. package/dist/web/assets/preview-store-DOnSmm_C.js +2 -0
  224. package/dist/web/assets/{project-files-store-byqyG2ts.js → project-files-store-CHP6RYFI.js} +1 -1
  225. package/dist/web/assets/{quadrantDiagram-O4NWA36T-CpFObUjT.js → quadrantDiagram-O4NWA36T-DYsSScxc.js} +1 -1
  226. package/dist/web/assets/{radar-RG4KPBEZ-Br8yH8rq.js → radar-RG4KPBEZ-BBjvaVVB.js} +1 -1
  227. package/dist/web/assets/{railroad-74A4TZTK-CACSqhA-.js → railroad-74A4TZTK-B-CRncBU.js} +1 -1
  228. package/dist/web/assets/railroad-abnf-HS5TGJTU-D37zpoYN.js +1 -0
  229. package/dist/web/assets/railroad-ebnf-LZEXJU2U-ZnMxH6Ym.js +1 -0
  230. package/dist/web/assets/railroad-peg-WCYAUIDC-Dg3g-VsM.js +1 -0
  231. package/dist/web/assets/{railroadDiagram-XR7U4H2S-sYXRKGK1.js → railroadDiagram-XR7U4H2S-hqp-2UHb.js} +1 -1
  232. package/dist/web/assets/{render-C7fu7uYY.js → render-Brao9Nj2.js} +1 -1
  233. package/dist/web/assets/repository-store-DZgQ5H7J.js +1 -0
  234. package/dist/web/assets/{requirementDiagram-PLB6GJNP-C9I1JbQc.js → requirementDiagram-PLB6GJNP-Dhuw5jcQ.js} +1 -1
  235. package/dist/web/assets/runtime-core.esm-bundler-DDnHUoIy.js +1 -0
  236. package/dist/web/assets/{safe-storage-C76bPypO.js → safe-storage-BchoYSbq.js} +1 -1
  237. package/dist/web/assets/{sankeyDiagram-IPEJSGJF-CuvFQhPh.js → sankeyDiagram-IPEJSGJF-D5rCIxGR.js} +1 -1
  238. package/dist/web/assets/{sequenceDiagram-PO4LG4MO-CaVb9Y6e.js → sequenceDiagram-PO4LG4MO-YEHR4Mp-.js} +1 -1
  239. package/dist/web/assets/single-flight-CyDZB3rb.js +1 -0
  240. package/dist/web/assets/{stateDiagram-v2-GCMORJYK-Dp_APryr.js → stateDiagram-v2-GCMORJYK-9iWmz6Xf.js} +1 -1
  241. package/dist/web/assets/{swimlanes-2SLR337P-FclUI-k0.js → swimlanes-2SLR337P-Cjwvgt_n.js} +1 -1
  242. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-gJwxhWoO.js +8 -0
  243. package/dist/web/assets/{terminal-store-BnEkXuBj.js → terminal-store-i7HHlWzR.js} +1 -1
  244. package/dist/web/assets/theme-CQ9InaWa.js +1 -0
  245. package/dist/web/assets/{timeline-definition-EJHVYXUP-BAqwqj3c.js → timeline-definition-EJHVYXUP-Cd5n2-Py.js} +1 -1
  246. package/dist/web/assets/{treeView-Q6P3EWNA-D87jJbUQ.js → treeView-Q6P3EWNA-C_QH9vtR.js} +1 -1
  247. package/dist/web/assets/{treemap-WGGIJYW6-B6nhGhRc.js → treemap-WGGIJYW6-CVnU7TVz.js} +1 -1
  248. package/dist/web/assets/use-add-agent-context-D5VqMr0p.js +1 -0
  249. package/dist/web/assets/use-app-theme-DgC4ivPF.js +1 -0
  250. package/dist/web/assets/use-countdown-D6_qSOZJ.js +1 -0
  251. package/dist/web/assets/use-notify-error-Dx2D9IEP.js +1 -0
  252. package/dist/web/assets/use-router-link-D7geCGQI.js +1 -0
  253. package/dist/web/assets/use-row-height-BgHg4-J-.js +1 -0
  254. package/dist/web/assets/use-server-events-CvcbsbIf.js +1 -0
  255. package/dist/web/assets/use-virtual-scroll-DixIsJk4.js +1 -0
  256. package/dist/web/assets/{use-workspace-navigation-CnebLvBV.js → use-workspace-navigation-Dq-Aw8Xq.js} +1 -1
  257. package/dist/web/assets/{usecaseDiagram-POWQR4AR-7YcIKxAb.js → usecaseDiagram-POWQR4AR-Cbj2Pvab.js} +1 -1
  258. package/dist/web/assets/{vennDiagram-UO4OBE2U-BZq5cFC4.js → vennDiagram-UO4OBE2U-2j79YqCN.js} +1 -1
  259. package/dist/web/assets/viewport-store-NqQS7itT.js +1 -0
  260. package/dist/web/assets/{vue-i18n.runtime-CEtihHHL.js → vue-i18n.runtime-JOo8b7-t.js} +2 -2
  261. package/dist/web/assets/{wardley-WFR3VGLG-BT8YO9H4.js → wardley-WFR3VGLG-wsMK7zm3.js} +1 -1
  262. package/dist/web/assets/{wardleyDiagram-VNRHLVJA-rDpXFf6D.js → wardleyDiagram-VNRHLVJA-D6PKTQIJ.js} +1 -1
  263. package/dist/web/assets/weighted-lru-BFtZKA_y.js +1 -0
  264. package/dist/web/assets/workspace-navigation-CoXKJJpP.js +1 -0
  265. package/dist/web/assets/{xychartDiagram-PMCCYNJV-ClniUuZc.js → xychartDiagram-PMCCYNJV-D1fQN7KG.js} +1 -1
  266. package/dist/web/index.html +10 -9
  267. package/package.json +5 -3
  268. package/dist/web/assets/AccessPage-CX3w30zw.js +0 -1
  269. package/dist/web/assets/AppPage-PFJG281y.js +0 -1
  270. package/dist/web/assets/CreateButton-Ch0b7juj.js +0 -1
  271. package/dist/web/assets/CreateReviewFabButton-DTuJzw3q.js +0 -1
  272. package/dist/web/assets/IndexPage-tgW07Qvs.js +0 -1
  273. package/dist/web/assets/MainLayout-C6yBhQnf.css +0 -1
  274. package/dist/web/assets/MainLayout-Cw4jpB1x.js +0 -8
  275. package/dist/web/assets/NoteVisualEditor-DiGhLhQg.js +0 -1054
  276. package/dist/web/assets/NotesPage-CVyVr9tl.js +0 -4
  277. package/dist/web/assets/NotesPage-CxGnZuVQ.css +0 -1
  278. package/dist/web/assets/PanelResize-B6FP9ZVB.js +0 -1
  279. package/dist/web/assets/ProjectFilePage-CkxfX9b1.js +0 -1
  280. package/dist/web/assets/QBtn-CyyV1Bx_.js +0 -1
  281. package/dist/web/assets/QExpansionItem-Dp9lbdVb.js +0 -4
  282. package/dist/web/assets/QFab-LOmZ9rev.js +0 -1
  283. package/dist/web/assets/QInput-Dq6131uz.js +0 -1
  284. package/dist/web/assets/QSelect-B34OqtIH.js +0 -1
  285. package/dist/web/assets/QSpace-BhOVGpQh.js +0 -1
  286. package/dist/web/assets/QVirtualScroll-BYgJ1Kh2.js +0 -1
  287. package/dist/web/assets/ReviewDetailPage-CkCilMNW.css +0 -1
  288. package/dist/web/assets/ReviewDetailPage-GNjBa4X0.js +0 -1
  289. package/dist/web/assets/ReviewsPage-An5fRS92.js +0 -1
  290. package/dist/web/assets/StatusSwitcher-DrFHHwGm.js +0 -1
  291. package/dist/web/assets/architecture-7GRP2DOG-BPCNj4lR.js +0 -1
  292. package/dist/web/assets/channel-CzRYxuLe.js +0 -1
  293. package/dist/web/assets/create-B9Tn5Xvi.js +0 -1
  294. package/dist/web/assets/diff-store-B4adGxC2.js +0 -93
  295. package/dist/web/assets/eventmodeling-NTZA5JFV-BJsTZ_nG.js +0 -1
  296. package/dist/web/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-Dr0goTwe.woff +0 -0
  297. package/dist/web/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ-D-x-0Q06.woff2 +0 -0
  298. package/dist/web/assets/flowDiagram-KWPJA3E3-CvXh1Df7.js +0 -1
  299. package/dist/web/assets/i18n-DnlAcIbT.js +0 -1
  300. package/dist/web/assets/index-Cw7GJi3K.js +0 -2
  301. package/dist/web/assets/index-wsOPzloa.css +0 -1
  302. package/dist/web/assets/markdown-CvtLTiBZ.js +0 -16
  303. package/dist/web/assets/pinia-DO0AdKGg.js +0 -1
  304. package/dist/web/assets/pinia-uOZCmBi-.js +0 -1
  305. package/dist/web/assets/preview-store-DyO8G-ox.js +0 -1
  306. package/dist/web/assets/railroad-abnf-HS5TGJTU-DTBsRB1c.js +0 -1
  307. package/dist/web/assets/railroad-ebnf-LZEXJU2U-D3mrY4ar.js +0 -1
  308. package/dist/web/assets/railroad-peg-WCYAUIDC-33ZjWX0u.js +0 -1
  309. package/dist/web/assets/repository-store-DtRDth1L.js +0 -1
  310. package/dist/web/assets/runtime-core.esm-bundler-CAvPiMpd.js +0 -1
  311. package/dist/web/assets/single-flight-fPyIy7h5.js +0 -1
  312. package/dist/web/assets/swimlanesDiagram-TC7HE7FX-CuUvsn0e.js +0 -8
  313. package/dist/web/assets/theme-CnbaLamF.js +0 -1
  314. package/dist/web/assets/use-add-agent-context-xHAjjOf1.js +0 -1
  315. package/dist/web/assets/use-app-theme-DEowpWRR.js +0 -1
  316. package/dist/web/assets/use-countdown-DlcwwJrs.js +0 -1
  317. package/dist/web/assets/use-panel-width-CjSWCFr4.js +0 -1
  318. package/dist/web/assets/use-router-link-CUoYaYUw.js +0 -1
  319. package/dist/web/assets/use-row-height-BsE9-rO2.js +0 -1
  320. package/dist/web/assets/use-server-events-C2X4Xz00.js +0 -1
  321. package/dist/web/assets/use-virtual-scroll-BAZGswHv.js +0 -1
  322. package/dist/web/assets/viewport-store-CCHiY2QG.js +0 -1
  323. package/dist/web/assets/weighted-lru-BGovtJ2a.js +0 -1
  324. package/dist/web/assets/workspace-navigation-DdW0rSGz.js +0 -1
  325. /package/dist/web/assets/{PanelResize-XjrbOj2S.css → AddToAgentButton-XjrbOj2S.css} +0 -0
package/README.md CHANGED
@@ -22,6 +22,9 @@ staged/unstaged diff, сравнение веток и коммитов, бра
22
22
  - Чаты с ACP-агентами (Claude Code, Cursor, Codex, pi): до 5 чатов во
23
23
  вкладках, контекст — diff, файл целиком, ревью, вложения и `@`-файлы и папки из
24
24
  репозитория. Подробнее — в разделе «Агенты» ниже.
25
+ - Раздел **Artifacts**: неизменяемые Markdown-документы, поиск и справочники,
26
+ комментарии по строкам и редакциям, проверка и подтверждение принятия,
27
+ контекст документов в чате и экспорт оригинала/истории.
25
28
  - Ручной/авто выбор тёмной-светлой темы.
26
29
  - CLI: `serve` (поднять сервер), `list`/`export` (быстрый доступ к
27
30
  сохранённым ревью без веб-интерфейса).
@@ -130,8 +133,34 @@ Tailscale) разрешается флагом `--allowed-host <имя>`, его
130
133
  - **Подтверждения.** Запросы разрешений приходят карточкой в чат. Для
131
134
  отдельного чата можно включить автоподтверждение (кнопка-щит) — агент
132
135
  тогда меняет файлы и выполняет команды без вашего ответа; включайте его
133
- только для работы, которую готовы проверить и откатить. pi вообще не
134
- спрашивает.
136
+ только для работы, которую готовы проверить и откатить. Native tools pi
137
+ выполняются без ACP-подтверждений; его MCP-вызовы требуют разрешения.
138
+ - **Артефакты через MCP.** Агенты внутри работающего GitHuman получают
139
+ инструменты создания неизменяемых черновиков, чтения содержимого и истории,
140
+ просмотра связей, работы с задачами и типами, [поиска с опечатками](docs/artifact-search.md).
141
+ Проверены Claude Code и штатный локальный мост pi; остальные
142
+ ACP-пресеты пока не проверены на поддержку этих инструментов.
143
+ Самостоятельный MCP без GitHuman не поддерживается. Раздел Artifacts показывает
144
+ документы и позволяет подтверждать точные предложения агента. Статус документа
145
+ меняется кнопкой в шапке: одно «Да» запускает проверку и применение на сервере;
146
+ принятие документов требует проверки и пользовательского разрешения;
147
+ [жизненный цикл и API](docs/artifact-lifecycle.md).
148
+ Ревью артефактов отложено; обсуждения и блокирующие замечания удалены.
149
+ - **Локальный мост pi** — в пакет включена команда
150
+ `githuman pi-acp --stdio`, использующая установленный pi, его авторизацию
151
+ и выбор моделей. MCP-вызовы проходят отдельное ACP-подтверждение;
152
+ валидатор получает серверный профиль с запретом native tools. Штатный
153
+ preset использует этот мост без runtime npx и подбора внешнего адаптера.
154
+ Явные пользовательские command/args overrides сохраняются. Для ручной
155
+ проверки нужен авторизованный pi с настроенной моделью.
156
+ При аварийном падении/SIGKILL pi запущенные native shell-команды могут
157
+ продолжить работу после закрытия чата. Очистка таких процессов — best effort;
158
+ это явно принятое ограничение обычного чата, не ослабление MCP-подтверждений.
159
+ Валидация через прежнюю или произвольную команду pi недоступна.
160
+ Проверки выполняются на Linux; macOS-проверки пропущены по поручению
161
+ пользователя, поддержка macOS не подтверждена. Windows не поддерживается.
162
+ Подробное руководство по MCP-интеграции: [русский](docs/pi-mcp-integration.md) ·
163
+ [English](docs/pi-mcp-integration.en.md).
135
164
  - **Свои команды запуска** — `<репозиторий>/.githuman/ght-agents.json`:
136
165
  `{ "cursor": { "args": ["--model", "<модель>", "acp"] } }`. Допустимы поля
137
166
  `command`, `args`, `env`; любое другое (в том числе опечатка) — ошибка
@@ -168,6 +197,18 @@ node dist/cli/index.js list --db-prefix "" # .githuman/reviews.db (ор
168
197
  `--api-docs` (`pnpm run dev:server` включает его сам). Агентские маршруты
169
198
  попадают в спецификацию, только когда сервер их отдаёт (loopback-хост).
170
199
 
200
+ ### Отладка валидации артефактов
201
+
202
+ `githuman serve --debug-validation` не закрывает сессию валидатора после
203
+ завершения проверки и пишет в консоль сервера строки `[validation <id>]`:
204
+ статусы сессии, вызовы инструментов, решения политики прав (ALLOW/DENY с
205
+ причиной), причину завершения. Текст вывода инструментов обрезается до 500
206
+ символов. Флаг нужен для отладки: в обычном режиме сессия закрывается, а
207
+ причина остановки валидатора нигде не сохраняется. Оставленная открытой
208
+ сессия не занимает место в лимите чатов: новый чат закрывает самую старую
209
+ завершённую сессию валидатора. Ключ артефактной сессии такого валидатора
210
+ отзывается сразу при завершении проверки.
211
+
171
212
  ## Разработка
172
213
 
173
214
  Два процесса нужны одновременно — backend (Fastify, автоперезапуск при
@@ -245,6 +286,37 @@ MIT, см. [LICENSE](LICENSE).
245
286
 
246
287
  Для разработки на другом порту backend можно передать `GITHUMAN_DEV_API=http://localhost:3848` при запуске Quasar dev-сервера.
247
288
 
289
+ ## Артефакты
290
+
291
+ Раздел **Artifacts** хранит неизменяемые Markdown-документы, созданные агентом
292
+ через MCP. Каталог поддерживает обычный поиск и поиск с опечатками, фильтры по
293
+ статусу, типу, задаче и тегу и группировку загруженных результатов; порядок
294
+ фиксирован (новые сверху), переключателя сортировки нет. Документ показывается
295
+ как Markdown; редактирования body и режима Source нет. Обсуждения, комментарии и
296
+ блокирующие замечания удалены (ADR 0097). Кнопка добавления в чат прикладывает
297
+ контекст документа; задачи чата назначаются через Tasks в панели чата.
298
+
299
+ Статус документа меняется кнопкой в шапке: меню показывает только допустимые
300
+ переходы, диалог — точные последствия и выбор валидатора. Одно «Да» запускает на
301
+ сервере проверку независимым валидатором и применение при свежем pass; повторного
302
+ подтверждения нет, работа продолжается после закрытия вкладки и показывает
303
+ стадию, отмену и результат проверки. Это отдельный путь от MCP/API жизненного
304
+ цикла (`change_sets`, `actions`, `validations`), где агент запрашивает действие
305
+ и использует выданное пользователем разрешение; очереди таких запросов в
306
+ интерфейсе нет. Подробности и ограничения — в
307
+ [жизненном цикле](docs/artifact-lifecycle.md) и
308
+ [матрице возможностей](docs/artifact-capabilities.md).
309
+
310
+ Если текст документа не читается (повреждённый или недоступный файл), метаданные,
311
+ история, связи и выгрузка JSON остаются доступны, а тело заменяется ошибкой с
312
+ кнопкой «Retry»; оригинал при повреждении не выгружается. Исходный путь
313
+ импорта (`sourcePath`), если он есть, показан в метаданных как обычный текст.
314
+
315
+ Download artifact выгружает точный оригинал с историческим frontmatter либо
316
+ JSON актуальных метаданных и полной истории. Текущие метаданные и исходный
317
+ frontmatter показаны отдельно. История и файлы сохраняются в `.githuman/`;
318
+ существующие Markdown-файлы репозитория автоматически не импортируются.
319
+
248
320
  ## Проектные заметки
249
321
 
250
322
  Раздел **Notes** хранит Markdown-заметки в `.githuman/notes/` относительно
@@ -0,0 +1,112 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
+ import { Value } from '@sinclair/typebox/value';
5
+ import { ARTIFACT_TASK_INSTRUCTIONS } from "../../shared/artifact-tools/instructions.js";
6
+ import { ARTIFACT_TOOL_DESCRIPTIONS } from "../../shared/artifact-tools/descriptions.js";
7
+ import { ArtifactToolSchemas } from "../../shared/artifact-tools/schemas.js";
8
+ import { ARTIFACT_AGENT_KEY_ENV, ARTIFACT_AGENT_KEY_PATTERN, ARTIFACT_AGENT_URL_ENV, ARTIFACT_BRIDGE_PATH_PREFIX, ARTIFACT_MCP_MAX_MESSAGE_BYTES } from "../../shared/artifacts/mcp-constants.js";
9
+ import { isRecord } from "../../shared/utils/guards.js";
10
+ import { getAppVersion } from "../../server/app-version.js";
11
+ // Fail boundedly when serve disappears; retries use the original request ID.
12
+ const REQUEST_TIMEOUT_MS = 30_000;
13
+ // MCP tool names allow no dots, so operation names map dots to underscores.
14
+ const TOOLS = new Map(Object.entries(ArtifactToolSchemas).map(([operation, schema]) => [
15
+ operation.replaceAll('.', '_'),
16
+ {
17
+ operation,
18
+ schema,
19
+ description: ARTIFACT_TOOL_DESCRIPTIONS[operation] ?? schema.description
20
+ }
21
+ ]));
22
+ function toolError(text) {
23
+ return { isError: true, content: [{ type: 'text', text }] };
24
+ }
25
+ export async function runMcp(argv) {
26
+ if (argv.length !== 1 || argv[0] !== '--stdio') {
27
+ throw new Error('Usage: githuman mcp --stdio');
28
+ }
29
+ const endpoint = process.env[ARTIFACT_AGENT_URL_ENV];
30
+ const key = process.env[ARTIFACT_AGENT_KEY_ENV];
31
+ if (!endpoint || !key || !ARTIFACT_AGENT_KEY_PATTERN.test(key)) {
32
+ throw new Error('Artifact MCP requires a running GitHuman agent session.');
33
+ }
34
+ const url = new URL(endpoint);
35
+ if (url.protocol !== 'http:' ||
36
+ url.username ||
37
+ url.password ||
38
+ url.pathname !== '/' ||
39
+ url.search ||
40
+ url.hash) {
41
+ throw new Error('Invalid GitHuman server address.');
42
+ }
43
+ const server = new Server({ name: 'githuman-artifacts', version: getAppVersion() }, { capabilities: { tools: {} }, instructions: ARTIFACT_TASK_INSTRUCTIONS });
44
+ const active = new AbortController();
45
+ server.setRequestHandler(ListToolsRequestSchema, () => ({
46
+ tools: [...TOOLS].map(([name, { schema, description }]) => ({
47
+ name,
48
+ description,
49
+ inputSchema: { ...schema, type: 'object' }
50
+ }))
51
+ }));
52
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
53
+ const tool = TOOLS.get(request.params.name);
54
+ if (!tool) {
55
+ return toolError(`Unknown artifact tool "${request.params.name}".`);
56
+ }
57
+ const args = request.params.arguments ?? {};
58
+ // The message names the field and the rule, never the rejected value.
59
+ const invalid = Value.Errors(tool.schema, args).First();
60
+ if (invalid) {
61
+ return toolError(`Invalid parameters for ${request.params.name}: ${invalid.path || '/'} ${invalid.message}.`);
62
+ }
63
+ let response;
64
+ try {
65
+ response = await fetch(new URL(`${ARTIFACT_BRIDGE_PATH_PREFIX}${tool.operation}`, url), {
66
+ method: 'POST',
67
+ redirect: 'error',
68
+ headers: {
69
+ authorization: `Bearer ${key}`,
70
+ 'content-type': 'application/json'
71
+ },
72
+ body: JSON.stringify(args),
73
+ signal: AbortSignal.any([
74
+ active.signal,
75
+ extra.signal,
76
+ AbortSignal.timeout(REQUEST_TIMEOUT_MS)
77
+ ])
78
+ });
79
+ }
80
+ catch (error) {
81
+ const name = error instanceof Error ? error.name : '';
82
+ return toolError(name === 'TimeoutError' || name === 'AbortError'
83
+ ? 'The GitHuman artifact request timed out or was cancelled.'
84
+ : 'GitHuman artifact server is unavailable.');
85
+ }
86
+ let result;
87
+ try {
88
+ result = await response.json();
89
+ }
90
+ catch {
91
+ result = undefined;
92
+ }
93
+ if (!isRecord(result)) {
94
+ return toolError(`GitHuman artifact server returned an unreadable response (HTTP ${response.status}).`);
95
+ }
96
+ return {
97
+ isError: !response.ok,
98
+ content: [{ type: 'text', text: JSON.stringify(result) }],
99
+ structuredContent: result
100
+ };
101
+ });
102
+ const transport = new StdioServerTransport(undefined, undefined, {
103
+ maxBufferSize: ARTIFACT_MCP_MAX_MESSAGE_BYTES
104
+ });
105
+ // oxlint-disable-next-line unicorn/prefer-add-event-listener -- MCP SDK exposes a callback property, not EventTarget
106
+ server.onclose = () => active.abort();
107
+ process.stdin.once('end', () => {
108
+ active.abort();
109
+ void server.close();
110
+ });
111
+ await server.connect(transport);
112
+ }
@@ -0,0 +1,21 @@
1
+ import * as acp from '@agentclientprotocol/sdk';
2
+ import { Readable, Writable } from 'node:stream';
3
+ import { createPiAgent } from "../../server/adapters/pi-acp/agent.js";
4
+ export function runPiAcp(argv) {
5
+ if (argv.length !== 1 || argv[0] !== '--stdio') {
6
+ throw new Error('Usage: githuman pi-acp --stdio');
7
+ }
8
+ const profile = process.env.GITHUMAN_PI_PROFILE ?? 'chat';
9
+ if (profile !== 'chat' && profile !== 'validator') {
10
+ throw new Error('Invalid trusted pi launch profile');
11
+ }
12
+ const agent = createPiAgent(profile);
13
+ agent.connect(acp.ndJsonStream(Writable.toWeb(process.stdout),
14
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Node and DOM streams have equivalent runtime contracts.
15
+ Readable.toWeb(process.stdin)));
16
+ const shutdown = () => {
17
+ agent.close();
18
+ };
19
+ process.once('SIGTERM', shutdown);
20
+ process.once('SIGINT', shutdown);
21
+ }
@@ -1,5 +1,7 @@
1
+ import { DEFAULT_DB_PREFIX } from "../shared/app/storage-constants.js";
1
2
  import { isIP } from 'node:net';
2
3
  import { parseArgs } from 'node:util';
4
+ import { isValidFilenamePrefix } from "../shared/utils/is-valid-filename-prefix.js";
3
5
  import { isLoopbackHost } from "../shared/network/loopback.js";
4
6
  import { WILDCARD_HOSTS } from "../server/utils/lan-addresses.js";
5
7
  const DEFAULT_PORT = 3847;
@@ -13,7 +15,7 @@ const HOST_NAME_PATTERN = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:
13
15
  * without a prefix, running both tools against the same repository would
14
16
  * silently corrupt or crash on the other tool's database file.
15
17
  */
16
- export const DEFAULT_DB_PREFIX = 'ght-';
18
+ export { DEFAULT_DB_PREFIX };
17
19
  /**
18
20
  * `GITHUMAN_DB_PREFIX` is intentionally not one of the env vars the original
19
21
  * mcollina/githuman CLI reads (`GITHUMAN_DB_PATH`, `GITHUMAN_TOKEN`), so
@@ -86,6 +88,7 @@ export function parseServeArgs(argv) {
86
88
  'notes-dir': { type: 'string' },
87
89
  'db-prefix': { type: 'string' },
88
90
  'api-docs': { type: 'boolean', default: false },
91
+ 'debug-validation': { type: 'boolean', default: false },
89
92
  'allowed-host': { type: 'string', multiple: true }
90
93
  },
91
94
  strict: false
@@ -94,7 +97,12 @@ export function parseServeArgs(argv) {
94
97
  const host = resolveHost(typeof values.host === 'string' ? values.host : undefined);
95
98
  const open = values['no-open'] === true ? false : values.open !== false;
96
99
  const dbPrefix = resolveDbPrefix(typeof values['db-prefix'] === 'string' ? values['db-prefix'] : undefined);
100
+ // Only `serve` creates artifact files, so only it needs a filename-safe prefix.
101
+ if (!isValidFilenamePrefix(dbPrefix)) {
102
+ throw new Error(`Invalid --db-prefix value "${dbPrefix}": use at most 100 characters and none of < > : " / \\ | ? * or control characters. Set it with --db-prefix or GITHUMAN_DB_PREFIX.`);
103
+ }
97
104
  const apiDocs = values['api-docs'] === true;
105
+ const debugValidation = values['debug-validation'] === true;
98
106
  const allowedHosts = resolveAllowedHosts(Array.isArray(values['allowed-host']) ? values['allowed-host'] : []);
99
107
  return {
100
108
  port,
@@ -102,6 +110,7 @@ export function parseServeArgs(argv) {
102
110
  open,
103
111
  dbPrefix,
104
112
  apiDocs,
113
+ debugValidation,
105
114
  allowedHosts,
106
115
  ...(typeof values['notes-dir'] === 'string'
107
116
  ? { notesDir: values['notes-dir'] }
package/dist/cli/index.js CHANGED
@@ -1,18 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { errorMessage } from "../shared/utils/error-message.js";
3
3
  import { writeFileSync } from 'node:fs';
4
- import { parseServeArgs } from "./config.js";
5
- import { startServer, resolveRepositoryPath, resolveReviewsDbPath } from "./server-runtime.js";
6
- import { formatStartupMessage } from "./startup-message.js";
7
- import { lanAddresses } from "../server/utils/lan-addresses.js";
8
- import { parseListArgs, runList } from "./commands/list.js";
9
- import { parseExportArgs, runExport } from "./commands/export.js";
10
- import { createFileDatabase } from "../server/db/index.js";
11
4
  import { getAppVersion } from "../server/app-version.js";
12
5
  // Force exit when a graceful close hangs. It must exceed the terminal kill time: ps timeout plus grace.
13
6
  const SHUTDOWN_TIMEOUT_MS = 5000;
14
7
  /** Opens the reviews DB for the repo at cwd, shared by `list` and `export`. */
15
8
  async function openReviewsDb(dbPrefix) {
9
+ const { resolveRepositoryPath, resolveReviewsDbPath } = await import("./server-runtime.js");
10
+ const { createFileDatabase } = await import("../server/db/index.js");
16
11
  const repositoryPath = await resolveRepositoryPath(process.cwd());
17
12
  return {
18
13
  db: createFileDatabase(resolveReviewsDbPath(repositoryPath, dbPrefix)),
@@ -20,10 +15,24 @@ async function openReviewsDb(dbPrefix) {
20
15
  };
21
16
  }
22
17
  async function main(argv) {
18
+ if (argv[0] === 'pi-acp') {
19
+ const { runPiAcp } = await import("./commands/pi-acp.js");
20
+ runPiAcp(argv.slice(1));
21
+ return;
22
+ }
23
+ if (argv[0] === 'mcp') {
24
+ const { runMcp } = await import("./commands/mcp.js");
25
+ await runMcp(argv.slice(1));
26
+ return;
27
+ }
23
28
  console.log(`githuman v${getAppVersion()}`);
24
29
  const [command, ...rest] = argv;
25
30
  switch (command) {
26
31
  case 'serve': {
32
+ const { parseServeArgs } = await import("./config.js");
33
+ const { startServer } = await import("./server-runtime.js");
34
+ const { formatStartupMessage } = await import("./startup-message.js");
35
+ const { lanAddresses } = await import("../server/utils/lan-addresses.js");
27
36
  const options = parseServeArgs(rest);
28
37
  const { app, url } = await startServer(options);
29
38
  let stopping = false;
@@ -52,12 +61,14 @@ async function main(argv) {
52
61
  return;
53
62
  }
54
63
  case 'list': {
64
+ const { parseListArgs, runList } = await import("./commands/list.js");
55
65
  const options = parseListArgs(rest);
56
66
  const { db } = await openReviewsDb(options.dbPrefix);
57
67
  console.log(runList(db, options));
58
68
  return;
59
69
  }
60
70
  case 'export': {
71
+ const { parseExportArgs, runExport } = await import("./commands/export.js");
61
72
  const options = parseExportArgs(rest);
62
73
  const { db, repositoryPath } = await openReviewsDb(options.dbPrefix);
63
74
  const output = await runExport(db, options.id, options.format, repositoryPath);
@@ -71,7 +82,7 @@ async function main(argv) {
71
82
  }
72
83
  default:
73
84
  console.error(`Unknown command: ${command ?? '(none)'}`);
74
- console.error('Usage: githuman serve|list|export [options]');
85
+ console.error('Usage: githuman serve|list|export|mcp|pi-acp [options]');
75
86
  process.exitCode = 1;
76
87
  }
77
88
  }
@@ -66,8 +66,13 @@ export async function startServer(options) {
66
66
  projectPath: process.cwd(),
67
67
  notesDir: options.notesDir,
68
68
  db,
69
+ artifactPrefix: resolveDbPrefix(options.dbPrefix),
69
70
  watchFiles: true,
70
71
  apiDocs: options.apiDocs === true,
72
+ // The server logs are off; validation debug lines go to the console.
73
+ ...(options.debugValidation === true
74
+ ? { onValidationDebug: (line) => console.log(line) }
75
+ : {}),
71
76
  allowedHosts: options.allowedHosts ?? [],
72
77
  onPairingRequest: device => console.log(`Pairing request from ${device.name} (${device.address}). Enter the code from the device in a localhost tab.`),
73
78
  terminalEnabled: true,
@@ -0,0 +1,88 @@
1
+ import { ArtifactToolSchemas } from "../../../shared/artifact-tools/schemas.js";
2
+ import { ARTIFACT_MCP_SERVER_NAME } from "../../../shared/artifacts/mcp-constants.js";
3
+ import { isRecord } from "../../../shared/utils/guards.js";
4
+ // MCP names replace operation dots with underscores on the stdio bridge.
5
+ const OPERATIONS = new Map(Object.entries(ArtifactToolSchemas).map(([operation, schema]) => [
6
+ operation.replaceAll('.', '_'),
7
+ { operation, schema }
8
+ ]));
9
+ // Claude's qualified name binds an operation to the configured server.
10
+ const CLAUDE_PREFIX = `mcp__${ARTIFACT_MCP_SERVER_NAME}__`;
11
+ export function artifactPermissionCall(request, previous, presetId) {
12
+ const call = request.toolCall;
13
+ const pi = call['_meta']?.githumanPi;
14
+ if (pi !== undefined &&
15
+ (!isRecord(pi) ||
16
+ pi.server !== ARTIFACT_MCP_SERVER_NAME ||
17
+ pi.registryGeneration !== 1 ||
18
+ call.name !== `${CLAUDE_PREFIX}${String(pi.tool)}`)) {
19
+ return undefined;
20
+ }
21
+ const claude = call['_meta']?.claudeCode;
22
+ const metadataName = isRecord(claude) ? claude.toolName : undefined;
23
+ const name = call.name ?? metadataName;
24
+ if (name !== undefined) {
25
+ if (typeof name !== 'string' || !name.startsWith(CLAUDE_PREFIX)) {
26
+ return undefined;
27
+ }
28
+ if (metadataName !== undefined && metadataName !== name)
29
+ return undefined;
30
+ if (previous?.name !== undefined &&
31
+ previous.name !== null &&
32
+ previous.name !== name) {
33
+ return undefined;
34
+ }
35
+ if (isRecord(claude) && claude.mcpServer !== undefined) {
36
+ if (!isRecord(claude.mcpServer) ||
37
+ claude.mcpServer.name !== ARTIFACT_MCP_SERVER_NAME) {
38
+ return undefined;
39
+ }
40
+ }
41
+ const operation = OPERATIONS.get(name.slice(CLAUDE_PREFIX.length));
42
+ return operation ? { ...operation, input: call.rawInput } : undefined;
43
+ }
44
+ // Cursor supplies MCP identity in the correlated tool update, not the permission card.
45
+ if (presetId === 'cursor' && call.kind === 'other') {
46
+ if (call.rawInput !== undefined ||
47
+ request['_meta']?.is_mcp_tool_approval !== undefined ||
48
+ !previous ||
49
+ previous.toolCallId !== call.toolCallId ||
50
+ previous.kind !== 'other' ||
51
+ (previous.name !== undefined && previous.name !== null)) {
52
+ return undefined;
53
+ }
54
+ const input = previous.rawInput;
55
+ if (!isRecord(input) ||
56
+ input.providerIdentifier !== ARTIFACT_MCP_SERVER_NAME ||
57
+ typeof input.toolName !== 'string' ||
58
+ !isRecord(input.args) ||
59
+ Object.keys(input).some(key => !['providerIdentifier', 'toolName', 'args'].includes(key))) {
60
+ return undefined;
61
+ }
62
+ const operation = OPERATIONS.get(input.toolName);
63
+ return operation ? { ...operation, input: input.args } : undefined;
64
+ }
65
+ // Codex omits call details only for a correlated MCP approval, not an elicitation.
66
+ if (request['_meta']?.is_mcp_tool_approval !== true ||
67
+ call.rawInput !== undefined ||
68
+ call.kind !== 'execute') {
69
+ return undefined;
70
+ }
71
+ if (!previous ||
72
+ previous.toolCallId !== call.toolCallId ||
73
+ previous.kind !== 'execute' ||
74
+ (previous.name !== undefined && previous.name !== null)) {
75
+ return undefined;
76
+ }
77
+ const input = previous.rawInput;
78
+ if (!isRecord(input) ||
79
+ input.server !== ARTIFACT_MCP_SERVER_NAME ||
80
+ typeof input.tool !== 'string') {
81
+ return undefined;
82
+ }
83
+ if (Object.keys(input).some(key => !['server', 'tool', 'arguments'].includes(key))) {
84
+ return undefined;
85
+ }
86
+ const operation = OPERATIONS.get(input.tool);
87
+ return operation ? { ...operation, input: input.arguments } : undefined;
88
+ }
@@ -0,0 +1,98 @@
1
+ import { errorMessage } from "../../../shared/utils/error-message.js";
2
+ import * as acp from '@agentclientprotocol/sdk';
3
+ import { PiSession } from "./session.js";
4
+ export function createPiAgent(profile) {
5
+ let session;
6
+ let used = false;
7
+ let connection;
8
+ const app = acp
9
+ .agent({ name: 'githuman-pi' })
10
+ .onRequest(acp.methods.agent.initialize, () => ({
11
+ protocolVersion: acp.PROTOCOL_VERSION,
12
+ agentCapabilities: {
13
+ promptCapabilities: { image: true, embeddedContext: true },
14
+ mcpCapabilities: { http: false, sse: false },
15
+ loadSession: false
16
+ }
17
+ }))
18
+ .onRequest(acp.methods.agent.session.new, async (ctx) => {
19
+ if (used) {
20
+ throw new acp.RequestError(-32602, 'One pi bridge process supports exactly one session/new');
21
+ }
22
+ used = true;
23
+ session = new PiSession(profile, {
24
+ update: (sessionId, update) => ctx.client.notify(acp.methods.client.session.update, {
25
+ sessionId,
26
+ update
27
+ }),
28
+ permission: (request, signal) => ctx.client.request(acp.methods.client.session.requestPermission, request, { cancellationSignal: signal }),
29
+ failure: () => connection?.close(new Error('Pi bridge runtime or MCP failed'))
30
+ });
31
+ try {
32
+ await session.start(ctx.params.cwd, ctx.params.mcpServers);
33
+ }
34
+ catch (error) {
35
+ throw new acp.RequestError(-32000, errorMessage(error), {
36
+ githumanBridge: { version: 1, profile, phase: 'startup' }
37
+ });
38
+ }
39
+ return {
40
+ sessionId: session.id,
41
+ configOptions: session.config,
42
+ _meta: {
43
+ githumanBridge: { version: 1, profile, registryGeneration: 1 }
44
+ }
45
+ };
46
+ })
47
+ .onRequest(acp.methods.agent.session.prompt, async (ctx) => {
48
+ if (!session) {
49
+ throw new acp.RequestError(-32602, 'Pi session has not been created');
50
+ }
51
+ session.assertSession(ctx.params.sessionId);
52
+ try {
53
+ return await session.prompt(ctx.params.prompt);
54
+ }
55
+ catch (error) {
56
+ throw new acp.RequestError(-32000, errorMessage(error), {
57
+ githumanBridge: { version: 1, profile, phase: 'prompt' }
58
+ });
59
+ }
60
+ })
61
+ .onNotification(acp.methods.agent.session.cancel, async (ctx) => {
62
+ if (!session) {
63
+ throw new acp.RequestError(-32602, 'Pi session has not been created');
64
+ }
65
+ session.assertSession(ctx.params.sessionId);
66
+ await session.cancel();
67
+ })
68
+ .onRequest(acp.methods.agent.session.setMode, async (ctx) => {
69
+ if (!session) {
70
+ throw new acp.RequestError(-32602, 'Pi session has not been created');
71
+ }
72
+ session.assertSession(ctx.params.sessionId);
73
+ await session.setConfig('thought_level', ctx.params.modeId);
74
+ return {};
75
+ })
76
+ .onRequest(acp.methods.agent.session.setConfigOption, async (ctx) => {
77
+ if (!session) {
78
+ throw new acp.RequestError(-32602, 'Pi session has not been created');
79
+ }
80
+ session.assertSession(ctx.params.sessionId);
81
+ if (typeof ctx.params.value !== 'string') {
82
+ throw new acp.RequestError(-32602, 'Invalid pi setting');
83
+ }
84
+ await session.setConfig(ctx.params.configId, ctx.params.value);
85
+ return { configOptions: session.config };
86
+ });
87
+ return {
88
+ connect(stream) {
89
+ connection = app.connect(stream);
90
+ void connection.closed.then(() => session?.close());
91
+ return connection;
92
+ },
93
+ close() {
94
+ session?.close();
95
+ connection?.close();
96
+ }
97
+ };
98
+ }
@@ -0,0 +1,57 @@
1
+ import { mkdtemp, rm } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { execFile } from 'node:child_process';
5
+ import { promisify } from 'node:util';
6
+ // Probe only flags needed for isolation. Do not infer capabilities from semver.
7
+ const REQUIRED_FLAGS = [
8
+ '--mode',
9
+ '--no-session',
10
+ '--no-extensions',
11
+ '--no-skills',
12
+ '--no-prompt-templates',
13
+ '--no-themes',
14
+ '--no-context-files',
15
+ '--no-builtin-tools',
16
+ '--offline'
17
+ ];
18
+ // Bound runtime discovery before opening a session.
19
+ const PROBE_TIMEOUT_MS = 10000;
20
+ const execute = promisify(execFile);
21
+ export async function piLaunchArgs(command, profile, extension) {
22
+ if (process.platform !== 'linux' && process.platform !== 'darwin') {
23
+ throw new Error('Pi bridge requires Linux or macOS (macOS verification was skipped).');
24
+ }
25
+ let help;
26
+ const probeDir = await mkdtemp(join(tmpdir(), 'githuman-pi-probe-'));
27
+ try {
28
+ const result = await execute(command, ['--help'], {
29
+ cwd: probeDir,
30
+ env: {
31
+ PATH: process.env.PATH,
32
+ HOME: probeDir,
33
+ PI_CODING_AGENT_DIR: probeDir,
34
+ PI_OFFLINE: '1'
35
+ },
36
+ timeout: PROBE_TIMEOUT_MS,
37
+ maxBuffer: 256 * 1024
38
+ });
39
+ help = result.stdout;
40
+ }
41
+ catch {
42
+ throw new Error('Pi bridge could not probe the installed pi executable.');
43
+ }
44
+ finally {
45
+ await rm(probeDir, { recursive: true, force: true });
46
+ }
47
+ if (REQUIRED_FLAGS.some(flag => !help.includes(flag))) {
48
+ throw new Error('Unsupported pi runtime: required RPC/isolation flags are missing. Control versions start at pi 0.81.0; install a compatible runtime.');
49
+ }
50
+ const args = ['--mode', 'rpc', '--no-session', '--no-themes', '-e', extension];
51
+ if (profile === 'validator') {
52
+ args.push('--no-extensions', '--no-skills', '--no-prompt-templates', '--no-context-files', '--no-builtin-tools', '--offline');
53
+ if (help.includes('--no-mcp'))
54
+ args.push('--no-mcp');
55
+ }
56
+ return args;
57
+ }