@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.
- package/README.md +74 -2
- package/dist/cli/commands/mcp.js +112 -0
- package/dist/cli/commands/pi-acp.js +21 -0
- package/dist/cli/config.js +10 -1
- package/dist/cli/index.js +19 -8
- package/dist/cli/server-runtime.js +5 -0
- package/dist/server/adapters/agents/artifact-permission.js +88 -0
- package/dist/server/adapters/pi-acp/agent.js +98 -0
- package/dist/server/adapters/pi-acp/compatibility.js +57 -0
- package/dist/server/adapters/pi-acp/control.js +76 -0
- package/dist/server/adapters/pi-acp/errors.js +17 -0
- package/dist/server/adapters/pi-acp/extension.js +255 -0
- package/dist/server/adapters/pi-acp/launch.js +16 -0
- package/dist/server/adapters/pi-acp/mcp.js +153 -0
- package/dist/server/adapters/pi-acp/process.js +199 -0
- package/dist/server/adapters/pi-acp/session.js +409 -0
- package/dist/server/adapters/pi-acp/vendor/LICENSE +21 -0
- package/dist/server/adapters/pi-acp/vendor/README.md +29 -0
- package/dist/server/adapters/pi-acp/vendor/prompt.js +56 -0
- package/dist/server/app.js +95 -5
- package/dist/server/config/agents.js +4 -6
- package/dist/server/db/artifact-graph-migrations.js +56 -0
- package/dist/server/db/artifact-migrations.js +70 -0
- package/dist/server/db/artifact-review-migrations.js +24 -0
- package/dist/server/db/artifact-search-migrations.js +31 -0
- package/dist/server/db/artifact-validation-migrations.js +70 -0
- package/dist/server/db/index.js +3 -0
- package/dist/server/db/migrations.js +10 -0
- package/dist/server/db/sqlite-error.js +15 -0
- package/dist/server/db/transaction.js +40 -0
- package/dist/server/errors/artifacts.js +28 -0
- package/dist/server/errors/database.js +2 -0
- package/dist/server/hooks/access/local-request.js +5 -0
- package/dist/server/hooks/access/require-access.js +13 -2
- package/dist/server/repositories/artifact-catalog.repo.js +283 -0
- package/dist/server/repositories/artifact-files.repo.js +181 -0
- package/dist/server/repositories/artifact-graph.repo.js +50 -0
- package/dist/server/repositories/artifact-search.repo.js +192 -0
- package/dist/server/repositories/artifact-transition.repo.js +85 -0
- package/dist/server/repositories/artifact-validation.repo.js +157 -0
- package/dist/server/repositories/notes-catalog.repo.js +2 -10
- package/dist/server/repositories/task.repo.js +114 -0
- package/dist/server/routes/agent.js +8 -1
- package/dist/server/routes/artifact-actions.js +129 -0
- package/dist/server/routes/artifact-agent.js +199 -0
- package/dist/server/routes/artifact-definitions.js +163 -0
- package/dist/server/routes/artifact-transitions.js +80 -0
- package/dist/server/routes/artifacts.js +111 -0
- package/dist/server/routes/events.js +5 -1
- package/dist/server/services/agent/agent-session.js +180 -10
- package/dist/server/services/agent/context-builder.js +30 -2
- package/dist/server/services/agent/session-registry.js +136 -10
- package/dist/server/services/agent/turn-task-context.js +1 -0
- package/dist/server/services/artifact-authorization.service.js +199 -0
- package/dist/server/services/artifact-definition.service.js +96 -0
- package/dist/server/services/artifact-export.service.js +44 -0
- package/dist/server/services/artifact-graph-validation.js +541 -0
- package/dist/server/services/artifact-graph.service.js +81 -0
- package/dist/server/services/artifact-lifecycle.service.js +431 -0
- package/dist/server/services/artifact-maintenance.service.js +55 -0
- package/dist/server/services/artifact-search.service.js +331 -0
- package/dist/server/services/artifact-storage.service.js +646 -0
- package/dist/server/services/artifact-transition.service.js +608 -0
- package/dist/server/services/artifact-type.service.js +74 -0
- package/dist/server/services/artifact-validation-jobs.service.js +848 -0
- package/dist/server/services/device-connections.js +9 -1
- package/dist/server/services/review.service.js +6 -5
- package/dist/server/services/task.service.js +225 -0
- package/dist/server/utils/artifact-actor.js +13 -0
- package/dist/server/utils/artifact-page.js +42 -0
- package/dist/server/utils/take-within-bytes.js +16 -0
- package/dist/server/utils/text.js +7 -0
- package/dist/shared/agents/schemas.js +30 -0
- package/dist/shared/app/storage-constants.js +2 -0
- package/dist/shared/artifact-tools/descriptions.js +17 -0
- package/dist/shared/artifact-tools/instructions.js +14 -0
- package/dist/shared/artifact-tools/schemas.js +124 -0
- package/dist/shared/artifact-transitions/constants.js +21 -0
- package/dist/shared/artifact-transitions/schemas.js +111 -0
- package/dist/shared/artifact-transitions/transitions.js +61 -0
- package/dist/shared/artifact-transitions/types.js +1 -0
- package/dist/shared/artifacts/constants.js +34 -0
- package/dist/shared/artifacts/mcp-constants.js +24 -0
- package/dist/shared/artifacts/normalize.js +9 -0
- package/dist/shared/artifacts/schemas.js +874 -0
- package/dist/shared/artifacts/search.js +101 -0
- package/dist/shared/artifacts/types.js +1 -0
- package/dist/shared/events/schemas.js +1 -1
- package/dist/shared/events/types.js +1 -0
- package/dist/shared/tasks/schemas.js +261 -0
- package/dist/shared/tasks/types.js +1 -0
- package/dist/shared/utils/artifact-body.js +10 -0
- package/dist/shared/utils/canonical-json.js +22 -0
- package/dist/shared/utils/is-safe-prefixed-filename.js +10 -0
- package/dist/shared/utils/is-uuid.js +4 -2
- package/dist/shared/utils/is-valid-artifact-type-id.js +9 -0
- package/dist/shared/utils/is-valid-filename-prefix.js +13 -0
- package/dist/web/assets/AccessPage-D9xfFUBC.js +1 -0
- package/dist/web/assets/AddButton-DKNKmS1i.js +4 -0
- package/dist/web/assets/AddToAgentButton-wC1dzbDE.js +1 -0
- package/dist/web/assets/AppPage-Cozv2vqG.js +1 -0
- package/dist/web/assets/ArtifactsPage-IHUO7SbH.js +2 -0
- package/dist/web/assets/ArtifactsPage-nRD9XiRm.css +1 -0
- package/dist/web/assets/CancelButton-mkxRHwoZ.js +1 -0
- package/dist/web/assets/ClosePopup-Bd5a-Lu_.js +1 -0
- package/dist/web/assets/CreateButton-zCmb7snC.js +1 -0
- package/dist/web/assets/CreateReviewFabButton-D58IHr36.js +1 -0
- package/dist/web/assets/DialogHeader-BVrtb0Ri.js +1 -0
- package/dist/web/assets/DialogHeader-CPL9OtDV.css +1 -0
- package/dist/web/assets/{ErrorNotFound-DucDzOUJ.js → ErrorNotFound-fXS367lZ.js} +1 -1
- package/dist/web/assets/{IndexPage-D5PvyGrX.css → IndexPage-5V5GLtgi.css} +1 -1
- package/dist/web/assets/IndexPage-BJ1EQdlT.js +1 -0
- package/dist/web/assets/MainLayout-C3Ie5yOo.css +1 -0
- package/dist/web/assets/MainLayout-CeogGMHH.js +7 -0
- package/dist/web/assets/{NoteVisualEditor-CawpxEFB.css → NoteVisualEditor-DE4ACTRJ.css} +1 -1
- package/dist/web/assets/NoteVisualEditor-DqAZZig1.js +1054 -0
- package/dist/web/assets/NotesPage-C_eoCUl7.css +1 -0
- package/dist/web/assets/NotesPage-DXgI-kwN.js +4 -0
- package/dist/web/assets/{PdfPreview-rlkcqoMF.js → PdfPreview-ByeBjQMQ.js} +2 -2
- package/dist/web/assets/ProjectFilePage-DV1anYfN.js +1 -0
- package/dist/web/assets/QBtn-V3VXtJXi.js +1 -0
- package/dist/web/assets/QFab-DJhLqo9i.js +1 -0
- package/dist/web/assets/{QForm-Be8-ucuJ.js → QForm-ClpSneeD.js} +1 -1
- package/dist/web/assets/QInput-BnqLJGXl.js +1 -0
- package/dist/web/assets/QScrollArea-qf2G1s2r.js +1 -0
- package/dist/web/assets/QSeparator-B8uLaDiI.js +1 -0
- package/dist/web/assets/QSpace-CVp0CPR_.js +1 -0
- package/dist/web/assets/QSplitter-K2LjbupZ.js +1 -0
- package/dist/web/assets/QTabs-Bl_rIz4_.js +1 -0
- package/dist/web/assets/QVirtualScroll-BeEkuL6x.js +1 -0
- package/dist/web/assets/ReviewDetailPage-BgxcsTqY.css +1 -0
- package/dist/web/assets/ReviewDetailPage-CL4Dmz0L.js +1 -0
- package/dist/web/assets/ReviewsPage-BPJFTulG.js +1 -0
- package/dist/web/assets/SaveButton-D1q2suzR.js +3 -0
- package/dist/web/assets/SaveButton-Vtjvcbt0.css +1 -0
- package/dist/web/assets/SearchInput-DapVXrFj.js +1 -0
- package/dist/web/assets/StatusSwitcher-BtbSIr5q.js +1 -0
- package/dist/web/assets/{StatusSwitcher-D6i8_OfR.css → StatusSwitcher-DaE1ufAA.css} +1 -1
- package/dist/web/assets/TagFilterField-CPl-BxtL.js +1 -0
- package/dist/web/assets/TagFilterField-DjUH0m3_.css +1 -0
- package/dist/web/assets/{TerminalView-D4elkzN4.js → TerminalView-B56cEx8g.js} +12 -12
- package/dist/web/assets/{TerminalView-617DZuPt.css → TerminalView-BCeke4xd.css} +1 -1
- package/dist/web/assets/{abnfDiagram-O67JEVCF-Cugru96L.js → abnfDiagram-O67JEVCF-D_6l0gCA.js} +1 -1
- package/dist/web/assets/{access-store-Cdg8oRAM.js → access-store-CwkOl71l.js} +1 -1
- package/dist/web/assets/{agent-store-D_W7iD_B.js → agent-store-Cs-hu1v1.js} +5 -5
- package/dist/web/assets/architecture-7GRP2DOG-KT2-_RA5.js +1 -0
- package/dist/web/assets/{architectureDiagram-NJMV4G6O-7rMsE4Wt.js → architectureDiagram-NJMV4G6O-BFgjp9nL.js} +1 -1
- package/dist/web/assets/{blockDiagram-BEXU5L5S-BvSnwUrI.js → blockDiagram-BEXU5L5S-BWfbJk26.js} +1 -1
- package/dist/web/assets/{c4Diagram-YGBWAQC7-CgmQlCVx.js → c4Diagram-YGBWAQC7-oIqgOwQa.js} +1 -1
- package/dist/web/assets/channel-CAhty-fl.js +1 -0
- package/dist/web/assets/{chunk-3FUC2YCW-_i8udThz.js → chunk-3FUC2YCW-WI2pliXT.js} +1 -1
- package/dist/web/assets/{chunk-5DYCD2WN-Mhk2LlLk.js → chunk-5DYCD2WN-DYvaF8o2.js} +1 -1
- package/dist/web/assets/{chunk-742MDFTN-CDVcwgEp.js → chunk-742MDFTN-xd7B3x5h.js} +1 -1
- package/dist/web/assets/{chunk-7INBJB4K-C2c1fi9s.js → chunk-7INBJB4K-nsyx3RGB.js} +1 -1
- package/dist/web/assets/{chunk-7M6MHVWA-BeGkoIBL.js → chunk-7M6MHVWA-BxPQ9AEv.js} +1 -1
- package/dist/web/assets/{chunk-7PRAP22T-BVWTh9sT.js → chunk-7PRAP22T-CvHw2y-F.js} +1 -1
- package/dist/web/assets/{chunk-GTNCS2PH-gVhX7NZP.js → chunk-GTNCS2PH-DIfN1SOI.js} +1 -1
- package/dist/web/assets/{chunk-GWA4HPMP-BPdnIcQH.js → chunk-GWA4HPMP-2WZX1fG-.js} +1 -1
- package/dist/web/assets/{chunk-MBY4JIJT-B2VfO_06.js → chunk-MBY4JIJT-BL7akw7q.js} +1 -1
- package/dist/web/assets/{chunk-NETBCI7D-DZF_gITO.js → chunk-NETBCI7D-CQX1tY3W.js} +1 -1
- package/dist/web/assets/{chunk-O7XYJQB3-CDpBWiLq.js → chunk-O7XYJQB3-CtGXf4J6.js} +1 -1
- package/dist/web/assets/{chunk-UA2S7LBM-Iv7TSRE_.js → chunk-UA2S7LBM-C_3M_IIp.js} +1 -1
- package/dist/web/assets/{chunk-WEXAMYUT-Ce6goZ2Y.js → chunk-WEXAMYUT-6MO559WJ.js} +1 -1
- package/dist/web/assets/{chunk-Z7XXMR3K-CY6E6_Ux.js → chunk-Z7XXMR3K-CHJ55IlF.js} +1 -1
- package/dist/web/assets/{chunk-ZIGJFQKS-BLzsXZBc.js → chunk-ZIGJFQKS-533qcfPb.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-NBCMYWYE-Dz0kD9P6.js → classDiagram-v2-NBCMYWYE-CFySVswx.js} +1 -1
- package/dist/web/assets/copy-code-XoEu_Yh6.js +1 -0
- package/dist/web/assets/create-DedXY-KP.js +1 -0
- package/dist/web/assets/{cynefin-OW5HDTMX-DWIx3wRm.js → cynefin-OW5HDTMX-Dfg_2VTu.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-VND7K2PF-2D80uocv.js → cynefinDiagram-VND7K2PF-DaSXiPph.js} +1 -1
- package/dist/web/assets/{dagre-6A5THRUB-BLBhukn-.js → dagre-6A5THRUB-D7d1gbRO.js} +1 -1
- package/dist/web/assets/date-snFAXn1W.js +1 -0
- package/dist/web/assets/{devices-store-BfZKPOhg.js → devices-store-DB_tWC1Q.js} +1 -1
- package/dist/web/assets/{diagram-22UHCM2B-DY8dMLZ3.js → diagram-22UHCM2B-CNuTss_x.js} +1 -1
- package/dist/web/assets/{diagram-3UASUU5V-Bf6Od1NH.js → diagram-3UASUU5V--Rt3-ARV.js} +1 -1
- package/dist/web/assets/{diagram-ATOU4E4O-CjLGcYD5.js → diagram-ATOU4E4O-BP79L-gP.js} +1 -1
- package/dist/web/assets/{diagram-CDSNMT55-gIvaVNvs.js → diagram-CDSNMT55-CRO5cocs.js} +1 -1
- package/dist/web/assets/{diagram-MLGK6HIB-VR5kiCi5.js → diagram-MLGK6HIB-Difu0Zmh.js} +1 -1
- package/dist/web/assets/{diagram-MPIPVDR6-CdAdj25I.js → diagram-MPIPVDR6-grQ3ie17.js} +1 -1
- package/dist/web/assets/diff-store-D4XiTkfi.js +93 -0
- package/dist/web/assets/{dist-CBGyhCYv.js → dist-75uxNoTf.js} +1 -1
- package/dist/web/assets/{dist-CIMEaJAX.js → dist-9rzCziV2.js} +1 -1
- package/dist/web/assets/{dist-CEl-Ko94.js → dist-B9i6cUYu.js} +1 -1
- package/dist/web/assets/{dist-yzAhvE-V.js → dist-BU-fZfEv.js} +1 -1
- package/dist/web/assets/{dist-CTd7Kuqx.js → dist-BeUB43Ur.js} +1 -1
- package/dist/web/assets/{dist-C85t5q3z.js → dist-BxIdk5Al.js} +1 -1
- package/dist/web/assets/{dist-joQDFmfy.js → dist-By534Syk.js} +1 -1
- package/dist/web/assets/{dist-C54FrSb8.js → dist-DFjLCq-0.js} +1 -1
- package/dist/web/assets/{dist-lgw4kcVA.js → dist-DNrP7O-J.js} +1 -1
- package/dist/web/assets/{dist-BU8erXQF.js → dist-Du5VPTAq.js} +1 -1
- package/dist/web/assets/{dist-DLuI1PxH.js → dist-DyBqP777.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-ZINNZB2B-irTAlMFO.js → ebnfDiagram-ZINNZB2B-DX2rcvMK.js} +1 -1
- package/dist/web/assets/{elk-276RUBZZ-Dj5ligvC.js → elk-276RUBZZ-DSHIl9hv.js} +1 -1
- package/dist/web/assets/{erDiagram-OPXOYQCR-Bvn6rbL1.js → erDiagram-OPXOYQCR-BIZVJO8N.js} +1 -1
- package/dist/web/assets/eventmodeling-NTZA5JFV-Bh_xDKx6.js +1 -0
- package/dist/web/assets/flowDiagram-KWPJA3E3-DXkIxaXL.js +1 -0
- package/dist/web/assets/{ganttDiagram-FUAMR5RP-BNGAUF5H.js → ganttDiagram-FUAMR5RP-D4kPfh4X.js} +1 -1
- package/dist/web/assets/{gitGraph-4MIJSDKK-DYSHOl72.js → gitGraph-4MIJSDKK-B41R-oAb.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-X574FWY7-BGwRHrPq.js → gitGraphDiagram-X574FWY7-xXrZiSJI.js} +1 -1
- package/dist/web/assets/i18n-Cfw_OfRR.js +1 -0
- package/dist/web/assets/icons-BIOTvmdT.js +1 -0
- package/dist/web/assets/index-B1Bugudn.js +2 -0
- package/dist/web/assets/index-BQU3KK1E.css +1 -0
- package/dist/web/assets/{info-A6RAGUB7-DNWR20pW.js → info-A6RAGUB7-CgSmK-La.js} +1 -1
- package/dist/web/assets/{infoDiagram-VRGFBTTK-BhNwJLY5.js → infoDiagram-VRGFBTTK-CDNEJ_R-.js} +1 -1
- package/dist/web/assets/{init-app-cg-B_TFN.js → init-app-C3tD3faT.js} +1 -1
- package/dist/web/assets/{is-D0waCELe.js → is-B1kBQ5Va.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-CSkDpn64.js → ishikawaDiagram-OU5B5YK6-ZcU1IxFn.js} +1 -1
- package/dist/web/assets/{journeyDiagram-ZHPQQLJL-D2CEecC3.js → journeyDiagram-ZHPQQLJL-g-8ZRhJj.js} +1 -1
- package/dist/web/assets/{kanban-definition-PNTS6WVX-CQHlo4Hh.js → kanban-definition-PNTS6WVX-nfsfxVOE.js} +1 -1
- package/dist/web/assets/{line-C-izH1ks.js → line-BpuX_ban.js} +1 -1
- package/dist/web/assets/markdown-ogvtoQzt.js +16 -0
- package/dist/web/assets/mdi-Du7sIqtH.js +1 -0
- package/dist/web/assets/{mermaid-parser.core-CAGwq6D-.js → mermaid-parser.core-BBj_ep7Z.js} +3 -3
- package/dist/web/assets/{mermaid.core--xlI_0tK.js → mermaid.core-DP4USVSM.js} +4 -4
- package/dist/web/assets/{mindmap-definition-NLK3R4M7-BuCxhlwy.js → mindmap-definition-NLK3R4M7-C5GhUvi3.js} +1 -1
- package/dist/web/assets/{packet-AYTQ26CC-Bi7x5lJK.js → packet-AYTQ26CC-BIdb-vfg.js} +1 -1
- package/dist/web/assets/{pegDiagram-GJSIUBJH-qWzBPkCQ.js → pegDiagram-GJSIUBJH-DH-SdKj6.js} +1 -1
- package/dist/web/assets/{pie-WAS4IAKB-Di0wC4XB.js → pie-WAS4IAKB-Du3-jRjK.js} +1 -1
- package/dist/web/assets/{pieDiagram-5QR66LMP-BCDVY9q2.js → pieDiagram-5QR66LMP-CJh2ngqY.js} +1 -1
- package/dist/web/assets/pinia-BfqEuvsi.js +1 -0
- package/dist/web/assets/pinia-mdReENsc.js +1 -0
- package/dist/web/assets/preview-store-DOnSmm_C.js +2 -0
- package/dist/web/assets/{project-files-store-byqyG2ts.js → project-files-store-CHP6RYFI.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-O4NWA36T-CpFObUjT.js → quadrantDiagram-O4NWA36T-DYsSScxc.js} +1 -1
- package/dist/web/assets/{radar-RG4KPBEZ-Br8yH8rq.js → radar-RG4KPBEZ-BBjvaVVB.js} +1 -1
- package/dist/web/assets/{railroad-74A4TZTK-CACSqhA-.js → railroad-74A4TZTK-B-CRncBU.js} +1 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-D37zpoYN.js +1 -0
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-ZnMxH6Ym.js +1 -0
- package/dist/web/assets/railroad-peg-WCYAUIDC-Dg3g-VsM.js +1 -0
- package/dist/web/assets/{railroadDiagram-XR7U4H2S-sYXRKGK1.js → railroadDiagram-XR7U4H2S-hqp-2UHb.js} +1 -1
- package/dist/web/assets/{render-C7fu7uYY.js → render-Brao9Nj2.js} +1 -1
- package/dist/web/assets/repository-store-DZgQ5H7J.js +1 -0
- package/dist/web/assets/{requirementDiagram-PLB6GJNP-C9I1JbQc.js → requirementDiagram-PLB6GJNP-Dhuw5jcQ.js} +1 -1
- package/dist/web/assets/runtime-core.esm-bundler-DDnHUoIy.js +1 -0
- package/dist/web/assets/{safe-storage-C76bPypO.js → safe-storage-BchoYSbq.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-IPEJSGJF-CuvFQhPh.js → sankeyDiagram-IPEJSGJF-D5rCIxGR.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-PO4LG4MO-CaVb9Y6e.js → sequenceDiagram-PO4LG4MO-YEHR4Mp-.js} +1 -1
- package/dist/web/assets/single-flight-CyDZB3rb.js +1 -0
- package/dist/web/assets/{stateDiagram-v2-GCMORJYK-Dp_APryr.js → stateDiagram-v2-GCMORJYK-9iWmz6Xf.js} +1 -1
- package/dist/web/assets/{swimlanes-2SLR337P-FclUI-k0.js → swimlanes-2SLR337P-Cjwvgt_n.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-gJwxhWoO.js +8 -0
- package/dist/web/assets/{terminal-store-BnEkXuBj.js → terminal-store-i7HHlWzR.js} +1 -1
- package/dist/web/assets/theme-CQ9InaWa.js +1 -0
- package/dist/web/assets/{timeline-definition-EJHVYXUP-BAqwqj3c.js → timeline-definition-EJHVYXUP-Cd5n2-Py.js} +1 -1
- package/dist/web/assets/{treeView-Q6P3EWNA-D87jJbUQ.js → treeView-Q6P3EWNA-C_QH9vtR.js} +1 -1
- package/dist/web/assets/{treemap-WGGIJYW6-B6nhGhRc.js → treemap-WGGIJYW6-CVnU7TVz.js} +1 -1
- package/dist/web/assets/use-add-agent-context-D5VqMr0p.js +1 -0
- package/dist/web/assets/use-app-theme-DgC4ivPF.js +1 -0
- package/dist/web/assets/use-countdown-D6_qSOZJ.js +1 -0
- package/dist/web/assets/use-notify-error-Dx2D9IEP.js +1 -0
- package/dist/web/assets/use-router-link-D7geCGQI.js +1 -0
- package/dist/web/assets/use-row-height-BgHg4-J-.js +1 -0
- package/dist/web/assets/use-server-events-CvcbsbIf.js +1 -0
- package/dist/web/assets/use-virtual-scroll-DixIsJk4.js +1 -0
- package/dist/web/assets/{use-workspace-navigation-CnebLvBV.js → use-workspace-navigation-Dq-Aw8Xq.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-POWQR4AR-7YcIKxAb.js → usecaseDiagram-POWQR4AR-Cbj2Pvab.js} +1 -1
- package/dist/web/assets/{vennDiagram-UO4OBE2U-BZq5cFC4.js → vennDiagram-UO4OBE2U-2j79YqCN.js} +1 -1
- package/dist/web/assets/viewport-store-NqQS7itT.js +1 -0
- package/dist/web/assets/{vue-i18n.runtime-CEtihHHL.js → vue-i18n.runtime-JOo8b7-t.js} +2 -2
- package/dist/web/assets/{wardley-WFR3VGLG-BT8YO9H4.js → wardley-WFR3VGLG-wsMK7zm3.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-VNRHLVJA-rDpXFf6D.js → wardleyDiagram-VNRHLVJA-D6PKTQIJ.js} +1 -1
- package/dist/web/assets/weighted-lru-BFtZKA_y.js +1 -0
- package/dist/web/assets/workspace-navigation-CoXKJJpP.js +1 -0
- package/dist/web/assets/{xychartDiagram-PMCCYNJV-ClniUuZc.js → xychartDiagram-PMCCYNJV-D1fQN7KG.js} +1 -1
- package/dist/web/index.html +10 -9
- package/package.json +5 -3
- package/dist/web/assets/AccessPage-CX3w30zw.js +0 -1
- package/dist/web/assets/AppPage-PFJG281y.js +0 -1
- package/dist/web/assets/CreateButton-Ch0b7juj.js +0 -1
- package/dist/web/assets/CreateReviewFabButton-DTuJzw3q.js +0 -1
- package/dist/web/assets/IndexPage-tgW07Qvs.js +0 -1
- package/dist/web/assets/MainLayout-C6yBhQnf.css +0 -1
- package/dist/web/assets/MainLayout-Cw4jpB1x.js +0 -8
- package/dist/web/assets/NoteVisualEditor-DiGhLhQg.js +0 -1054
- package/dist/web/assets/NotesPage-CVyVr9tl.js +0 -4
- package/dist/web/assets/NotesPage-CxGnZuVQ.css +0 -1
- package/dist/web/assets/PanelResize-B6FP9ZVB.js +0 -1
- package/dist/web/assets/ProjectFilePage-CkxfX9b1.js +0 -1
- package/dist/web/assets/QBtn-CyyV1Bx_.js +0 -1
- package/dist/web/assets/QExpansionItem-Dp9lbdVb.js +0 -4
- package/dist/web/assets/QFab-LOmZ9rev.js +0 -1
- package/dist/web/assets/QInput-Dq6131uz.js +0 -1
- package/dist/web/assets/QSelect-B34OqtIH.js +0 -1
- package/dist/web/assets/QSpace-BhOVGpQh.js +0 -1
- package/dist/web/assets/QVirtualScroll-BYgJ1Kh2.js +0 -1
- package/dist/web/assets/ReviewDetailPage-CkCilMNW.css +0 -1
- package/dist/web/assets/ReviewDetailPage-GNjBa4X0.js +0 -1
- package/dist/web/assets/ReviewsPage-An5fRS92.js +0 -1
- package/dist/web/assets/StatusSwitcher-DrFHHwGm.js +0 -1
- package/dist/web/assets/architecture-7GRP2DOG-BPCNj4lR.js +0 -1
- package/dist/web/assets/channel-CzRYxuLe.js +0 -1
- package/dist/web/assets/create-B9Tn5Xvi.js +0 -1
- package/dist/web/assets/diff-store-B4adGxC2.js +0 -93
- package/dist/web/assets/eventmodeling-NTZA5JFV-BJsTZ_nG.js +0 -1
- package/dist/web/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-Dr0goTwe.woff +0 -0
- package/dist/web/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ-D-x-0Q06.woff2 +0 -0
- package/dist/web/assets/flowDiagram-KWPJA3E3-CvXh1Df7.js +0 -1
- package/dist/web/assets/i18n-DnlAcIbT.js +0 -1
- package/dist/web/assets/index-Cw7GJi3K.js +0 -2
- package/dist/web/assets/index-wsOPzloa.css +0 -1
- package/dist/web/assets/markdown-CvtLTiBZ.js +0 -16
- package/dist/web/assets/pinia-DO0AdKGg.js +0 -1
- package/dist/web/assets/pinia-uOZCmBi-.js +0 -1
- package/dist/web/assets/preview-store-DyO8G-ox.js +0 -1
- package/dist/web/assets/railroad-abnf-HS5TGJTU-DTBsRB1c.js +0 -1
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-D3mrY4ar.js +0 -1
- package/dist/web/assets/railroad-peg-WCYAUIDC-33ZjWX0u.js +0 -1
- package/dist/web/assets/repository-store-DtRDth1L.js +0 -1
- package/dist/web/assets/runtime-core.esm-bundler-CAvPiMpd.js +0 -1
- package/dist/web/assets/single-flight-fPyIy7h5.js +0 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-CuUvsn0e.js +0 -8
- package/dist/web/assets/theme-CnbaLamF.js +0 -1
- package/dist/web/assets/use-add-agent-context-xHAjjOf1.js +0 -1
- package/dist/web/assets/use-app-theme-DEowpWRR.js +0 -1
- package/dist/web/assets/use-countdown-DlcwwJrs.js +0 -1
- package/dist/web/assets/use-panel-width-CjSWCFr4.js +0 -1
- package/dist/web/assets/use-router-link-CUoYaYUw.js +0 -1
- package/dist/web/assets/use-row-height-BsE9-rO2.js +0 -1
- package/dist/web/assets/use-server-events-C2X4Xz00.js +0 -1
- package/dist/web/assets/use-virtual-scroll-BAZGswHv.js +0 -1
- package/dist/web/assets/viewport-store-CCHiY2QG.js +0 -1
- package/dist/web/assets/weighted-lru-BGovtJ2a.js +0 -1
- package/dist/web/assets/workspace-navigation-DdW0rSGz.js +0 -1
- /package/dist/web/assets/{PanelResize-XjrbOj2S.css → AddToAgentButton-XjrbOj2S.css} +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { ArtifactExportService } from "../services/artifact-export.service.js";
|
|
2
|
+
import { ArtifactExportQuery, ArtifactOriginalExportSchema, ArtifactMetadataExportSchema, ArtifactSearchBody, ArtifactSearchQuery, ArtifactSearchSchema, ArtifactSearchDiagnosticsSchema, ArtifactContentQuery, ArtifactContentSchema, ArtifactHistoryQuery, ArtifactHistorySchema, ArtifactListQuery, ArtifactListSchema, ArtifactParams, ArtifactSchema } from "../../shared/artifacts/schemas.js";
|
|
3
|
+
import { ERROR_RESPONSES } from "../../shared/http/schemas.js";
|
|
4
|
+
export async function artifactRoutes(app, { service }) {
|
|
5
|
+
const typed = app.withTypeProvider();
|
|
6
|
+
const exports = new ArtifactExportService(service);
|
|
7
|
+
// The schema describes the downloaded file; Fastify sends exact buffers or pre-serialized JSON streams.
|
|
8
|
+
typed.get('/api/artifacts/:id/export', {
|
|
9
|
+
schema: {
|
|
10
|
+
tags: ['artifacts'],
|
|
11
|
+
summary: 'Download the original bytes or consistent metadata history',
|
|
12
|
+
params: ArtifactParams,
|
|
13
|
+
querystring: ArtifactExportQuery,
|
|
14
|
+
response: {
|
|
15
|
+
200: {
|
|
16
|
+
description: 'Exact original Markdown file or streamed metadata history snapshot.',
|
|
17
|
+
content: {
|
|
18
|
+
'text/markdown': { schema: ArtifactOriginalExportSchema },
|
|
19
|
+
'application/json': { schema: ArtifactMetadataExportSchema }
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
...ERROR_RESPONSES
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}, (request, reply) => {
|
|
26
|
+
const id = request.params.id;
|
|
27
|
+
if (request.query.format === 'original') {
|
|
28
|
+
const { artifact, content } = exports.original(id);
|
|
29
|
+
reply.header('Content-Disposition', `attachment; filename="artifact-${id}.md"`);
|
|
30
|
+
reply.header('X-Artifact-SHA256', artifact.sha256);
|
|
31
|
+
reply.type('text/markdown; charset=utf-8');
|
|
32
|
+
reply.send(content);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const stream = exports.metadataHistory(id);
|
|
36
|
+
reply.header('Content-Disposition', `attachment; filename="artifact-${id}.metadata-history.json"`);
|
|
37
|
+
reply.type('application/json; charset=utf-8');
|
|
38
|
+
const close = () => stream.destroy();
|
|
39
|
+
reply.raw.once('close', close);
|
|
40
|
+
stream.once('close', () => reply.raw.removeListener('close', close));
|
|
41
|
+
reply.send(stream);
|
|
42
|
+
});
|
|
43
|
+
typed.get('/api/artifacts/search', {
|
|
44
|
+
schema: {
|
|
45
|
+
tags: ['artifacts'],
|
|
46
|
+
summary: 'Search verified artifact titles and body text',
|
|
47
|
+
querystring: ArtifactSearchQuery,
|
|
48
|
+
response: { 200: ArtifactSearchSchema, ...ERROR_RESPONSES }
|
|
49
|
+
}
|
|
50
|
+
}, request => {
|
|
51
|
+
const { status, typeId, taskId, tag, ...query } = request.query;
|
|
52
|
+
return service.search.search({
|
|
53
|
+
...query,
|
|
54
|
+
filters: {
|
|
55
|
+
...(status ? { statuses: [status] } : {}),
|
|
56
|
+
...(typeId ? { typeIds: [typeId] } : {}),
|
|
57
|
+
...(taskId ? { taskIds: [taskId] } : {}),
|
|
58
|
+
...(tag ? { tags: [tag] } : {})
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
typed.post('/api/artifacts/search', {
|
|
63
|
+
schema: {
|
|
64
|
+
tags: ['artifacts'],
|
|
65
|
+
summary: 'Search with multiple metadata filters',
|
|
66
|
+
body: ArtifactSearchBody,
|
|
67
|
+
response: { 200: ArtifactSearchSchema, ...ERROR_RESPONSES }
|
|
68
|
+
}
|
|
69
|
+
}, request => service.search.search(request.body));
|
|
70
|
+
typed.get('/api/artifacts/search/diagnostics', {
|
|
71
|
+
schema: {
|
|
72
|
+
tags: ['artifacts'],
|
|
73
|
+
summary: 'Read derived search index diagnostics',
|
|
74
|
+
response: { 200: ArtifactSearchDiagnosticsSchema, ...ERROR_RESPONSES }
|
|
75
|
+
}
|
|
76
|
+
}, () => service.search.diagnostics());
|
|
77
|
+
typed.get('/api/artifacts', {
|
|
78
|
+
schema: {
|
|
79
|
+
tags: ['artifacts'],
|
|
80
|
+
summary: 'List committed artifacts',
|
|
81
|
+
querystring: ArtifactListQuery,
|
|
82
|
+
response: { 200: ArtifactListSchema, ...ERROR_RESPONSES }
|
|
83
|
+
}
|
|
84
|
+
}, request => service.list(request.query.limit, request.query.cursor));
|
|
85
|
+
typed.get('/api/artifacts/:id', {
|
|
86
|
+
schema: {
|
|
87
|
+
tags: ['artifacts'],
|
|
88
|
+
summary: 'Read current artifact metadata',
|
|
89
|
+
params: ArtifactParams,
|
|
90
|
+
response: { 200: ArtifactSchema, ...ERROR_RESPONSES }
|
|
91
|
+
}
|
|
92
|
+
}, request => service.get(request.params.id));
|
|
93
|
+
typed.get('/api/artifacts/:id/content', {
|
|
94
|
+
schema: {
|
|
95
|
+
tags: ['artifacts'],
|
|
96
|
+
summary: 'Read verified immutable artifact content',
|
|
97
|
+
params: ArtifactParams,
|
|
98
|
+
querystring: ArtifactContentQuery,
|
|
99
|
+
response: { 200: ArtifactContentSchema, ...ERROR_RESPONSES }
|
|
100
|
+
}
|
|
101
|
+
}, request => service.readContent(request.params.id, request.query.offset, request.query.limit));
|
|
102
|
+
typed.get('/api/artifacts/:id/history', {
|
|
103
|
+
schema: {
|
|
104
|
+
tags: ['artifacts'],
|
|
105
|
+
summary: 'Read immutable artifact history',
|
|
106
|
+
params: ArtifactParams,
|
|
107
|
+
querystring: ArtifactHistoryQuery,
|
|
108
|
+
response: { 200: ArtifactHistorySchema, ...ERROR_RESPONSES }
|
|
109
|
+
}
|
|
110
|
+
}, request => service.history(request.params.id, request.query.afterSeq, request.query.limit));
|
|
111
|
+
}
|
|
@@ -30,7 +30,11 @@ export async function eventRoutes(app, opts) {
|
|
|
30
30
|
const unsubscribe = eventBus.subscribe(event => {
|
|
31
31
|
safeSend(reply.sse, {
|
|
32
32
|
event: event.type,
|
|
33
|
-
data: {
|
|
33
|
+
data: {
|
|
34
|
+
reviewId: event.reviewId,
|
|
35
|
+
storeId: event.storeId,
|
|
36
|
+
storeEpoch: event.storeEpoch
|
|
37
|
+
}
|
|
34
38
|
});
|
|
35
39
|
});
|
|
36
40
|
reply.sse.onClose(() => {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { isLocalPiLaunch } from "../../adapters/pi-acp/launch.js";
|
|
2
|
+
import { isRecord } from "../../../shared/utils/guards.js";
|
|
1
3
|
import { AgentSessionError, AgentSessionStateError, AgentConfigError } from "../../errors/agents.js";
|
|
4
|
+
import { ARTIFACT_TASK_PROMPT_HINT } from "../../../shared/artifact-tools/instructions.js";
|
|
5
|
+
import { ARTIFACT_AGENT_KEY_ENV, ARTIFACT_MCP_SERVER_NAME } from "../../../shared/artifacts/mcp-constants.js";
|
|
2
6
|
import { spawn } from 'node:child_process';
|
|
3
7
|
import { randomUUID } from 'node:crypto';
|
|
4
8
|
import { rm } from 'node:fs/promises';
|
|
@@ -16,6 +20,8 @@ export const MAX_BUFFERED_EVENTS = 5_000;
|
|
|
16
20
|
const STDERR_TAIL_CHARS = 2_000;
|
|
17
21
|
/** How long a closed connection waits for the `exit` event that carries the reason. */
|
|
18
22
|
const EXIT_GRACE_MS = 500;
|
|
23
|
+
// Bound pending tool context retained only for server permission policies.
|
|
24
|
+
const MAX_PERMISSION_TOOL_CALLS = 64;
|
|
19
25
|
/** The option the server picks for an auto-approved request; never a rejection. */
|
|
20
26
|
function autoApproveChoice(options) {
|
|
21
27
|
return (options.find(o => o.kind === 'allow_once') ??
|
|
@@ -35,11 +41,14 @@ export class AgentSession {
|
|
|
35
41
|
presetId;
|
|
36
42
|
name;
|
|
37
43
|
reviewId;
|
|
44
|
+
kind;
|
|
45
|
+
#turnTaskContext;
|
|
38
46
|
#status = 'starting';
|
|
39
47
|
/** Set when the user (or the server) ends the session: its exit is no failure. */
|
|
40
48
|
#closing = false;
|
|
41
49
|
#error = null;
|
|
42
50
|
#autoApprove = false;
|
|
51
|
+
#permissionToolCalls = new Map();
|
|
43
52
|
#child;
|
|
44
53
|
#connection;
|
|
45
54
|
#acpSessionId;
|
|
@@ -47,6 +56,8 @@ export class AgentSession {
|
|
|
47
56
|
#image = false;
|
|
48
57
|
#config = [];
|
|
49
58
|
#stderrTail = '';
|
|
59
|
+
#mcpSecrets = [];
|
|
60
|
+
#hasArtifactMcp = false;
|
|
50
61
|
/** Settles when the agent process has exited. */
|
|
51
62
|
#exited = Promise.resolve();
|
|
52
63
|
#ownEventId = 0;
|
|
@@ -61,10 +72,35 @@ export class AgentSession {
|
|
|
61
72
|
this.presetId = options.preset.id;
|
|
62
73
|
this.name = options.name;
|
|
63
74
|
this.reviewId = options.reviewId ?? null;
|
|
75
|
+
this.kind = options.kind;
|
|
64
76
|
}
|
|
65
77
|
get status() {
|
|
66
78
|
return this.#status;
|
|
67
79
|
}
|
|
80
|
+
get turnTaskContext() {
|
|
81
|
+
return this.#turnTaskContext;
|
|
82
|
+
}
|
|
83
|
+
prepareTaskActivation(turnId, assignmentVersion, taskId, requestId) {
|
|
84
|
+
// Cancellation clears the context before the agent stops reporting busy.
|
|
85
|
+
if (!this.#turnTaskContext || this.#turnTaskContext.turnId !== turnId) {
|
|
86
|
+
throw new AgentSessionStateError('The response ended or its task context changed.');
|
|
87
|
+
}
|
|
88
|
+
const context = Object.freeze({
|
|
89
|
+
sessionId: this.id,
|
|
90
|
+
turnId,
|
|
91
|
+
assignmentVersion,
|
|
92
|
+
taskIds: Object.freeze([taskId]),
|
|
93
|
+
source: 'turn_activation',
|
|
94
|
+
activationRequestId: requestId
|
|
95
|
+
});
|
|
96
|
+
// The caller commits and applies synchronously, without yielding to cancellation or another prompt.
|
|
97
|
+
return {
|
|
98
|
+
context,
|
|
99
|
+
apply: () => {
|
|
100
|
+
this.#turnTaskContext = context;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
68
104
|
/** Whether the agent advertised `promptCapabilities.embeddedContext`. */
|
|
69
105
|
get supportsEmbeddedContext() {
|
|
70
106
|
return this.#embeddedContext;
|
|
@@ -76,8 +112,12 @@ export class AgentSession {
|
|
|
76
112
|
info() {
|
|
77
113
|
return {
|
|
78
114
|
id: this.id,
|
|
115
|
+
...(this.#options.taskIds
|
|
116
|
+
? { taskIds: this.#options.taskIds(this.id) }
|
|
117
|
+
: {}),
|
|
79
118
|
presetId: this.presetId,
|
|
80
119
|
name: this.name,
|
|
120
|
+
...(this.kind === undefined ? {} : { kind: this.kind }),
|
|
81
121
|
status: this.#status,
|
|
82
122
|
reviewId: this.reviewId,
|
|
83
123
|
autoApprove: this.#autoApprove,
|
|
@@ -106,7 +146,7 @@ export class AgentSession {
|
|
|
106
146
|
catch (error) {
|
|
107
147
|
// An exit during the start already reported itself (`#onExit`).
|
|
108
148
|
if (this.#error === null && !this.#closing) {
|
|
109
|
-
const message = errorMessage(error);
|
|
149
|
+
const message = this.#redact(errorMessage(error));
|
|
110
150
|
this.#error = message;
|
|
111
151
|
this.#emit({ type: 'error', message });
|
|
112
152
|
}
|
|
@@ -115,16 +155,28 @@ export class AgentSession {
|
|
|
115
155
|
}
|
|
116
156
|
async #start() {
|
|
117
157
|
const { preset, cwd } = this.#options;
|
|
158
|
+
const localPi = isLocalPiLaunch(preset);
|
|
159
|
+
if (preset.id === 'pi' && this.kind === 'validation' && !localPi) {
|
|
160
|
+
throw new AgentSessionError('Pi validation requires the trusted local GitHuman pi launcher. The configured command is available for chat only.');
|
|
161
|
+
}
|
|
118
162
|
const child = spawn(preset.command, preset.args, {
|
|
119
163
|
cwd,
|
|
120
164
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
121
|
-
env: {
|
|
165
|
+
env: {
|
|
166
|
+
...process.env,
|
|
167
|
+
...preset.env,
|
|
168
|
+
...(localPi
|
|
169
|
+
? {
|
|
170
|
+
GITHUMAN_PI_PROFILE: this.kind === 'validation' ? 'validator' : 'chat'
|
|
171
|
+
}
|
|
172
|
+
: {})
|
|
173
|
+
}
|
|
122
174
|
});
|
|
123
175
|
this.#child = child;
|
|
124
176
|
this.#exited = new Promise(resolve => child.once('exit', resolve));
|
|
125
177
|
child.stderr.setEncoding('utf-8');
|
|
126
178
|
child.stderr.on('data', (chunk) => {
|
|
127
|
-
this.#stderrTail = (this.#stderrTail + chunk).slice(-STDERR_TAIL_CHARS);
|
|
179
|
+
this.#stderrTail = this.#redact(this.#stderrTail + chunk).slice(-STDERR_TAIL_CHARS);
|
|
128
180
|
});
|
|
129
181
|
// Swallow stdin EPIPE after the agent died; the closed connection reports it.
|
|
130
182
|
child.stdin.on('error', () => { });
|
|
@@ -181,10 +233,28 @@ export class AgentSession {
|
|
|
181
233
|
const prompt = init.agentCapabilities?.promptCapabilities;
|
|
182
234
|
this.#embeddedContext = prompt?.embeddedContext === true;
|
|
183
235
|
this.#image = prompt?.image === true;
|
|
236
|
+
const mcpServers = typeof this.#options.mcpServers === 'function'
|
|
237
|
+
? this.#options.mcpServers(this.id)
|
|
238
|
+
: (this.#options.mcpServers ?? []);
|
|
239
|
+
this.#hasArtifactMcp = mcpServers.some(server => server.name === ARTIFACT_MCP_SERVER_NAME);
|
|
240
|
+
this.#mcpSecrets = mcpServers.flatMap(server => 'env' in server
|
|
241
|
+
? server.env
|
|
242
|
+
.filter(entry => entry.name === ARTIFACT_AGENT_KEY_ENV)
|
|
243
|
+
.map(entry => entry.value)
|
|
244
|
+
: []);
|
|
184
245
|
const created = await connection.agent.request(acp.methods.agent.session.new, {
|
|
185
246
|
cwd: this.#options.cwd,
|
|
186
|
-
mcpServers
|
|
247
|
+
mcpServers
|
|
187
248
|
});
|
|
249
|
+
if (isLocalPiLaunch(this.#options.preset)) {
|
|
250
|
+
const ack = created['_meta']?.githumanBridge;
|
|
251
|
+
if (!isRecord(ack) ||
|
|
252
|
+
ack.version !== 1 ||
|
|
253
|
+
ack.profile !== (this.kind === 'validation' ? 'validator' : 'chat') ||
|
|
254
|
+
ack.registryGeneration !== 1) {
|
|
255
|
+
throw new AgentSessionError('Pi bridge did not confirm its launch profile and MCP registry.');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
188
258
|
this.#acpSessionId = created.sessionId;
|
|
189
259
|
this.#setConfig(mapConfigOptions(created.configOptions));
|
|
190
260
|
}
|
|
@@ -223,7 +293,9 @@ export class AgentSession {
|
|
|
223
293
|
this.#setConfig(mapConfigOptions(response.configOptions));
|
|
224
294
|
}
|
|
225
295
|
catch (error) {
|
|
226
|
-
throw new AgentSessionError(errorMessage(error), {
|
|
296
|
+
throw new AgentSessionError(this.#redact(errorMessage(error)), {
|
|
297
|
+
cause: error
|
|
298
|
+
});
|
|
227
299
|
}
|
|
228
300
|
}
|
|
229
301
|
/** The agent process ended: report why, unless the session itself ended it. */
|
|
@@ -257,8 +329,15 @@ export class AgentSession {
|
|
|
257
329
|
}
|
|
258
330
|
this.#markClosed();
|
|
259
331
|
}
|
|
332
|
+
// Hides the session key in errors and stderr. Messages that the agent itself writes stay as they are.
|
|
333
|
+
#redact(text) {
|
|
334
|
+
for (const secret of this.#mcpSecrets) {
|
|
335
|
+
text = text.replaceAll(secret, '[redacted]');
|
|
336
|
+
}
|
|
337
|
+
return text;
|
|
338
|
+
}
|
|
260
339
|
#exitMessage(code, signal) {
|
|
261
|
-
const tail = this.#stderrTail.trim();
|
|
340
|
+
const tail = this.#redact(this.#stderrTail.trim());
|
|
262
341
|
return (`Agent exited (${signal ?? `code ${code}`})` +
|
|
263
342
|
(tail === '' ? '' : `: ${tail.slice(-400)}`));
|
|
264
343
|
}
|
|
@@ -268,13 +347,29 @@ export class AgentSession {
|
|
|
268
347
|
*/
|
|
269
348
|
prompt(blocks, display) {
|
|
270
349
|
const { connection, sessionId } = this.#readyChannel();
|
|
350
|
+
const assignment = this.#options.taskAssignment?.(this.id);
|
|
351
|
+
const turn = Object.freeze({
|
|
352
|
+
turnId: randomUUID(),
|
|
353
|
+
sessionId: this.id,
|
|
354
|
+
assignmentVersion: assignment?.version ?? 0,
|
|
355
|
+
source: 'turn_assignment',
|
|
356
|
+
taskIds: Object.freeze([...(assignment?.taskIds ?? [])])
|
|
357
|
+
});
|
|
358
|
+
this.#turnTaskContext = turn;
|
|
271
359
|
this.#setStatus('busy');
|
|
272
360
|
this.#emit({
|
|
273
361
|
type: 'user',
|
|
274
362
|
text: display.text,
|
|
275
363
|
context: display.context ?? []
|
|
276
364
|
});
|
|
277
|
-
|
|
365
|
+
// Append the reminder without changing the user transcript or validator assignments.
|
|
366
|
+
const prompt = this.#hasArtifactMcp && !this.#options.permissionPolicy
|
|
367
|
+
? [
|
|
368
|
+
...blocks,
|
|
369
|
+
{ type: 'text', text: ARTIFACT_TASK_PROMPT_HINT }
|
|
370
|
+
]
|
|
371
|
+
: blocks;
|
|
372
|
+
void this.#runPrompt(connection, sessionId, prompt, turn.turnId);
|
|
278
373
|
}
|
|
279
374
|
/**
|
|
280
375
|
* Throws when the session cannot take a prompt now. The route calls this
|
|
@@ -293,12 +388,14 @@ export class AgentSession {
|
|
|
293
388
|
}
|
|
294
389
|
return { connection, sessionId };
|
|
295
390
|
}
|
|
296
|
-
async #runPrompt(connection, sessionId, blocks) {
|
|
391
|
+
async #runPrompt(connection, sessionId, blocks, turnId) {
|
|
297
392
|
try {
|
|
298
393
|
const response = await connection.agent.request(acp.methods.agent.session.prompt, { sessionId, prompt: blocks });
|
|
394
|
+
this.#clearTurnTaskContext(turnId);
|
|
299
395
|
this.#emit({ type: 'stop', stopReason: response.stopReason });
|
|
300
396
|
}
|
|
301
397
|
catch (error) {
|
|
398
|
+
this.#clearTurnTaskContext(turnId);
|
|
302
399
|
// A failure of the transport comes before the `exit` event, and only
|
|
303
400
|
// that event can say why the agent died: let it report first.
|
|
304
401
|
if (!(error instanceof acp.RequestError)) {
|
|
@@ -308,10 +405,14 @@ export class AgentSession {
|
|
|
308
405
|
]);
|
|
309
406
|
}
|
|
310
407
|
if (!this.#isClosed() && this.#error === null) {
|
|
311
|
-
this.#emit({
|
|
408
|
+
this.#emit({
|
|
409
|
+
type: 'error',
|
|
410
|
+
message: this.#redact(errorMessage(error))
|
|
411
|
+
});
|
|
312
412
|
}
|
|
313
413
|
}
|
|
314
414
|
finally {
|
|
415
|
+
this.#clearTurnTaskContext(turnId);
|
|
315
416
|
// A request still open once the turn is over (it ended in an error, say)
|
|
316
417
|
// is dead: answering it later would still make the agent act on it.
|
|
317
418
|
this.#cancelPendingPermissions();
|
|
@@ -320,6 +421,11 @@ export class AgentSession {
|
|
|
320
421
|
}
|
|
321
422
|
}
|
|
322
423
|
}
|
|
424
|
+
#clearTurnTaskContext(turnId) {
|
|
425
|
+
if (this.#turnTaskContext?.turnId === turnId) {
|
|
426
|
+
this.#turnTaskContext = undefined;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
323
429
|
/** A method, so TypeScript does not keep a stale narrowing across an `await`. */
|
|
324
430
|
#isClosed() {
|
|
325
431
|
return this.#status === 'closed';
|
|
@@ -328,6 +434,8 @@ export class AgentSession {
|
|
|
328
434
|
if (this.#status !== 'busy' || !this.#connection || !this.#acpSessionId) {
|
|
329
435
|
return;
|
|
330
436
|
}
|
|
437
|
+
// Stop inheritance immediately; the agent may take time to finish cancellation.
|
|
438
|
+
this.#turnTaskContext = undefined;
|
|
331
439
|
try {
|
|
332
440
|
await this.#connection.agent.notify(acp.methods.agent.session.cancel, {
|
|
333
441
|
sessionId: this.#acpSessionId
|
|
@@ -336,7 +444,9 @@ export class AgentSession {
|
|
|
336
444
|
catch (error) {
|
|
337
445
|
// The connection closed since the check above: the turn is over anyway.
|
|
338
446
|
if (!this.#isClosed()) {
|
|
339
|
-
throw new AgentSessionError(errorMessage(error), {
|
|
447
|
+
throw new AgentSessionError(this.#redact(errorMessage(error)), {
|
|
448
|
+
cause: error
|
|
449
|
+
});
|
|
340
450
|
}
|
|
341
451
|
}
|
|
342
452
|
}
|
|
@@ -367,6 +477,9 @@ export class AgentSession {
|
|
|
367
477
|
if (this.#status === 'closed') {
|
|
368
478
|
throw new AgentSessionStateError('The session is closed');
|
|
369
479
|
}
|
|
480
|
+
if (enabled && this.#options.permissionPolicy) {
|
|
481
|
+
throw new AgentSessionStateError('This session uses a fixed permission policy.');
|
|
482
|
+
}
|
|
370
483
|
if (this.#autoApprove === enabled) {
|
|
371
484
|
return;
|
|
372
485
|
}
|
|
@@ -396,6 +509,9 @@ export class AgentSession {
|
|
|
396
509
|
if (this.#status !== 'busy') {
|
|
397
510
|
return Promise.resolve({ outcome: { outcome: 'cancelled' } });
|
|
398
511
|
}
|
|
512
|
+
if (this.#options.permissionPolicy) {
|
|
513
|
+
return Promise.resolve(this.#policyPermission(params));
|
|
514
|
+
}
|
|
399
515
|
const requestId = randomUUID();
|
|
400
516
|
const request = mapPermissionRequest(requestId, params);
|
|
401
517
|
if (this.#autoApprove) {
|
|
@@ -416,6 +532,40 @@ export class AgentSession {
|
|
|
416
532
|
this.#emit(request);
|
|
417
533
|
});
|
|
418
534
|
}
|
|
535
|
+
#policyPermission(params) {
|
|
536
|
+
const previous = this.#permissionToolCalls.get(params.toolCall.toolCallId);
|
|
537
|
+
this.#permissionToolCalls.delete(params.toolCall.toolCallId);
|
|
538
|
+
let decision = {
|
|
539
|
+
allow: false,
|
|
540
|
+
reason: 'Permission policy could not verify this action.'
|
|
541
|
+
};
|
|
542
|
+
try {
|
|
543
|
+
decision = this.#options.permissionPolicy(params, previous);
|
|
544
|
+
}
|
|
545
|
+
catch {
|
|
546
|
+
// Policy failures must not create a manual prompt or grant an action.
|
|
547
|
+
}
|
|
548
|
+
const choice = decision.allow
|
|
549
|
+
? params.options.find(option => option.kind === 'allow_once')
|
|
550
|
+
: undefined;
|
|
551
|
+
if (choice) {
|
|
552
|
+
this.#emit({ type: 'auto-approved', title: decision.reason });
|
|
553
|
+
return { outcome: { outcome: 'selected', optionId: choice.optionId } };
|
|
554
|
+
}
|
|
555
|
+
this.#emit({
|
|
556
|
+
type: 'tool',
|
|
557
|
+
toolCallId: params.toolCall.toolCallId,
|
|
558
|
+
title: 'Validation permission denied',
|
|
559
|
+
status: 'failed',
|
|
560
|
+
output: decision.allow
|
|
561
|
+
? 'Permission policy requires an allow_once option.'
|
|
562
|
+
: decision.reason
|
|
563
|
+
});
|
|
564
|
+
const reject = params.options.find(option => option.kind === 'reject_once');
|
|
565
|
+
return reject
|
|
566
|
+
? { outcome: { outcome: 'selected', optionId: reject.optionId } }
|
|
567
|
+
: { outcome: { outcome: 'cancelled' } };
|
|
568
|
+
}
|
|
419
569
|
#onUpdate(update) {
|
|
420
570
|
// Agents may speak outside a turn — pi greets with its version and skill
|
|
421
571
|
// list right after session/new. That is noise in a chat transcript.
|
|
@@ -423,6 +573,24 @@ export class AgentSession {
|
|
|
423
573
|
update.sessionUpdate === 'agent_message_chunk') {
|
|
424
574
|
return;
|
|
425
575
|
}
|
|
576
|
+
if (this.#options.permissionPolicy &&
|
|
577
|
+
this.#status === 'busy' &&
|
|
578
|
+
(update.sessionUpdate === 'tool_call' ||
|
|
579
|
+
update.sessionUpdate === 'tool_call_update')) {
|
|
580
|
+
if (update.status === 'completed' || update.status === 'failed') {
|
|
581
|
+
this.#permissionToolCalls.delete(update.toolCallId);
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
const previous = this.#permissionToolCalls.get(update.toolCallId);
|
|
585
|
+
this.#permissionToolCalls.set(update.toolCallId, {
|
|
586
|
+
...previous,
|
|
587
|
+
...update
|
|
588
|
+
});
|
|
589
|
+
if (this.#permissionToolCalls.size > MAX_PERMISSION_TOOL_CALLS) {
|
|
590
|
+
this.#permissionToolCalls.delete(this.#permissionToolCalls.keys().next().value);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
426
594
|
const event = mapSessionUpdate(update);
|
|
427
595
|
if (event?.type === 'config') {
|
|
428
596
|
// Keep `#config` current: `setConfig` checks values against it.
|
|
@@ -476,12 +644,14 @@ export class AgentSession {
|
|
|
476
644
|
if (this.#status === 'closed') {
|
|
477
645
|
return;
|
|
478
646
|
}
|
|
647
|
+
this.#turnTaskContext = undefined;
|
|
479
648
|
this.#setStatus('closed', this.#error ?? undefined);
|
|
480
649
|
void rm(this.attachmentDir, { recursive: true, force: true }).catch(() => { });
|
|
481
650
|
// Unanswered permission requests must not leave the agent blocked forever.
|
|
482
651
|
this.#cancelPendingPermissions();
|
|
483
652
|
}
|
|
484
653
|
#cancelPendingPermissions() {
|
|
654
|
+
this.#permissionToolCalls.clear();
|
|
485
655
|
// Each resolver removes itself from the map, which Map iteration allows.
|
|
486
656
|
for (const pending of this.#pendingPermissions.values()) {
|
|
487
657
|
pending.resolve({ outcome: { outcome: 'cancelled' } });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { artifactBody } from "../../../shared/utils/artifact-body.js";
|
|
1
2
|
import { MAX_ATTACHMENT_BYTES } from "../../../shared/agents/constants.js";
|
|
2
3
|
import { AgentContextError } from "../../errors/agents.js";
|
|
3
4
|
import { errorMessage } from "../../../shared/utils/error-message.js";
|
|
@@ -33,8 +34,9 @@ function fenceFor(text) {
|
|
|
33
34
|
* goes in as an embedded resource when the agent supports it, otherwise as a
|
|
34
35
|
* fenced block in a plain text part — same content either way.
|
|
35
36
|
*/
|
|
36
|
-
function embed(deps, uri, title, mimeType, text) {
|
|
37
|
-
const body =
|
|
37
|
+
function embed(deps, uri, title, mimeType, text, prefix = '') {
|
|
38
|
+
const body = prefix +
|
|
39
|
+
truncateText(text, MAX_EMBEDDED_CHARS, omitted => `\n… [truncated by githuman: ${omitted} more characters]`);
|
|
38
40
|
if (deps.embeddedContext) {
|
|
39
41
|
return { type: 'resource', resource: { uri, mimeType, text: body } };
|
|
40
42
|
}
|
|
@@ -173,7 +175,33 @@ async function buildNoteItem(item, deps) {
|
|
|
173
175
|
throw asContextError(error);
|
|
174
176
|
}
|
|
175
177
|
}
|
|
178
|
+
async function buildArtifactItem(item, deps) {
|
|
179
|
+
try {
|
|
180
|
+
const storage = deps.artifacts;
|
|
181
|
+
if (!storage || item.storeId !== storage.storeId) {
|
|
182
|
+
throw new AgentContextError('Artifact store is unavailable or has changed');
|
|
183
|
+
}
|
|
184
|
+
const { content, ...snapshot } = storage.graph.readDocumentContext(item.artifactId);
|
|
185
|
+
const { artifact } = snapshot;
|
|
186
|
+
const prefix = 'Artifact metadata snapshot (current; original frontmatter is historical):\n' +
|
|
187
|
+
JSON.stringify(snapshot) +
|
|
188
|
+
'\n\n' +
|
|
189
|
+
'Use artifacts.relations with direction and nextCursor to read remaining links. Read related documents explicitly via artifacts.get and artifacts.get_content; they are not embedded here.\n' +
|
|
190
|
+
'Cite documents with /#/artifacts?storeId=' +
|
|
191
|
+
encodeURIComponent(storage.storeId) +
|
|
192
|
+
'&selectedId=' +
|
|
193
|
+
encodeURIComponent(artifact.id) +
|
|
194
|
+
'. Related document citations use their own selectedId.\n' +
|
|
195
|
+
'Use artifacts.get_content with this artifact ID and offset=0 to read the full original UTF-8 file; follow nextOffset. bodyStartLine identifies the body. Cite artifact IDs and distinguish historical statuses from current accepted context.\n\nDocument body:\n';
|
|
196
|
+
return embed(deps, `githuman://artifact/${encodeURIComponent(item.storeId)}/${encodeURIComponent(artifact.id)}`, `Artifact ${artifact.title}:`, 'text/markdown', artifactBody(content.toString('utf8'), artifact.bodyStartLine), prefix);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
throw asContextError(error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
176
202
|
function buildItem(item, deps) {
|
|
203
|
+
if (item.kind === 'artifact')
|
|
204
|
+
return buildArtifactItem(item, deps);
|
|
177
205
|
if (item.kind === 'note')
|
|
178
206
|
return buildNoteItem(item, deps);
|
|
179
207
|
if (item.kind === 'diff') {
|