@tequila99/githuman 0.2.3 → 0.3.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 +26 -0
- package/dist/cli/commands/export.js +2 -1
- package/dist/cli/server-runtime.js +13 -1
- package/dist/cli/startup-message.js +3 -2
- package/dist/server/adapters/agents/event-mapper.js +140 -0
- package/dist/server/app.js +21 -12
- package/dist/server/config/agents.js +141 -0
- package/dist/server/errors/agents.js +12 -0
- package/dist/server/errors/comments.js +2 -0
- package/dist/server/errors/export.js +2 -0
- package/dist/server/errors/http.js +4 -0
- package/dist/server/errors/reviews.js +3 -0
- package/dist/server/hooks/agents/local-origin.js +33 -0
- package/dist/server/repositories/review.repo.js +1 -3
- package/dist/server/routes/agent.js +135 -0
- package/dist/server/routes/comments.js +17 -67
- package/dist/server/routes/diff.js +5 -6
- package/dist/server/routes/events.js +6 -1
- package/dist/server/routes/export.js +6 -15
- package/dist/server/routes/git.js +12 -21
- package/dist/server/routes/reviews.js +11 -43
- package/dist/server/services/agent/agent-session.js +497 -0
- package/dist/server/services/agent/context-builder.js +137 -0
- package/dist/server/services/agent/file-index.js +58 -0
- package/dist/server/services/agent/session-registry.js +100 -0
- package/dist/server/services/comment.service.js +1 -2
- package/dist/server/services/diff.service.js +2 -1
- package/dist/server/services/export.service.js +1 -2
- package/dist/server/services/git.service.js +6 -7
- package/dist/server/services/review.service.js +3 -3
- package/dist/server/utils/executable.js +26 -0
- package/dist/server/utils/file-name.js +6 -0
- package/dist/server/utils/sse.js +11 -0
- package/dist/server/utils/text.js +29 -0
- package/dist/shared/agents/chat-names.js +17 -0
- package/dist/shared/agents/constants.js +6 -0
- package/dist/shared/agents/context-format.js +17 -0
- package/dist/shared/agents/file-search.js +48 -0
- package/dist/shared/agents/schemas.js +51 -0
- package/dist/shared/agents/types.js +11 -0
- package/dist/shared/app/types.js +1 -0
- package/dist/shared/comments/types.js +1 -0
- package/dist/shared/diff/types.js +4 -0
- package/dist/shared/{types.js → events/types.js} +0 -3
- package/dist/shared/git/types.js +1 -0
- package/dist/shared/http/types.js +1 -0
- package/dist/shared/network/loopback.js +4 -0
- package/dist/shared/reviews/types.js +1 -0
- package/dist/shared/utils/error-message.js +3 -0
- package/dist/shared/utils/guards.js +4 -0
- package/dist/web/assets/AppPage-CSb8txs5.js +1 -0
- package/dist/web/assets/CreateReviewFabButton-B18DLuH6.js +1 -0
- package/dist/web/assets/CreateReviewFabButton-Cufd8hVJ.css +1 -0
- package/dist/web/assets/{ErrorNotFound-BuL12Ld8.js → ErrorNotFound-B5uYICL4.js} +1 -1
- package/dist/web/assets/IndexPage-B-hkrnvt.css +1 -0
- package/dist/web/assets/IndexPage-Cm_ssBeC.js +1 -0
- package/dist/web/assets/MainLayout-ChxXEt_Q.css +1 -0
- package/dist/web/assets/MainLayout-ClBPF545.js +7 -0
- package/dist/web/assets/QBtn-E32fUOKx.js +1 -0
- package/dist/web/assets/QItemLabel-Co6oCEUr.js +1 -0
- package/dist/web/assets/QMenu-BZ1eK_rS.js +1 -0
- package/dist/web/assets/QSelect-D1V4tbDr.js +1 -0
- package/dist/web/assets/ReviewDetailPage-BWa3EEkv.css +1 -0
- package/dist/web/assets/ReviewDetailPage-Ct0hXwZL.js +1 -0
- package/dist/web/assets/ReviewsPage-CbLAU6OM.js +1 -0
- package/dist/web/assets/StatusSwitcher-C0k4efwK.js +4 -0
- package/dist/web/assets/StatusSwitcher-CZYtI0ID.css +1 -0
- package/dist/web/assets/abnfDiagram-O67JEVCF-DkOrqZLn.js +1 -0
- package/dist/web/assets/agent-icon-BKoq2a6T.js +17 -0
- package/dist/web/assets/agent-icon-BUd-vCRS.css +1 -0
- package/dist/web/assets/agent-store-CEQ6MmTC.js +1 -0
- package/dist/web/assets/app-info-store-CIqmSeWK.js +1 -0
- package/dist/web/assets/arc-BALAYY3f.js +1 -0
- package/dist/web/assets/architecture-7GRP2DOG-CTkghkmX.js +1 -0
- package/dist/web/assets/architectureDiagram-NJMV4G6O-C-xtrMea.js +36 -0
- package/dist/web/assets/array-BifhSqXX.js +1 -0
- package/dist/web/assets/blockDiagram-BEXU5L5S-DYo9Os-m.js +140 -0
- package/dist/web/assets/c4Diagram-YGBWAQC7-BpSFjUAX.js +38 -0
- package/dist/web/assets/channel-f9cE6NV9.js +1 -0
- package/dist/web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist/web/assets/chunk-3FUC2YCW-DtUqbu5K.js +2 -0
- package/dist/web/assets/chunk-5DYCD2WN-DeYTIM8k.js +1 -0
- package/dist/web/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/dist/web/assets/chunk-742MDFTN-8BfKAsu6.js +1 -0
- package/dist/web/assets/chunk-7INBJB4K-PXK092EZ.js +62 -0
- package/dist/web/assets/chunk-7M6MHVWA-Db9reT-V.js +213 -0
- package/dist/web/assets/chunk-7PRAP22T-CNFpjNaH.js +1 -0
- package/dist/web/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
- package/dist/web/assets/chunk-FOHPRMQF-CoA4358r.js +161 -0
- package/dist/web/assets/chunk-GTNCS2PH-C5gqOp1W.js +88 -0
- package/dist/web/assets/chunk-GWA4HPMP-BquHLG8L.js +1 -0
- package/dist/web/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
- package/dist/web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist/web/assets/chunk-MBY4JIJT-DyOEFgCh.js +72 -0
- package/dist/web/assets/chunk-NETBCI7D-Bd3ij3-b.js +1 -0
- package/dist/web/assets/chunk-O7XYJQB3-DQvIvDe6.js +126 -0
- package/dist/web/assets/chunk-UA2S7LBM-BDIHwgCZ.js +1 -0
- package/dist/web/assets/chunk-WEXAMYUT-DwQKTsK-.js +1 -0
- package/dist/web/assets/chunk-XXDRQBXY-DTdiON6C.js +1 -0
- package/dist/web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist/web/assets/chunk-Z7XXMR3K-CIvnaGnU.js +10 -0
- package/dist/web/assets/chunk-ZIGJFQKS-BdT_T5CV.js +2 -0
- package/dist/web/assets/classDiagram-v2-NBCMYWYE-BUoclHlO.js +217 -0
- package/dist/web/assets/{core-Ruj7F7dx.js → core-B8kUiZoM.js} +1 -1
- package/dist/web/assets/cose-bilkent-JH36ORCC-C16eW6pc.js +1 -0
- package/dist/web/assets/create-B9ZqyTxV.js +1 -0
- package/dist/web/assets/cynefin-OW5HDTMX-1mS7ZeoM.js +1 -0
- package/dist/web/assets/cynefinDiagram-VND7K2PF-D1PC4YT4.js +62 -0
- package/dist/web/assets/cytoscape.esm-B-1iW2ft.js +321 -0
- package/dist/web/assets/dagre-6A5THRUB-amODOP74.js +4 -0
- package/dist/web/assets/debounce-CDIE7CV6.js +1 -0
- package/dist/web/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/dist/web/assets/diagram-22UHCM2B-wUvcsN_B.js +200 -0
- package/dist/web/assets/diagram-3UASUU5V-CLiOVs2l.js +24 -0
- package/dist/web/assets/diagram-ATOU4E4O-Cs5cFGgz.js +3 -0
- package/dist/web/assets/diagram-CDSNMT55-C8Jb-YeE.js +30 -0
- package/dist/web/assets/diagram-MLGK6HIB-DA6C9fVB.js +24 -0
- package/dist/web/assets/diagram-MPIPVDR6-BOaFKuUi.js +41 -0
- package/dist/web/assets/dist-DuFVAX6Y.js +1 -0
- package/dist/web/assets/ebnfDiagram-ZINNZB2B-e5jvn-EE.js +1 -0
- package/dist/web/assets/elk-276RUBZZ-D7Gcu17D.js +27 -0
- package/dist/web/assets/engine-oniguruma-HbxpIAu4.js +1 -0
- package/dist/web/assets/erDiagram-OPXOYQCR-Cn1bBUF8.js +99 -0
- package/dist/web/assets/event-rR76ioXz.js +1 -0
- package/dist/web/assets/eventmodeling-NTZA5JFV-BjGpd42n.js +1 -0
- package/dist/web/assets/export-file-Di_2jvjP.js +1 -0
- package/dist/web/assets/fira-code-symbols2-400-normal-9X26I2LK.woff2 +0 -0
- package/dist/web/assets/fira-code-symbols2-500-normal-B5s_njw3.woff2 +0 -0
- package/dist/web/assets/fira-code-symbols2-600-normal-Bu3RnO39.woff2 +0 -0
- package/dist/web/assets/flowDiagram-KWPJA3E3-a3N8MVB8.js +1 -0
- package/dist/web/assets/ganttDiagram-FUAMR5RP-C3U8jeJB.js +292 -0
- package/dist/web/assets/gitGraph-4MIJSDKK-C165DC0H.js +1 -0
- package/dist/web/assets/gitGraphDiagram-X574FWY7-CVHdT1OC.js +106 -0
- package/dist/web/assets/golos-text-cyrillic-400-normal-BwL4n7Pb.woff +0 -0
- package/dist/web/assets/golos-text-cyrillic-400-normal-C7us6pn1.woff2 +0 -0
- package/dist/web/assets/golos-text-cyrillic-500-normal-BSLQUuP1.woff2 +0 -0
- package/dist/web/assets/golos-text-cyrillic-500-normal-hXinzVVQ.woff +0 -0
- package/dist/web/assets/golos-text-cyrillic-ext-400-normal-Bo67NYBq.woff2 +0 -0
- package/dist/web/assets/golos-text-cyrillic-ext-400-normal-D592xEk3.woff +0 -0
- package/dist/web/assets/golos-text-cyrillic-ext-500-normal-CLsu_eDI.woff2 +0 -0
- package/dist/web/assets/golos-text-cyrillic-ext-500-normal-InHNvB7v.woff +0 -0
- package/dist/web/assets/golos-text-latin-400-normal-Coi1FYaD.woff2 +0 -0
- package/dist/web/assets/golos-text-latin-400-normal-DOuJOmdK.woff +0 -0
- package/dist/web/assets/golos-text-latin-500-normal-BQo4s7Kn.woff +0 -0
- package/dist/web/assets/golos-text-latin-500-normal-BznAvurO.woff2 +0 -0
- package/dist/web/assets/golos-text-latin-ext-400-normal-BXgyX_iE.woff +0 -0
- package/dist/web/assets/golos-text-latin-ext-400-normal-BjKcJWKY.woff2 +0 -0
- package/dist/web/assets/golos-text-latin-ext-500-normal-9vZPKadr.woff2 +0 -0
- package/dist/web/assets/golos-text-latin-ext-500-normal-BmtMVntR.woff +0 -0
- package/dist/web/assets/graphlib-DS17s2tU.js +1 -0
- package/dist/web/assets/i18n-CyUPETur.js +1 -0
- package/dist/web/assets/{index-JAYe_SFI.css → index-C6ArNnKs.css} +1 -1
- package/dist/web/assets/index-C_B6Z2lc.js +2 -0
- package/dist/web/assets/info-A6RAGUB7-cbWtF3FJ.js +1 -0
- package/dist/web/assets/infoDiagram-VRGFBTTK-C_kWn3Ai.js +2 -0
- package/dist/web/assets/init-C-OQMol4.js +1 -0
- package/dist/web/assets/init-app-DnfYD-0k.js +1 -0
- package/dist/web/assets/is-ChHvR1Z-.js +1 -0
- package/dist/web/assets/ishikawaDiagram-OU5B5YK6-Xb9cDRr7.js +70 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-ext-400-normal-Bh0R7Dhr.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-ext-400-normal-C_uLvvQ5.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-ext-500-normal-C9ShMxGR.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-ext-500-normal-CEVyPk4Y.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-ext-600-normal-DVvC-yKp.woff +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-ext-600-normal-Dj6eZy5f.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-ByoDsISC.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-500-normal-BvH7FW2L.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-600-normal-Dtizs43-.woff2 +0 -0
- package/dist/web/assets/journeyDiagram-ZHPQQLJL-6eZcefap.js +139 -0
- package/dist/web/assets/kanban-definition-PNTS6WVX-D_z_AsKR.js +89 -0
- package/dist/web/assets/katex-ZlcWpGUi.js +257 -0
- package/dist/web/assets/line-v7JtZ-Za.js +1 -0
- package/dist/web/assets/linear-hp1KWmiC.js +1 -0
- package/dist/web/assets/mermaid-parser.core-Cwwk5NqO.js +7 -0
- package/dist/web/assets/mermaid.core-BjPJhwW0.js +44 -0
- package/dist/web/assets/mindmap-definition-NLK3R4M7-lQohhDXq.js +96 -0
- package/dist/web/assets/ordinal-BDEzSJ7C.js +1 -0
- package/dist/web/assets/packet-AYTQ26CC-DxiGe6nt.js +1 -0
- package/dist/web/assets/path-fybaL0A-.js +1 -0
- package/dist/web/assets/pegDiagram-GJSIUBJH-XZRpQTLx.js +1 -0
- package/dist/web/assets/pie-WAS4IAKB-fxN0O90k.js +1 -0
- package/dist/web/assets/pieDiagram-5QR66LMP-M_bBKE-n.js +39 -0
- package/dist/web/assets/pinia-0B8sIOgD.js +1 -0
- package/dist/web/assets/pinia-DbmXdZbT.js +1 -0
- package/dist/web/assets/quadrantDiagram-O4NWA36T-BNxVPrq3.js +7 -0
- package/dist/web/assets/radar-RG4KPBEZ-Cd-5aokk.js +1 -0
- package/dist/web/assets/railroad-74A4TZTK-BvSKL8Ze.js +1 -0
- package/dist/web/assets/railroad-abnf-HS5TGJTU-CB32K25L.js +1 -0
- package/dist/web/assets/railroad-ebnf-LZEXJU2U-CqQR3zRl.js +1 -0
- package/dist/web/assets/railroad-peg-WCYAUIDC-DRSdB-oL.js +1 -0
- package/dist/web/assets/railroadDiagram-XR7U4H2S-D664lPSL.js +1 -0
- package/dist/web/assets/requirementDiagram-PLB6GJNP-B_1Dl0-3.js +84 -0
- package/dist/web/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/dist/web/assets/runtime-core.esm-bundler-Carm8LUR.js +1 -0
- package/dist/web/assets/safe-storage-CWaD6Dq3.js +1 -0
- package/dist/web/assets/sankeyDiagram-IPEJSGJF-BvFmMC_F.js +40 -0
- package/dist/web/assets/sequenceDiagram-PO4LG4MO-DMK1ey4g.js +169 -0
- package/dist/web/assets/single-flight-r8B7stt1.js +1 -0
- package/dist/web/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
- package/dist/web/assets/src-Cy0hT8a0.js +1 -0
- package/dist/web/assets/stateDiagram-v2-GCMORJYK-VVElU-_E.js +291 -0
- package/dist/web/assets/swimlanes-2SLR337P-DyfYJvHL.js +1 -0
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-BQ0mK2BI.js +8 -0
- package/dist/web/assets/theme-BFceB3b9.js +1 -0
- package/dist/web/assets/timeline-definition-EJHVYXUP-DBoRb7uC.js +120 -0
- package/dist/web/assets/treeView-Q6P3EWNA-D8AoZg1Y.js +1 -0
- package/dist/web/assets/treemap-WGGIJYW6-DhcVtZsu.js +1 -0
- package/dist/web/assets/use-app-theme-DxZW-eOR.js +1 -0
- package/dist/web/assets/use-panel-width-CY75Fomr.js +1 -0
- package/dist/web/assets/usecaseDiagram-POWQR4AR-BCfvWOH4.js +328 -0
- package/dist/web/assets/vennDiagram-UO4OBE2U-BIk6-FLo.js +34 -0
- package/dist/web/assets/{vue-i18n.runtime-CxBM6QPV.js → vue-i18n.runtime-BQwnBdmC.js} +2 -2
- package/dist/web/assets/wardley-WFR3VGLG-BMHH70A3.js +1 -0
- package/dist/web/assets/wardleyDiagram-VNRHLVJA-DB-cxlSq.js +78 -0
- package/dist/web/assets/xychartDiagram-PMCCYNJV-BejE-3gi.js +7 -0
- package/dist/web/index.html +8 -6
- package/package.json +12 -3
- package/dist/web/assets/AppPage-B9tWPrzn.js +0 -1
- package/dist/web/assets/CreateReviewFabButton-BqWdgfEf.css +0 -1
- package/dist/web/assets/CreateReviewFabButton-DcXpOlBP.js +0 -1
- package/dist/web/assets/IndexPage-CsgdLXZh.css +0 -1
- package/dist/web/assets/IndexPage-y9DcUqW9.js +0 -1
- package/dist/web/assets/MainLayout-BRPoh8y0.css +0 -1
- package/dist/web/assets/MainLayout-fQytypS5.js +0 -1
- package/dist/web/assets/Platform-DDGYwfzl.js +0 -1
- package/dist/web/assets/QBtn-DGiC5uLo.js +0 -1
- package/dist/web/assets/QTooltip-CPN6UvuX.js +0 -1
- package/dist/web/assets/ReviewDetailPage-CL6A5zjH.css +0 -1
- package/dist/web/assets/ReviewDetailPage-aMMuYtax.js +0 -1
- package/dist/web/assets/ReviewsPage-B1CTHU13.js +0 -1
- package/dist/web/assets/StatusSwitcher-Bj-XCwSr.js +0 -3
- package/dist/web/assets/StatusSwitcher-BydQq1LI.css +0 -1
- package/dist/web/assets/app-info-store-Dw8pPU-w.js +0 -1
- package/dist/web/assets/client-De34x_P_.js +0 -1
- package/dist/web/assets/engine-oniguruma-Bon2Icja.js +0 -1
- package/dist/web/assets/event-D0kaqRwq.js +0 -1
- package/dist/web/assets/format-Bb6ahGqi.js +0 -1
- package/dist/web/assets/i18n-Dw0eMaZf.js +0 -1
- package/dist/web/assets/index-i1Dlwasy.js +0 -2
- package/dist/web/assets/init-app-CPTVCTFc.js +0 -1
- package/dist/web/assets/pinia-ClnoFqXt.js +0 -1
- package/dist/web/assets/pinia-jMX0pzvu.js +0 -1
- package/dist/web/assets/runtime-core.esm-bundler-Db5Q9Gsb.js +0 -1
- package/dist/web/assets/theme-CgDsrcvS.js +0 -1
- package/dist/web/assets/use-app-theme-D0Pl-VfI.js +0 -1
- package/dist/web/assets/use-server-events-pJWjsMIC.js +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { NotFoundError } from "../errors/http.js";
|
|
1
2
|
import { Type } from '@sinclair/typebox';
|
|
2
3
|
import { getReview } from "../services/review.service.js";
|
|
3
|
-
import { createComment, getComments, editComment, removeComment, resolveComment, unresolveComment
|
|
4
|
+
import { createComment, getComments, editComment, removeComment, resolveComment, unresolveComment } from "../services/comment.service.js";
|
|
4
5
|
// Null goes first in each union: Fastify's Ajv coerces types, and with
|
|
5
6
|
// Integer (or String) first it turns a JSON null into 0 (or "") before the
|
|
6
7
|
// Null branch is ever tried — a file-level comment would be stored as line 0.
|
|
@@ -27,87 +28,36 @@ export async function commentRoutes(app, opts) {
|
|
|
27
28
|
const typedApp = app.withTypeProvider();
|
|
28
29
|
typedApp.post('/api/reviews/:id/comments', { schema: { params: ReviewIdParams, body: CreateCommentBody } }, async (request, reply) => {
|
|
29
30
|
if (!getReview(db, request.params.id)) {
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
error: 'Not Found',
|
|
33
|
-
message: `Review ${request.params.id} not found`,
|
|
34
|
-
statusCode: 404
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
try {
|
|
38
|
-
const comment = createComment(db, request.params.id, request.body, eventBus);
|
|
39
|
-
reply.code(201);
|
|
40
|
-
return comment;
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
if (error instanceof ValidationError) {
|
|
44
|
-
reply.code(400);
|
|
45
|
-
return {
|
|
46
|
-
error: 'Bad Request',
|
|
47
|
-
message: error.message,
|
|
48
|
-
statusCode: 400
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
throw error;
|
|
31
|
+
throw new NotFoundError(`Review ${request.params.id} not found`);
|
|
52
32
|
}
|
|
33
|
+
const comment = createComment(db, request.params.id, request.body, eventBus);
|
|
34
|
+
reply.code(201);
|
|
35
|
+
return comment;
|
|
53
36
|
});
|
|
54
|
-
typedApp.get('/api/reviews/:id/comments', { schema: { params: ReviewIdParams } }, async (request
|
|
37
|
+
typedApp.get('/api/reviews/:id/comments', { schema: { params: ReviewIdParams } }, async (request) => {
|
|
55
38
|
if (!getReview(db, request.params.id)) {
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
error: 'Not Found',
|
|
59
|
-
message: `Review ${request.params.id} not found`,
|
|
60
|
-
statusCode: 404
|
|
61
|
-
};
|
|
39
|
+
throw new NotFoundError(`Review ${request.params.id} not found`);
|
|
62
40
|
}
|
|
63
41
|
return getComments(db, request.params.id);
|
|
64
42
|
});
|
|
65
|
-
typedApp.patch('/api/comments/:id', { schema: { params: CommentIdParams, body: UpdateCommentBody } }, async (request
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
reply.code(404);
|
|
70
|
-
return {
|
|
71
|
-
error: 'Not Found',
|
|
72
|
-
message: `Comment ${request.params.id} not found`,
|
|
73
|
-
statusCode: 404
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
return updated;
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
if (error instanceof ValidationError) {
|
|
80
|
-
reply.code(400);
|
|
81
|
-
return {
|
|
82
|
-
error: 'Bad Request',
|
|
83
|
-
message: error.message,
|
|
84
|
-
statusCode: 400
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
throw error;
|
|
43
|
+
typedApp.patch('/api/comments/:id', { schema: { params: CommentIdParams, body: UpdateCommentBody } }, async (request) => {
|
|
44
|
+
const updated = editComment(db, request.params.id, request.body.content, eventBus);
|
|
45
|
+
if (!updated) {
|
|
46
|
+
throw new NotFoundError(`Comment ${request.params.id} not found`);
|
|
88
47
|
}
|
|
48
|
+
return updated;
|
|
89
49
|
});
|
|
90
|
-
typedApp.patch('/api/comments/:id/resolve', { schema: { params: CommentIdParams } }, async (request
|
|
50
|
+
typedApp.patch('/api/comments/:id/resolve', { schema: { params: CommentIdParams } }, async (request) => {
|
|
91
51
|
const updated = resolveComment(db, request.params.id, eventBus);
|
|
92
52
|
if (!updated) {
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
error: 'Not Found',
|
|
96
|
-
message: `Comment ${request.params.id} not found`,
|
|
97
|
-
statusCode: 404
|
|
98
|
-
};
|
|
53
|
+
throw new NotFoundError(`Comment ${request.params.id} not found`);
|
|
99
54
|
}
|
|
100
55
|
return updated;
|
|
101
56
|
});
|
|
102
|
-
typedApp.patch('/api/comments/:id/unresolve', { schema: { params: CommentIdParams } }, async (request
|
|
57
|
+
typedApp.patch('/api/comments/:id/unresolve', { schema: { params: CommentIdParams } }, async (request) => {
|
|
103
58
|
const updated = unresolveComment(db, request.params.id, eventBus);
|
|
104
59
|
if (!updated) {
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
error: 'Not Found',
|
|
108
|
-
message: `Comment ${request.params.id} not found`,
|
|
109
|
-
statusCode: 404
|
|
110
|
-
};
|
|
60
|
+
throw new NotFoundError(`Comment ${request.params.id} not found`);
|
|
111
61
|
}
|
|
112
62
|
return updated;
|
|
113
63
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BadRequestError } from "../errors/http.js";
|
|
1
2
|
import { Type } from '@sinclair/typebox';
|
|
2
3
|
import { getStagedDiff, getUnstagedDiff, getBranchDiff, getCommitsDiff } from "../services/diff.service.js";
|
|
3
4
|
const BranchQuery = Type.Object({
|
|
@@ -16,24 +17,22 @@ export async function diffRoutes(app, opts) {
|
|
|
16
17
|
typedApp.get('/api/diff/unstaged', async () => {
|
|
17
18
|
return getUnstagedDiff(repositoryPath);
|
|
18
19
|
});
|
|
19
|
-
typedApp.get('/api/diff/branch', { schema: { querystring: BranchQuery } }, async (request
|
|
20
|
+
typedApp.get('/api/diff/branch', { schema: { querystring: BranchQuery } }, async (request) => {
|
|
20
21
|
try {
|
|
21
22
|
return await getBranchDiff(repositoryPath, request.query.base);
|
|
22
23
|
}
|
|
23
24
|
catch (err) {
|
|
24
|
-
reply.code(400);
|
|
25
25
|
const message = err instanceof Error ? err.message : 'Bad ref';
|
|
26
|
-
|
|
26
|
+
throw new BadRequestError(message, { cause: err });
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
|
-
typedApp.get('/api/diff/commits', { schema: { querystring: CommitsQuery } }, async (request
|
|
29
|
+
typedApp.get('/api/diff/commits', { schema: { querystring: CommitsQuery } }, async (request) => {
|
|
30
30
|
try {
|
|
31
31
|
return await getCommitsDiff(repositoryPath, request.query.from, request.query.to);
|
|
32
32
|
}
|
|
33
33
|
catch (err) {
|
|
34
|
-
reply.code(400);
|
|
35
34
|
const message = err instanceof Error ? err.message : 'Bad ref';
|
|
36
|
-
|
|
35
|
+
throw new BadRequestError(message, { cause: err });
|
|
37
36
|
}
|
|
38
37
|
});
|
|
39
38
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import { safeSend } from "../utils/sse.js";
|
|
1
2
|
export async function eventRoutes(app, opts) {
|
|
2
3
|
const { eventBus, instanceId } = opts;
|
|
3
4
|
const hello = { instanceId };
|
|
4
5
|
app.get('/api/events', { sse: true }, async (request, reply) => {
|
|
5
6
|
reply.sse.keepAlive();
|
|
6
7
|
await reply.sse.send({ event: 'connected', data: hello });
|
|
8
|
+
// The client can leave during the await; a later `onClose` would never run.
|
|
9
|
+
if (!reply.sse.isConnected) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
7
12
|
const unsubscribe = eventBus.subscribe(event => {
|
|
8
|
-
|
|
13
|
+
safeSend(reply.sse, {
|
|
9
14
|
event: event.type,
|
|
10
15
|
data: { reviewId: event.reviewId }
|
|
11
16
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
|
-
import { exportAsJson, exportAsMarkdown
|
|
2
|
+
import { exportAsJson, exportAsMarkdown } from "../services/export.service.js";
|
|
3
3
|
const ExportParams = Type.Object({ id: Type.String() });
|
|
4
4
|
const ExportQuery = Type.Object({
|
|
5
5
|
format: Type.Union([Type.Literal('json'), Type.Literal('markdown')])
|
|
@@ -8,20 +8,11 @@ export async function exportRoutes(app, opts) {
|
|
|
8
8
|
const { db, repositoryPath } = opts;
|
|
9
9
|
const typedApp = app.withTypeProvider();
|
|
10
10
|
typedApp.get('/api/reviews/:id/export', { schema: { params: ExportParams, querystring: ExportQuery } }, async (request, reply) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return exportAsJson(db, request.params.id);
|
|
14
|
-
}
|
|
15
|
-
const markdown = await exportAsMarkdown(db, request.params.id, repositoryPath);
|
|
16
|
-
reply.type('text/markdown');
|
|
17
|
-
return markdown;
|
|
18
|
-
}
|
|
19
|
-
catch (error) {
|
|
20
|
-
if (error instanceof ExportNotFoundError) {
|
|
21
|
-
reply.code(404);
|
|
22
|
-
return { error: 'Not Found', message: error.message, statusCode: 404 };
|
|
23
|
-
}
|
|
24
|
-
throw error;
|
|
11
|
+
if (request.query.format === 'json') {
|
|
12
|
+
return exportAsJson(db, request.params.id);
|
|
25
13
|
}
|
|
14
|
+
const markdown = await exportAsMarkdown(db, request.params.id, repositoryPath);
|
|
15
|
+
reply.type('text/markdown');
|
|
16
|
+
return markdown;
|
|
26
17
|
});
|
|
27
18
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BadRequestError } from "../errors/http.js";
|
|
1
2
|
import { Type } from '@sinclair/typebox';
|
|
2
3
|
import { getRepositoryInfo, stagePaths, unstagePaths, discardPaths, getFilesAtRef, getFileAtRef } from "../services/git.service.js";
|
|
3
4
|
const TreeParams = Type.Object({
|
|
@@ -20,61 +21,52 @@ export async function gitRoutes(app, opts) {
|
|
|
20
21
|
app.get('/api/git/info', async () => {
|
|
21
22
|
return getRepositoryInfo(repositoryPath);
|
|
22
23
|
});
|
|
23
|
-
typedApp.post('/api/git/stage', { schema: { body: OptionalPathsBody } }, async (request
|
|
24
|
+
typedApp.post('/api/git/stage', { schema: { body: OptionalPathsBody } }, async (request) => {
|
|
24
25
|
try {
|
|
25
26
|
await stagePaths(repositoryPath, request.body.paths ?? []);
|
|
26
27
|
return { ok: true };
|
|
27
28
|
}
|
|
28
29
|
catch (err) {
|
|
29
|
-
reply.code(400);
|
|
30
30
|
const message = err instanceof Error ? err.message : 'Failed to stage';
|
|
31
|
-
|
|
31
|
+
throw new BadRequestError(message, { cause: err });
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
|
-
typedApp.post('/api/git/unstage', { schema: { body: OptionalPathsBody } }, async (request
|
|
34
|
+
typedApp.post('/api/git/unstage', { schema: { body: OptionalPathsBody } }, async (request) => {
|
|
35
35
|
try {
|
|
36
36
|
await unstagePaths(repositoryPath, request.body.paths ?? []);
|
|
37
37
|
return { ok: true };
|
|
38
38
|
}
|
|
39
39
|
catch (err) {
|
|
40
|
-
reply.code(400);
|
|
41
40
|
const message = err instanceof Error ? err.message : 'Failed to unstage';
|
|
42
|
-
|
|
41
|
+
throw new BadRequestError(message, { cause: err });
|
|
43
42
|
}
|
|
44
43
|
});
|
|
45
|
-
typedApp.post('/api/git/discard', { schema: { body: DiscardBody } }, async (request
|
|
44
|
+
typedApp.post('/api/git/discard', { schema: { body: DiscardBody } }, async (request) => {
|
|
46
45
|
try {
|
|
47
46
|
await discardPaths(repositoryPath, request.body.paths);
|
|
48
47
|
return { ok: true };
|
|
49
48
|
}
|
|
50
49
|
catch (err) {
|
|
51
|
-
reply.code(400);
|
|
52
50
|
const message = err instanceof Error ? err.message : 'Failed to discard changes';
|
|
53
|
-
|
|
51
|
+
throw new BadRequestError(message, { cause: err });
|
|
54
52
|
}
|
|
55
53
|
});
|
|
56
|
-
typedApp.get('/api/git/tree/:ref', { schema: { params: TreeParams } }, async (request
|
|
54
|
+
typedApp.get('/api/git/tree/:ref', { schema: { params: TreeParams } }, async (request) => {
|
|
57
55
|
const { ref } = request.params;
|
|
58
56
|
try {
|
|
59
57
|
const files = await getFilesAtRef(repositoryPath, ref);
|
|
60
58
|
return { ref, files };
|
|
61
59
|
}
|
|
62
60
|
catch (err) {
|
|
63
|
-
reply.code(400);
|
|
64
61
|
const message = err instanceof Error ? err.message : 'Failed to list files';
|
|
65
|
-
|
|
62
|
+
throw new BadRequestError(message, { cause: err });
|
|
66
63
|
}
|
|
67
64
|
});
|
|
68
|
-
typedApp.get('/api/git/file/*', { schema: { querystring: FileContentQuery } }, async (request
|
|
65
|
+
typedApp.get('/api/git/file/*', { schema: { querystring: FileContentQuery } }, async (request) => {
|
|
69
66
|
const filePath = request.params['*'];
|
|
70
67
|
const { ref } = request.query;
|
|
71
68
|
if (!filePath) {
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
error: 'Bad Request',
|
|
75
|
-
message: 'File path is required',
|
|
76
|
-
statusCode: 400
|
|
77
|
-
};
|
|
69
|
+
throw new BadRequestError('File path is required');
|
|
78
70
|
}
|
|
79
71
|
let content;
|
|
80
72
|
let isBinary;
|
|
@@ -83,9 +75,8 @@ export async function gitRoutes(app, opts) {
|
|
|
83
75
|
({ content, isBinary } = await getFileAtRef(repositoryPath, ref, filePath));
|
|
84
76
|
}
|
|
85
77
|
catch (err) {
|
|
86
|
-
reply.code(400);
|
|
87
78
|
const message = err instanceof Error ? err.message : 'Failed to read file';
|
|
88
|
-
|
|
79
|
+
throw new BadRequestError(message, { cause: err });
|
|
89
80
|
}
|
|
90
81
|
const lines = isBinary ? [] : content.split('\n');
|
|
91
82
|
return {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { NotFoundError, BadRequestError } from "../errors/http.js";
|
|
1
2
|
import { Type } from '@sinclair/typebox';
|
|
2
|
-
import { createReview, getReview, getReviews, setReviewStatus, removeReview
|
|
3
|
+
import { createReview, getReview, getReviews, setReviewStatus, removeReview } from "../services/review.service.js";
|
|
3
4
|
import { getRepositoryInfo } from "../services/git.service.js";
|
|
4
5
|
const CreateReviewBody = Type.Object({
|
|
5
6
|
sourceType: Type.Optional(Type.Union([
|
|
@@ -33,22 +34,9 @@ export async function reviewRoutes(app, opts) {
|
|
|
33
34
|
const { repositoryPath, db, eventBus } = opts;
|
|
34
35
|
const typedApp = app.withTypeProvider();
|
|
35
36
|
typedApp.post('/api/reviews', { schema: { body: CreateReviewBody } }, async (request, reply) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return review;
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
if (error instanceof ValidationError) {
|
|
43
|
-
reply.code(400);
|
|
44
|
-
return {
|
|
45
|
-
error: 'Bad Request',
|
|
46
|
-
message: error.message,
|
|
47
|
-
statusCode: 400
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
37
|
+
const review = await createReview(db, repositoryPath, request.body, eventBus);
|
|
38
|
+
reply.code(201);
|
|
39
|
+
return review;
|
|
52
40
|
});
|
|
53
41
|
typedApp.get('/api/reviews', { schema: { querystring: ReviewsQuery } }, async (request) => {
|
|
54
42
|
const { branch, search, createdFrom, createdTo, files } = request.query;
|
|
@@ -63,46 +51,26 @@ export async function reviewRoutes(app, opts) {
|
|
|
63
51
|
: undefined
|
|
64
52
|
});
|
|
65
53
|
});
|
|
66
|
-
typedApp.get('/api/reviews/:id', { schema: { params: ReviewIdParams } }, async (request
|
|
54
|
+
typedApp.get('/api/reviews/:id', { schema: { params: ReviewIdParams } }, async (request) => {
|
|
67
55
|
const review = getReview(db, request.params.id);
|
|
68
56
|
if (!review) {
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
error: 'Not Found',
|
|
72
|
-
message: `Review ${request.params.id} not found`,
|
|
73
|
-
statusCode: 404
|
|
74
|
-
};
|
|
57
|
+
throw new NotFoundError(`Review ${request.params.id} not found`);
|
|
75
58
|
}
|
|
76
59
|
return review;
|
|
77
60
|
});
|
|
78
|
-
typedApp.patch('/api/reviews/:id', { schema: { params: ReviewIdParams, body: UpdateReviewBody } }, async (request
|
|
61
|
+
typedApp.patch('/api/reviews/:id', { schema: { params: ReviewIdParams, body: UpdateReviewBody } }, async (request) => {
|
|
79
62
|
if (!request.body.status) {
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
error: 'Bad Request',
|
|
83
|
-
message: '"status" is required',
|
|
84
|
-
statusCode: 400
|
|
85
|
-
};
|
|
63
|
+
throw new BadRequestError('"status" is required');
|
|
86
64
|
}
|
|
87
65
|
const updated = setReviewStatus(db, request.params.id, request.body.status, eventBus);
|
|
88
66
|
if (!updated) {
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
error: 'Not Found',
|
|
92
|
-
message: `Review ${request.params.id} not found`,
|
|
93
|
-
statusCode: 404
|
|
94
|
-
};
|
|
67
|
+
throw new NotFoundError(`Review ${request.params.id} not found`);
|
|
95
68
|
}
|
|
96
69
|
return updated;
|
|
97
70
|
});
|
|
98
71
|
typedApp.delete('/api/reviews/:id', { schema: { params: ReviewIdParams } }, async (request, reply) => {
|
|
99
72
|
if (!getReview(db, request.params.id)) {
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
error: 'Not Found',
|
|
103
|
-
message: `Review ${request.params.id} not found`,
|
|
104
|
-
statusCode: 404
|
|
105
|
-
};
|
|
73
|
+
throw new NotFoundError(`Review ${request.params.id} not found`);
|
|
106
74
|
}
|
|
107
75
|
removeReview(db, request.params.id, eventBus);
|
|
108
76
|
reply.code(204);
|