@cursor/july 0.1.111 → 0.1.112
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/dist/bin/agent-serve.js +18 -1
- package/dist/channels/github/github-channel.d.ts +29 -19
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +29 -19
- package/dist/channels/slack/agentic-delivery.d.ts.map +1 -1
- package/dist/channels/slack/agentic-delivery.js +2 -0
- package/dist/channels/slack/dispatch.d.ts +11 -1
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +142 -39
- package/dist/channels/slack/placeholder.d.ts +26 -0
- package/dist/channels/slack/placeholder.d.ts.map +1 -1
- package/dist/channels/slack/placeholder.js +28 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +9 -16
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.Drol6mi6.js → app.DxTdhphC.js} +4 -4
- package/dist/docs/assets/building-with-agents.md.BBCx0AUo.js +9 -0
- package/dist/docs/assets/building-with-agents.md.BBCx0AUo.lean.js +1 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.QmjDU6Jh.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.CdqoBZJX.js → VPLocalSearchBox.CR3KTF0X.js} +1 -1
- package/dist/docs/assets/chunks/{arc.BVX3ycTn.js → arc.CVVqBOdS.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CcChnMxX.js → architectureDiagram-Q4EWVU46.CJHGP4ki.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.xwtXO-yt.js → baseUniq.r7UVVRBP.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.CijZ_taK.js → blockDiagram-DXYQGD6D.DKmMaTre.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.0FBvwBvK.js → c4Diagram-AHTNJAMY.DDJsntUO.js} +1 -1
- package/dist/docs/assets/chunks/channel.BjpoSbz_.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CELMmMDA.js → chunk-4BX2VUAB.BK2rKt6W.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.C4bhFtSm.js → chunk-4TB4RGXK.DRLV8RnF.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.ZnQ9gRRQ.js → chunk-55IACEB6.DaKjxtb7.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.DPlmglG-.js → chunk-EDXVE4YY.C5sPCIT1.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.BrUk8pff.js → chunk-FMBD7UC4.CSGWyNTB.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CcmWIncu.js → chunk-OYMX7WX6.D5tK9XEr.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.D65-cs8I.js → chunk-QZHKN3VN.BeZGd1UZ.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.qoXZpG9F.js → chunk-YZCP3GAM.U_tfWwQR.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.BgxOlMHw.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.BgxOlMHw.js +1 -0
- package/dist/docs/assets/chunks/clone.DRuGBKZC.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.8rYtqudO.js → cose-bilkent-S5V4N54A.DVeRXIb6.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.DrRP1fOh.js → dagre-KV5264BT.BpKJAeRZ.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DHj_xA2_.js → diagram-5BDNPKRD.BQOtrd1Z.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.Bz_6nAKj.js → diagram-G4DWMVQ6.CSDAhjPI.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.BWA0xSW9.js → diagram-MMDJMWI5.Dpztst2S.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.CpTJLNJI.js → diagram-TYMM5635.qJHRizHR.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.-7AWWSrP.js → erDiagram-SMLLAGMA.vbDotH3l.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BTnQ742_.js → flowDiagram-DWJPFMVM.CqS_ZQr4.js} +1 -1
- package/dist/docs/assets/chunks/framework.BNw1pucY.js +19 -0
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.B5_HiiQ5.js → ganttDiagram-T4ZO3ILL.DTLdR4pN.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.CZcNTFZd.js → gitGraphDiagram-UUTBAWPF.D04lnbnr.js} +1 -1
- package/dist/docs/assets/chunks/{graph.V2GLaab4.js → graph.BlfqLJsM.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.7pZOkCCU.js → infoDiagram-42DDH7IO.tAooImWA.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DSMo3Qa3.js → ishikawaDiagram-UXIWVN3A.ClUsVqnJ.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.BNEgWN1S.js → journeyDiagram-VCZTEJTY.C3tUgyCg.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B-4d4tC7.js → kanban-definition-6JOO6SKY.CtD9-QCe.js} +1 -1
- package/dist/docs/assets/chunks/{layout.Dvbn9nSb.js → layout.D38U-LnT.js} +1 -1
- package/dist/docs/assets/chunks/{linear.D2GM4p4b.js → linear.BJmssyhN.js} +1 -1
- package/dist/docs/assets/chunks/{min.DVBtLK-B.js → min.DNgXoouU.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CnJRI55x.js → mindmap-definition-QFDTVHPH.Dcp6cxeu.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.CtoaTFlA.js → pieDiagram-DEJITSTG.CLDw6zIs.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.DtT24_vN.js → quadrantDiagram-34T5L4WZ.CYaeeY4c.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CjSO4o8f.js → requirementDiagram-MS252O5E.gMYuRpq2.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.-wWiIVWa.js → sankeyDiagram-XADWPNL6.CZqyHFbc.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.DSk8s4gX.js → sequenceDiagram-FGHM5R23.BTsCjUDN.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BFKAsdkN.js → stateDiagram-FHFEXIEX.CftT9mLJ.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.-43J68xB.js +1 -0
- package/dist/docs/assets/chunks/{theme.C0MctGaz.js → theme.B_7J9ZsV.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.TUNJbAFe.js → timeline-definition-GMOUNBTQ.DbU3WUNw.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.C-RGNnk4.js → vennDiagram-DHZGUBPP.ixsq-q2u.js} +1 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.WRXz-Dux.js +162 -0
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.DH4zt73Y.js → wardleyDiagram-NUSXRM2D.C0ewvgbp.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.B-3k6bF6.js → xychartDiagram-5P7HB3ND.nAEhF4bO.js} +1 -1
- package/dist/docs/assets/deployment.md.D2jQZuFx.js +32 -0
- package/dist/docs/assets/deployment.md.D2jQZuFx.lean.js +1 -0
- package/dist/docs/assets/evals.md.BYvfZ-PO.js +72 -0
- package/dist/docs/assets/evals.md.BYvfZ-PO.lean.js +1 -0
- package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.js +30 -0
- package/dist/docs/assets/guides_agent-to-agent.md.8oDTfu-E.lean.js +1 -0
- package/dist/docs/assets/guides_bitbucket.md.mpevW-VP.js +145 -0
- package/dist/docs/assets/guides_bitbucket.md.mpevW-VP.lean.js +1 -0
- package/dist/docs/assets/guides_cloud-agents.md.Cp1O3u-X.js +15 -0
- package/dist/docs/assets/guides_cloud-agents.md.Cp1O3u-X.lean.js +1 -0
- package/dist/docs/assets/guides_convert-automation.md.CqEyfP6Y.js +43 -0
- package/dist/docs/assets/guides_convert-automation.md.CqEyfP6Y.lean.js +1 -0
- package/dist/docs/assets/guides_github.md.BwpBp3ed.js +156 -0
- package/dist/docs/assets/guides_github.md.BwpBp3ed.lean.js +1 -0
- package/dist/docs/assets/guides_gitlab.md.DaEC3nMk.js +153 -0
- package/dist/docs/assets/guides_gitlab.md.DaEC3nMk.lean.js +1 -0
- package/dist/docs/assets/guides_grokbot-agents.md.CMhZNdEU.js +16 -0
- package/dist/docs/assets/guides_grokbot-agents.md.CMhZNdEU.lean.js +1 -0
- package/dist/docs/assets/guides_improve.md.Bnp4F99w.js +22 -0
- package/dist/docs/assets/guides_improve.md.Bnp4F99w.lean.js +1 -0
- package/dist/docs/assets/guides_mcp-oauth.md.bSFakfCY.js +50 -0
- package/dist/docs/assets/guides_mcp-oauth.md.bSFakfCY.lean.js +1 -0
- package/dist/docs/assets/guides_opentelemetry.md.BKDxQmmd.js +35 -0
- package/dist/docs/assets/guides_opentelemetry.md.BKDxQmmd.lean.js +1 -0
- package/dist/docs/assets/guides_slack.md.Bo96y42E.js +70 -0
- package/dist/docs/assets/guides_slack.md.Bo96y42E.lean.js +1 -0
- package/dist/docs/assets/guides_webhooks.md.1A72_VEE.js +92 -0
- package/dist/docs/assets/guides_webhooks.md.1A72_VEE.lean.js +1 -0
- package/dist/docs/assets/hillclimbing.md.D4E1o5Sa.js +7 -0
- package/dist/docs/assets/hillclimbing.md.D4E1o5Sa.lean.js +1 -0
- package/dist/docs/assets/{index.md.BFVyY2KT.js → index.md.C-t81M5J.js} +2 -2
- package/dist/docs/assets/{index.md.BFVyY2KT.lean.js → index.md.C-t81M5J.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.D3MjSZN-.js → quickstart.md.DAvVhuuU.js} +1 -1
- package/dist/docs/assets/{quickstart.md.D3MjSZN-.lean.js → quickstart.md.DAvVhuuU.lean.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.CfVA-LZJ.js → reference_agent-config.md.DGPyw7ms.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.CfVA-LZJ.lean.js → reference_agent-config.md.DGPyw7ms.lean.js} +1 -1
- package/dist/docs/assets/{reference_artifacts.md.Vf7qyIZ-.js → reference_artifacts.md.Bu_4HmsD.js} +1 -1
- package/dist/docs/assets/{reference_artifacts.md.Vf7qyIZ-.lean.js → reference_artifacts.md.Bu_4HmsD.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.icqLKcTc.js → reference_channels.md.nFWbzAic.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.icqLKcTc.lean.js → reference_channels.md.nFWbzAic.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.B2dBL6L8.js → reference_cli.md.DLWDz9ij.js} +3 -1
- package/dist/docs/assets/{reference_cli.md.B2dBL6L8.lean.js → reference_cli.md.DLWDz9ij.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Cb3U_c8n.js → reference_connections.md.CmyrlXfY.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Cb3U_c8n.lean.js → reference_connections.md.CmyrlXfY.lean.js} +1 -1
- package/dist/docs/assets/reference_evals.md.DNJzM_yf.js +57 -0
- package/dist/docs/assets/reference_evals.md.DNJzM_yf.lean.js +1 -0
- package/dist/docs/assets/reference_extensions.md.Ceq-qT8d.js +58 -0
- package/dist/docs/assets/reference_extensions.md.Ceq-qT8d.lean.js +1 -0
- package/dist/docs/assets/{reference_hooks.md.CZuynAxj.js → reference_hooks.md.B7uzNENk.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.CZuynAxj.lean.js → reference_hooks.md.B7uzNENk.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DTKcYE6L.js → reference_http-api.md.CduHavZ2.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DTKcYE6L.lean.js → reference_http-api.md.CduHavZ2.lean.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.D7gkckK-.js → reference_instructions.md.CU1My5My.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.D7gkckK-.lean.js → reference_instructions.md.CU1My5My.lean.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.D2YExv5K.js → reference_playground.md.Ch2d0Iqi.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.D2YExv5K.lean.js → reference_playground.md.Ch2d0Iqi.lean.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.DPxbUJyt.js → reference_project-layout.md.BGhgpy9V.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.DPxbUJyt.lean.js → reference_project-layout.md.BGhgpy9V.lean.js} +1 -1
- package/dist/docs/assets/{reference_prompt.md.BQ5uAv1F.js → reference_prompt.md.Ccp0R53H.js} +1 -1
- package/dist/docs/assets/{reference_prompt.md.BQ5uAv1F.lean.js → reference_prompt.md.Ccp0R53H.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.BasfZWO-.js → reference_schedules.md.B2Nm6FaD.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.BasfZWO-.lean.js → reference_schedules.md.B2Nm6FaD.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.YKvIsWAx.js → reference_sessions.md.1_6Vyv7x.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.YKvIsWAx.lean.js → reference_sessions.md.1_6Vyv7x.lean.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.rNgpsGd0.js → reference_skills.md.DjQkRefx.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.rNgpsGd0.lean.js → reference_skills.md.DjQkRefx.lean.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.e5qitjJt.js → reference_subagents.md.BHsSMMyO.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.e5qitjJt.lean.js → reference_subagents.md.BHsSMMyO.lean.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.BdCO2aHZ.js → reference_tools.md.BYzUTeVA.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.BdCO2aHZ.lean.js → reference_tools.md.BYzUTeVA.lean.js} +1 -1
- package/dist/docs/assets/{templates_agentic-owners.md.Da_AGDlH.js → templates_agentic-owners.md.9M575F5C.js} +1 -1
- package/dist/docs/assets/{templates_agentic-owners.md.Da_AGDlH.lean.js → templates_agentic-owners.md.9M575F5C.lean.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DqxocIGh.js → templates_pr-autofixer.md.ws0DDXDy.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DqxocIGh.lean.js → templates_pr-autofixer.md.ws0DDXDy.lean.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.Bhnvd8VE.js → templates_security-reviewer.md.KEFYXzfK.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.Bhnvd8VE.lean.js → templates_security-reviewer.md.KEFYXzfK.lean.js} +1 -1
- package/dist/docs/assets/templates_thermo-quality-review.md.VNJ_mohX.js +3 -0
- package/dist/docs/assets/templates_thermo-quality-review.md.VNJ_mohX.lean.js +1 -0
- package/dist/docs/assets/templates_thermo-review.md.Hi3zWOkP.js +3 -0
- package/dist/docs/assets/templates_thermo-review.md.Hi3zWOkP.lean.js +1 -0
- package/dist/docs/assets/{templates_triage.md.BdBWO9Ic.js → templates_triage.md.CVGe_FG6.js} +1 -1
- package/dist/docs/assets/{templates_triage.md.BdBWO9Ic.lean.js → templates_triage.md.CVGe_FG6.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.mnfFG2Em.js +1 -0
- package/dist/docs/assets/troubleshooting.md.mnfFG2Em.lean.js +1 -0
- package/dist/docs/building-with-agents.html +44 -48
- package/dist/docs/building-with-agents.md +94 -82
- package/dist/docs/deployment.html +59 -78
- package/dist/docs/deployment.md +117 -363
- package/dist/docs/evals.html +85 -224
- package/dist/docs/evals.md +146 -673
- package/dist/docs/guides/agent-to-agent.html +58 -42
- package/dist/docs/guides/agent-to-agent.md +112 -35
- package/dist/docs/guides/bitbucket.html +179 -44
- package/dist/docs/guides/bitbucket.md +249 -48
- package/dist/docs/guides/cloud-agents.html +46 -40
- package/dist/docs/guides/cloud-agents.md +119 -66
- package/dist/docs/guides/convert-automation.html +80 -49
- package/dist/docs/guides/convert-automation.md +156 -147
- package/dist/docs/guides/github.html +184 -92
- package/dist/docs/guides/github.md +260 -245
- package/dist/docs/guides/gitlab.html +184 -45
- package/dist/docs/guides/gitlab.md +249 -50
- package/dist/docs/guides/grokbot-agents.html +48 -41
- package/dist/docs/guides/grokbot-agents.md +99 -53
- package/dist/docs/guides/improve.html +48 -40
- package/dist/docs/guides/improve.md +111 -58
- package/dist/docs/guides/mcp-oauth.html +74 -52
- package/dist/docs/guides/mcp-oauth.md +111 -121
- package/dist/docs/guides/opentelemetry.html +63 -54
- package/dist/docs/guides/opentelemetry.md +96 -165
- package/dist/docs/guides/slack.html +83 -59
- package/dist/docs/guides/slack.md +157 -227
- package/dist/docs/guides/webhooks.html +97 -230
- package/dist/docs/guides/webhooks.md +154 -385
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +44 -38
- package/dist/docs/hillclimbing.md +101 -55
- package/dist/docs/index.html +38 -38
- package/dist/docs/index.md +2 -0
- package/dist/docs/llms-full.txt +3082 -3104
- package/dist/docs/llms.txt +21 -18
- package/dist/docs/quickstart.html +37 -37
- package/dist/docs/reference/agent-config.html +37 -37
- package/dist/docs/reference/artifacts.html +38 -38
- package/dist/docs/reference/channels.html +37 -37
- package/dist/docs/reference/cli.html +39 -37
- package/dist/docs/reference/cli.md +2 -0
- package/dist/docs/reference/connections.html +37 -37
- package/dist/docs/reference/evals.html +116 -0
- package/dist/docs/reference/evals.md +293 -0
- package/dist/docs/reference/extensions.html +80 -84
- package/dist/docs/reference/extensions.md +127 -199
- package/dist/docs/reference/hooks.html +39 -39
- package/dist/docs/reference/hooks.md +34 -34
- package/dist/docs/reference/http-api.html +37 -37
- package/dist/docs/reference/instructions.html +37 -37
- package/dist/docs/reference/playground.html +37 -37
- package/dist/docs/reference/project-layout.html +37 -37
- package/dist/docs/reference/prompt.html +37 -37
- package/dist/docs/reference/schedules.html +37 -37
- package/dist/docs/reference/sessions.html +37 -37
- package/dist/docs/reference/skills.html +37 -37
- package/dist/docs/reference/subagents.html +37 -37
- package/dist/docs/reference/tools.html +37 -37
- package/dist/docs/templates/agentic-owners.html +38 -38
- package/dist/docs/templates/pr-autofixer.html +37 -37
- package/dist/docs/templates/security-reviewer.html +38 -38
- package/dist/docs/templates/thermo-quality-review.html +62 -0
- package/dist/docs/templates/thermo-quality-review.md +75 -0
- package/dist/docs/templates/thermo-review.html +62 -0
- package/dist/docs/templates/thermo-review.md +74 -0
- package/dist/docs/templates/triage.html +37 -37
- package/dist/docs/troubleshooting.html +38 -38
- package/dist/docs/troubleshooting.md +97 -66
- package/dist/extensions/cursor-cloud-agents/skills/handoff.md +3 -7
- package/dist/extensions/improve/extension.d.ts +3 -1
- package/dist/extensions/improve/extension.d.ts.map +1 -1
- package/dist/extensions/improve/extension.js +4 -2
- package/dist/extensions/improve/skills/yourself.js +1 -1
- package/dist/filesystem.d.ts +46 -2
- package/dist/filesystem.d.ts.map +1 -1
- package/dist/filesystem.js +149 -102
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/cli-ax.d.ts +6 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +72 -14
- package/dist/internal/continuation-identity.d.ts.map +1 -1
- package/dist/internal/continuation-identity.js +1 -0
- package/dist/internal/cursor-agent-template.d.ts +1 -1
- package/dist/internal/cursor-agent-template.d.ts.map +1 -1
- package/dist/internal/cursor-agent-template.js +2 -0
- package/dist/internal/filesystem/tools.d.ts.map +1 -1
- package/dist/internal/filesystem/tools.js +2 -2
- package/dist/internal/filesystem/walk.d.ts +7 -4
- package/dist/internal/filesystem/walk.d.ts.map +1 -1
- package/dist/internal/filesystem/walk.js +34 -11
- package/dist/internal/hosted-admission-adapter.d.ts +3 -0
- package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.d.ts +17 -0
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +50 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +8 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +4 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +94 -39
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +11 -5
- package/dist/internal/skill-catalog.d.ts +28 -0
- package/dist/internal/skill-catalog.d.ts.map +1 -0
- package/dist/internal/skill-catalog.js +44 -0
- package/dist/playground/assets/index-B1c1LeIf.js +67 -0
- package/dist/playground/assets/index-CK2LX3iD.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +2 -0
- package/docs/building-with-agents.md +96 -84
- package/docs/deployment.md +118 -364
- package/docs/evals.md +147 -674
- package/docs/guides/agent-to-agent.md +113 -36
- package/docs/guides/bitbucket.md +250 -49
- package/docs/guides/cloud-agents.md +119 -67
- package/docs/guides/convert-automation.md +157 -148
- package/docs/guides/github.md +261 -246
- package/docs/guides/gitlab.md +250 -51
- package/docs/guides/grokbot-agents.md +100 -55
- package/docs/guides/improve.md +112 -59
- package/docs/guides/mcp-oauth.md +112 -122
- package/docs/guides/opentelemetry.md +97 -166
- package/docs/guides/slack.md +158 -228
- package/docs/guides/webhooks.md +155 -386
- package/docs/hillclimbing.md +102 -56
- package/docs/reference/cli.md +2 -0
- package/docs/reference/evals.md +298 -0
- package/docs/reference/extensions.md +128 -200
- package/docs/reference/hooks.md +34 -34
- package/docs/templates/thermo-quality-review.md +80 -0
- package/docs/templates/thermo-review.md +79 -0
- package/docs/troubleshooting.md +98 -67
- package/package.json +1 -1
- package/skills/github/SKILL.md +21 -13
- package/src/bin/agent-serve.ts +22 -0
- package/src/channels/github/github-channel.ts +29 -19
- package/src/channels/slack/agentic-delivery.ts +2 -0
- package/src/channels/slack/dispatch.ts +126 -4
- package/src/channels/slack/placeholder.ts +51 -0
- package/src/channels/slack/slack-channel.ts +9 -2
- package/src/extensions/cursor-cloud-agents/skills/handoff.md +3 -7
- package/src/extensions/improve/extension.ts +4 -2
- package/src/extensions/improve/skills/yourself.ts +1 -1
- package/src/filesystem.ts +168 -65
- package/src/index.ts +3 -0
- package/src/internal/cli-ax.ts +88 -15
- package/src/internal/continuation-identity.ts +1 -0
- package/src/internal/cursor-agent-template.ts +2 -0
- package/src/internal/filesystem/tools.ts +2 -0
- package/src/internal/filesystem/walk.ts +60 -15
- package/src/internal/hosted-admission-adapter.ts +3 -0
- package/src/internal/hosted-delivery-protocol.ts +78 -1
- package/src/internal/hosted-delivery.ts +8 -0
- package/src/internal/init-project.ts +4 -0
- package/src/internal/server.ts +104 -41
- package/src/internal/session-engine.ts +16 -4
- package/src/internal/skill-catalog.ts +69 -0
- package/src/types.ts +9 -0
- package/templates/thermo-quality-review/README.md +35 -0
- package/templates/thermo-quality-review/agent/agent.ts +8 -0
- package/templates/thermo-quality-review/agent/channels/github.ts +42 -0
- package/templates/thermo-quality-review/agent/instructions.md +43 -0
- package/templates/thermo-quality-review/agent/tools/post_findings.ts +70 -0
- package/templates/thermo-quality-review/evals/evals.config.ts +5 -0
- package/templates/thermo-quality-review/evals/review.eval.ts +62 -0
- package/templates/thermo-quality-review/package.json +18 -0
- package/templates/thermo-quality-review/tsconfig.json +12 -0
- package/templates/thermo-review/README.md +35 -0
- package/templates/thermo-review/agent/agent.ts +8 -0
- package/templates/thermo-review/agent/channels/github.ts +42 -0
- package/templates/thermo-review/agent/instructions.md +40 -0
- package/templates/thermo-review/agent/tools/post_findings.ts +70 -0
- package/templates/thermo-review/evals/evals.config.ts +5 -0
- package/templates/thermo-review/evals/review.eval.ts +53 -0
- package/templates/thermo-review/package.json +18 -0
- package/templates/thermo-review/tsconfig.json +12 -0
- package/dist/docs/assets/building-with-agents.md.CEGVXkmO.js +0 -13
- package/dist/docs/assets/building-with-agents.md.CEGVXkmO.lean.js +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DtXk1hy-.js +0 -1
- package/dist/docs/assets/chunks/channel.Bkv1N-gK.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CZDco1o8.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CZDco1o8.js +0 -1
- package/dist/docs/assets/chunks/clone.YSt_40_s.js +0 -1
- package/dist/docs/assets/chunks/framework.dypDpWZ3.js +0 -19
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.C4CLm481.js +0 -1
- package/dist/docs/assets/chunks/wardley-RL74JXVD.g5efOWmT.js +0 -162
- package/dist/docs/assets/deployment.md.Dm4Qo3hp.js +0 -51
- package/dist/docs/assets/deployment.md.Dm4Qo3hp.lean.js +0 -1
- package/dist/docs/assets/evals.md.BLDRt5LH.js +0 -211
- package/dist/docs/assets/evals.md.BLDRt5LH.lean.js +0 -1
- package/dist/docs/assets/guides_agent-to-agent.md.BI0xclmy.js +0 -14
- package/dist/docs/assets/guides_agent-to-agent.md.BI0xclmy.lean.js +0 -1
- package/dist/docs/assets/guides_bitbucket.md.CTpCl__f.js +0 -10
- package/dist/docs/assets/guides_bitbucket.md.CTpCl__f.lean.js +0 -1
- package/dist/docs/assets/guides_cloud-agents.md.lSE_l7lH.js +0 -9
- package/dist/docs/assets/guides_cloud-agents.md.lSE_l7lH.lean.js +0 -1
- package/dist/docs/assets/guides_convert-automation.md.Ck6Cr68A.js +0 -12
- package/dist/docs/assets/guides_convert-automation.md.Ck6Cr68A.lean.js +0 -1
- package/dist/docs/assets/guides_github.md.D6ER29dG.js +0 -64
- package/dist/docs/assets/guides_github.md.D6ER29dG.lean.js +0 -1
- package/dist/docs/assets/guides_gitlab.md.P-TjBnS5.js +0 -14
- package/dist/docs/assets/guides_gitlab.md.P-TjBnS5.lean.js +0 -1
- package/dist/docs/assets/guides_grokbot-agents.md.WBZIOvkz.js +0 -9
- package/dist/docs/assets/guides_grokbot-agents.md.WBZIOvkz.lean.js +0 -1
- package/dist/docs/assets/guides_improve.md.BKaDuKKK.js +0 -14
- package/dist/docs/assets/guides_improve.md.BKaDuKKK.lean.js +0 -1
- package/dist/docs/assets/guides_mcp-oauth.md.DMNMpXtO.js +0 -28
- package/dist/docs/assets/guides_mcp-oauth.md.DMNMpXtO.lean.js +0 -1
- package/dist/docs/assets/guides_opentelemetry.md._CRfDyzH.js +0 -26
- package/dist/docs/assets/guides_opentelemetry.md._CRfDyzH.lean.js +0 -1
- package/dist/docs/assets/guides_slack.md.DdT8rmsj.js +0 -46
- package/dist/docs/assets/guides_slack.md.DdT8rmsj.lean.js +0 -1
- package/dist/docs/assets/guides_webhooks.md.aQW10HRe.js +0 -225
- package/dist/docs/assets/guides_webhooks.md.aQW10HRe.lean.js +0 -1
- package/dist/docs/assets/hillclimbing.md.Dq4kkVIL.js +0 -1
- package/dist/docs/assets/hillclimbing.md.Dq4kkVIL.lean.js +0 -1
- package/dist/docs/assets/reference_extensions.md.wlFD3cUR.js +0 -62
- package/dist/docs/assets/reference_extensions.md.wlFD3cUR.lean.js +0 -1
- package/dist/docs/assets/troubleshooting.md.BcgNoYtJ.js +0 -1
- package/dist/docs/assets/troubleshooting.md.BcgNoYtJ.lean.js +0 -1
- package/dist/playground/assets/index-BLlKgZtI.css +0 -1
- package/dist/playground/assets/index-CDS5p9sR.js +0 -67
|
@@ -1,464 +1,233 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Webhook agents
|
|
2
2
|
|
|
3
|
-
A custom channel
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
mechanism. The [GitLab](/docs/guides/gitlab.md) and [Bitbucket](/docs/guides/bitbucket.md) packs
|
|
8
|
-
use it too. This page is the mechanism itself.
|
|
3
|
+
A custom channel turns an event from another system into an agent
|
|
4
|
+
conversation, then sends the result back to the system that started it.
|
|
5
|
+
Use one when the built-in [HTTP API](/docs/reference/http-api.md) does not
|
|
6
|
+
match the provider's payload, conversation key, or reply path.
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
Author `agent/channels/<id>.ts`. Its routes mount under
|
|
9
|
+
`/<slug>/v1/channels/<id>`.
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
default multi-agent layout). `POST /v1/session` starts a conversation,
|
|
14
|
-
`POST /v1/session/:id` follows up, and `GET /v1/session/:id/stream`
|
|
15
|
-
streams NDJSON events, plus sessions, approvals, and tool routes. See
|
|
16
|
-
the [HTTP API reference](/docs/reference/http-api.md).
|
|
11
|
+
## Receive a webhook and send the answer back
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## Define a channel
|
|
23
|
-
|
|
24
|
-
Author `agent/channels/<id>.ts` with `defineChannel`. The filename is
|
|
25
|
-
the channel id, and routes mount under `/v1/channels/<id>`:
|
|
13
|
+
When a ticket system sends a new message, this endpoint responds with
|
|
14
|
+
`202 Accepted` right away. The agent keeps working after the HTTP
|
|
15
|
+
request ends, and its completed answer appears as a comment on the
|
|
16
|
+
ticket.
|
|
26
17
|
|
|
27
18
|
```ts
|
|
19
|
+
// agent/channels/tickets.ts
|
|
28
20
|
import { defineChannel, POST } from "@cursor/july/channels";
|
|
29
21
|
import { z } from "zod";
|
|
22
|
+
import { postTicketComment } from "../lib/tickets.js";
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
type TicketState = {
|
|
25
|
+
ticketId: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default defineChannel<TicketState>({
|
|
29
|
+
state: { ticketId: "" },
|
|
32
30
|
routes: [
|
|
33
|
-
POST("/
|
|
34
|
-
description: "
|
|
31
|
+
POST("/ticket", {
|
|
32
|
+
description: "Answer a new ticket message",
|
|
35
33
|
bodySchema: z.object({
|
|
34
|
+
ticketId: z.string(),
|
|
36
35
|
message: z.string(),
|
|
37
|
-
thread: z.string().optional(),
|
|
38
36
|
}),
|
|
39
|
-
handler: async (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
handler: async (_request, { send, waitUntil, body }) => {
|
|
38
|
+
waitUntil(
|
|
39
|
+
send(body.message, {
|
|
40
|
+
state: { ticketId: body.ticketId },
|
|
41
|
+
title: `Ticket ${body.ticketId}`,
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
return Response.json({ accepted: true }, { status: 202 });
|
|
45
45
|
},
|
|
46
46
|
}),
|
|
47
47
|
],
|
|
48
48
|
events: {
|
|
49
|
-
"message.completed"(event, channel
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
async "message.completed"(event, channel) {
|
|
50
|
+
if (event.data.finishReason === "tool_call" || event.data.text === "") {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
await postTicketComment(channel.state.ticketId, event.data.text);
|
|
52
54
|
},
|
|
53
55
|
},
|
|
54
56
|
});
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
-d '{"message":"hello","thread":"ticket-42"}'
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Schemas are Zod, and required
|
|
59
|
+
`postTicketComment` is a small wrapper around the ticket provider's
|
|
60
|
+
SDK. Keeping that write in the event handler means the webhook request
|
|
61
|
+
does not stay open while the model works.
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
require a Zod `bodySchema`. Compile-time checks enforce this, so plain
|
|
67
|
-
JSON Schema objects won't type-check. Use `z.object({})` or
|
|
68
|
-
`z.unknown()` when a surface is intentionally open. The host validates
|
|
69
|
-
before your handler runs, handlers receive typed `args.body` and
|
|
70
|
-
`args.query`, and empty POST bodies are coerced to `{}` first.
|
|
63
|
+
## Keep one conversation per ticket
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
Without a conversation key, every delivery creates a new session. Add
|
|
66
|
+
the ticket ID as the `continuationToken` so the opening message and all
|
|
67
|
+
later comments resume the same conversation, while a different ticket
|
|
68
|
+
starts its own.
|
|
75
69
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
| `callTool(name, input, opts?)` | Run an authored server tool with no model turn ([Tools](/docs/reference/tools.md#call-a-tool-without-a-model-turn)) |
|
|
86
|
-
| `body`, `query`, `params` | Validated payloads and path params |
|
|
87
|
-
| `auth` | The `AuthContext` the route's auth chain resolved |
|
|
88
|
-
| `requestIp` | The TCP peer address |
|
|
89
|
-
| `host` | Shared host services: `host.mcp`, `host.github`, `host.slack`, `host.reminders` |
|
|
90
|
-
| `waitUntil(promise)` | Background work that outlives the response |
|
|
70
|
+
```ts
|
|
71
|
+
waitUntil(
|
|
72
|
+
send(body.message, {
|
|
73
|
+
continuationToken: `ticket:${body.ticketId}`,
|
|
74
|
+
state: { ticketId: body.ticketId },
|
|
75
|
+
title: `Ticket ${body.ticketId}`,
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
```
|
|
91
79
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
`channel.state`.
|
|
80
|
+
The channel owns this key. Callers only need to send the domain ID they
|
|
81
|
+
already know.
|
|
95
82
|
|
|
96
|
-
##
|
|
83
|
+
## Prepare evidence before the turn
|
|
97
84
|
|
|
98
|
-
Webhook
|
|
99
|
-
|
|
85
|
+
Webhook payloads often contain little more than an object ID. This
|
|
86
|
+
handler fetches the full ticket through a deterministic tool and writes
|
|
87
|
+
the result to `ticket.json`, so the model begins with a stable snapshot
|
|
88
|
+
instead of spending the turn looking for context.
|
|
100
89
|
|
|
101
90
|
```ts
|
|
102
|
-
handler: async (
|
|
91
|
+
handler: async (_request, { callTool, send, waitUntil, body }) => {
|
|
92
|
+
const prepared = await callTool("prepare_ticket", {
|
|
93
|
+
ticketId: body.ticketId,
|
|
94
|
+
});
|
|
95
|
+
if (prepared.isError) {
|
|
96
|
+
return Response.json(
|
|
97
|
+
{ error: prepared.errorMessage ?? "Could not prepare ticket" },
|
|
98
|
+
{ status: 502 }
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
103
102
|
waitUntil(
|
|
104
|
-
send(
|
|
105
|
-
continuationToken: `
|
|
103
|
+
send("Read ticket.json, then draft the reply.", {
|
|
104
|
+
continuationToken: `ticket:${body.ticketId}`,
|
|
105
|
+
state: { ticketId: body.ticketId },
|
|
106
|
+
workspaceFiles: {
|
|
107
|
+
"ticket.json": JSON.stringify(prepared.result, null, 2) ?? "null",
|
|
108
|
+
},
|
|
106
109
|
})
|
|
107
110
|
);
|
|
108
111
|
return Response.json({ accepted: true }, { status: 202 });
|
|
109
112
|
},
|
|
110
113
|
```
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
The same `message.completed` handler from the first example delivers
|
|
116
|
+
the answer back to the ticket.
|
|
113
117
|
|
|
114
|
-
|
|
115
|
-
handler, then hand the model prepared evidence. Fetch the PR with
|
|
116
|
-
`callTool`, seed the files it needs, and make the prompt about judgment
|
|
117
|
-
rather than about finding things:
|
|
118
|
+
## Routes receive, events deliver
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
const session = await send("Review the prepared PR under pr/.", {
|
|
126
|
-
continuationToken: `pr:${body.pr}`,
|
|
127
|
-
});
|
|
128
|
-
return Response.json({ sessionId: session.id });
|
|
129
|
-
},
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
This host-prep shape is the change with the largest effect on latency
|
|
133
|
-
and quality. [Hillclimbing](/docs/hillclimbing.md) lists it first.
|
|
134
|
-
|
|
135
|
-
## Deliver replies back out
|
|
136
|
-
|
|
137
|
-
The `events` map subscribes the channel to stream events for the
|
|
138
|
-
sessions it owns. Typical wiring: `message.completed` posts the
|
|
139
|
-
assistant text back to the caller's surface, and `turn.failed` posts an
|
|
140
|
-
error notice. The full vocabulary is in
|
|
141
|
-
[Sessions and streaming](/docs/reference/sessions.md#which-events-can-i-stream).
|
|
142
|
-
|
|
143
|
-
## Auth: loopback by default, on purpose
|
|
120
|
+
Routes own inbound HTTP. A route validates the request, decides whether
|
|
121
|
+
to start or resume a turn, and responds to the caller. The channel's
|
|
122
|
+
`events` handlers receive session events later, which is where you
|
|
123
|
+
deliver the model's answer or report a failure to the originating
|
|
124
|
+
system.
|
|
144
125
|
|
|
145
|
-
|
|
146
|
-
default is `[localDevStrict()]`: direct loopback callers only. Requests
|
|
147
|
-
carrying proxy-forwarding headers (`X-Forwarded-For`, `X-Real-IP`,
|
|
148
|
-
`Forwarded`, `X-Forwarded-Host`) are rejected, and a loopback `Host`
|
|
149
|
-
header is required. So a tunnel, a same-host reverse proxy, or a
|
|
150
|
-
DNS-rebinding page can't silently re-expose the route.
|
|
151
|
-
|
|
152
|
-
Before real traffic, author auth explicitly:
|
|
153
|
-
|
|
154
|
-
```ts
|
|
155
|
-
import { bearerAuth, defineChannel, localDevStrict } from "@cursor/july/channels";
|
|
156
|
-
|
|
157
|
-
export default defineChannel({
|
|
158
|
-
auth: [localDevStrict(), bearerAuth(process.env.WEBHOOK_TOKEN ?? "")],
|
|
159
|
-
routes: [/* … */],
|
|
160
|
-
});
|
|
161
|
-
```
|
|
126
|
+
## Validate payloads with Zod
|
|
162
127
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
`
|
|
166
|
-
|
|
128
|
+
`POST`, `PUT`, and `PATCH` routes require a Zod `bodySchema`; `GET`
|
|
129
|
+
requires a `querySchema`. Validation runs before the handler, and the
|
|
130
|
+
parsed value arrives as typed `body` or `query`. Use `z.unknown()` when
|
|
131
|
+
the provider controls a variable payload and your own parser will
|
|
132
|
+
narrow it.
|
|
167
133
|
|
|
168
|
-
The
|
|
169
|
-
|
|
134
|
+
The route description and schema also appear in `GET /v1/info`. The
|
|
135
|
+
playground uses them to add a **Try** action and a matching slash
|
|
136
|
+
command, so you can exercise the same handler without building a
|
|
137
|
+
separate test UI.
|
|
170
138
|
|
|
171
|
-
|
|
172
|
-
swaps the default for `bearerAuth` on every channel that doesn't author
|
|
173
|
-
its own chain, and `--allow-anonymous` swaps it for `allowAll()`
|
|
174
|
-
(trusted networks only). Authored `auth` arrays always win over both.
|
|
139
|
+
## Use handler context
|
|
175
140
|
|
|
176
|
-
|
|
141
|
+
The handler context keeps deterministic setup and model work in one
|
|
142
|
+
route:
|
|
177
143
|
|
|
178
|
-
|
|
179
|
-
normally send `X-Agent-Alias-Token` on every request. Webhook providers
|
|
180
|
-
often cannot set it.
|
|
144
|
+
- `send` starts or resumes the agent conversation.
|
|
181
145
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
routes stay private. See [Deployment](/docs/deployment.md#use-the-hosted-agent).
|
|
146
|
+
- `callTool` runs an authored server tool without starting a model
|
|
147
|
+
turn.
|
|
185
148
|
|
|
186
|
-
|
|
149
|
+
- `waitUntil` keeps background work alive after the HTTP response. Await
|
|
150
|
+
`send` when the caller needs the session handle, then call
|
|
151
|
+
`session.waitForCompletion()` if it also needs the turn outcome.
|
|
187
152
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
resume sessions, and replies land back on the issue as comments. The
|
|
191
|
-
same shape works for any tracker with signed webhooks.
|
|
153
|
+
- `host` provides authenticated services for API calls made by channel
|
|
154
|
+
code.
|
|
192
155
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
the signing secret. Linear requires a public HTTPS URL, so use a
|
|
196
|
-
tunnel during local development or test with signed fixtures (below).
|
|
197
|
-
Set three environment variables:
|
|
156
|
+
The full handler API lives in the
|
|
157
|
+
[Channels reference](/docs/reference/channels.md#handler-arguments).
|
|
198
158
|
|
|
199
|
-
|
|
200
|
-
LINEAR_WEBHOOK_SECRET=lin_wh_... # the webhook's signing secret
|
|
201
|
-
LINEAR_API_KEY=lin_api_... # posts replies as comments
|
|
202
|
-
LINEAR_AGENT_USER_ID=... # the API key's user: query { viewer { id } }
|
|
203
|
-
```
|
|
159
|
+
## Protect public webhooks
|
|
204
160
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
turn.
|
|
161
|
+
Custom routes accept direct loopback requests by default. They reject
|
|
162
|
+
forwarded requests, so a tunnel or reverse proxy does not silently turn
|
|
163
|
+
a local development endpoint into a public one.
|
|
209
164
|
|
|
210
|
-
|
|
165
|
+
Before accepting remote traffic, choose an explicit boundary.
|
|
166
|
+
`bearerAuth()` works when the sender can attach an authorization header.
|
|
167
|
+
On managed hosting, webhook providers often cannot attach the agent
|
|
168
|
+
alias token, so `publicEndpoint()` lets that custom channel bypass it.
|
|
169
|
+
That opens the route to every caller; verify the provider signature
|
|
170
|
+
before starting a turn or calling a tool.
|
|
211
171
|
|
|
212
172
|
```ts
|
|
213
|
-
import { Buffer } from "node:buffer";
|
|
214
|
-
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
215
173
|
import { defineChannel, POST, publicEndpoint } from "@cursor/july/channels";
|
|
216
174
|
import { z } from "zod";
|
|
217
|
-
|
|
218
|
-
const secret = process.env.LINEAR_WEBHOOK_SECRET ?? "";
|
|
219
|
-
const apiKey = process.env.LINEAR_API_KEY ?? "";
|
|
220
|
-
const agentUserId = process.env.LINEAR_AGENT_USER_ID ?? "";
|
|
221
|
-
|
|
222
|
-
interface LinearWebhook {
|
|
223
|
-
action: string;
|
|
224
|
-
type: string;
|
|
225
|
-
url?: string;
|
|
226
|
-
webhookTimestamp: number;
|
|
227
|
-
data: {
|
|
228
|
-
id: string;
|
|
229
|
-
title?: string;
|
|
230
|
-
description?: string;
|
|
231
|
-
body?: string;
|
|
232
|
-
issueId?: string;
|
|
233
|
-
userId?: string;
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Linear signs the raw body: hex HMAC-SHA256 in `Linear-Signature`.
|
|
238
|
-
function verified(rawBody: string, header: string | null): boolean {
|
|
239
|
-
if (secret === "" || header === null) {
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
const expected = createHmac("sha256", secret).update(rawBody).digest();
|
|
243
|
-
const received = Buffer.from(header, "hex");
|
|
244
|
-
return (
|
|
245
|
-
received.length === expected.length && timingSafeEqual(received, expected)
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
async function postComment(issueId: string, body: string): Promise<void> {
|
|
250
|
-
const response = await fetch("https://api.linear.app/graphql", {
|
|
251
|
-
method: "POST",
|
|
252
|
-
headers: { "content-type": "application/json", authorization: apiKey },
|
|
253
|
-
body: JSON.stringify({
|
|
254
|
-
query:
|
|
255
|
-
"mutation($input: CommentCreateInput!) { commentCreate(input: $input) { success } }",
|
|
256
|
-
variables: { input: { issueId, body } },
|
|
257
|
-
}),
|
|
258
|
-
});
|
|
259
|
-
if (!response.ok) {
|
|
260
|
-
throw new Error(`commentCreate failed: ${response.status}`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function issueIdFromToken(token: string | null): string | null {
|
|
265
|
-
if (token === null || !token.startsWith("linear:")) {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
return token.slice("linear:".length);
|
|
269
|
-
}
|
|
175
|
+
import { verifyProviderSignature } from "../lib/tickets.js";
|
|
270
176
|
|
|
271
177
|
export default defineChannel({
|
|
272
178
|
auth: [publicEndpoint()],
|
|
273
179
|
routes: [
|
|
274
180
|
POST("/", {
|
|
275
|
-
description: "
|
|
276
|
-
// The payload shape varies by `Linear-Event`; parse after verifying.
|
|
181
|
+
description: "Signed ticket webhook",
|
|
277
182
|
bodySchema: z.unknown(),
|
|
278
|
-
handler: async
|
|
183
|
+
handler: async request => {
|
|
279
184
|
const rawBody = await request.text();
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
const event = JSON.parse(rawBody) as LinearWebhook;
|
|
284
|
-
// Reject stale deliveries to guard against replay.
|
|
285
|
-
if (Math.abs(Date.now() - event.webhookTimestamp) > 60_000) {
|
|
185
|
+
const signature = request.headers.get("x-provider-signature");
|
|
186
|
+
if (!verifyProviderSignature(rawBody, signature)) {
|
|
286
187
|
return Response.json({ ok: false }, { status: 401 });
|
|
287
188
|
}
|
|
288
|
-
// Skip the agent's own comments so replies don't re-trigger it.
|
|
289
|
-
if (event.type === "Comment" && event.data.userId === agentUserId) {
|
|
290
|
-
return Response.json({ ok: true });
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// New issue → new session. New comment → follow-up on the same
|
|
294
|
-
// session, keyed by issue id through the continuation token.
|
|
295
|
-
let issueId: string | undefined;
|
|
296
|
-
let message: string | undefined;
|
|
297
|
-
if (event.type === "Issue" && event.action === "create") {
|
|
298
|
-
issueId = event.data.id;
|
|
299
|
-
message = `New Linear issue: ${event.data.title}\n\n${
|
|
300
|
-
event.data.description ?? ""
|
|
301
|
-
}\n${event.url ?? ""}`;
|
|
302
|
-
} else if (event.type === "Comment" && event.action === "create") {
|
|
303
|
-
issueId = event.data.issueId;
|
|
304
|
-
message = event.data.body;
|
|
305
|
-
}
|
|
306
|
-
if (issueId === undefined || message === undefined) {
|
|
307
|
-
return Response.json({ ok: true });
|
|
308
|
-
}
|
|
309
189
|
|
|
310
|
-
//
|
|
311
|
-
// seconds: ACK now, run the turn in the background.
|
|
312
|
-
waitUntil(send(message, { continuationToken: `linear:${issueId}` }));
|
|
190
|
+
// Parse and dispatch only after the signature passes.
|
|
313
191
|
return Response.json({ ok: true });
|
|
314
192
|
},
|
|
315
193
|
}),
|
|
316
194
|
],
|
|
317
|
-
events: {
|
|
318
|
-
async "message.completed"(event, channel) {
|
|
319
|
-
if (event.data.finishReason === "tool_call" || event.data.text === "") {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
const issueId = issueIdFromToken(channel.continuationToken);
|
|
323
|
-
if (issueId !== null) {
|
|
324
|
-
await postComment(issueId, event.data.text);
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
async "turn.failed"(event, channel) {
|
|
328
|
-
const issueId = issueIdFromToken(channel.continuationToken);
|
|
329
|
-
if (issueId !== null) {
|
|
330
|
-
await postComment(issueId, `Turn failed: ${event.data.message}`);
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
195
|
});
|
|
335
196
|
```
|
|
336
197
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
```ts
|
|
343
|
-
// agent/mcp-connections/linear.ts
|
|
344
|
-
import { defineConnection } from "@cursor/july/connections";
|
|
345
|
-
|
|
346
|
-
// Uses the signed-in Cursor account's Linear connector.
|
|
347
|
-
export default defineConnection({ cursorAccount: true, servers: ["Linear"] });
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
See [MCP connections](/docs/reference/connections.md) for the direct
|
|
351
|
-
`https://mcp.linear.app/mcp` form when the host isn't signed in to
|
|
352
|
-
Cursor.
|
|
353
|
-
|
|
354
|
-
### Production Linear agents: expiring OAuth tokens
|
|
198
|
+
`publicEndpoint()` only opens this channel's routes. The built-in
|
|
199
|
+
session and tool APIs stay private. See
|
|
200
|
+
[Auth policies](/docs/reference/channels.md#auth-policies) for bearer
|
|
201
|
+
tokens and the complete policy reference.
|
|
355
202
|
|
|
356
|
-
|
|
357
|
-
is an OAuth application: installing it in a workspace mints an access
|
|
358
|
-
token with an expiry plus a refresh token. The serve host can be
|
|
359
|
-
replaced at any time, so the pair can't live in process memory.
|
|
360
|
-
Persist it in `host.kv` instead.
|
|
361
|
-
Route handlers receive `host` in their args, and event handlers get the
|
|
362
|
-
same services on `ctx`.
|
|
203
|
+
## Test locally
|
|
363
204
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
deploy-time env vars fit them.
|
|
369
|
-
- Back kv with durable storage. On Cursor-managed hosting, use
|
|
370
|
-
`cursorHostedStorage` in `agent/storage.ts`. Without it, kv falls back
|
|
371
|
-
to local disk and a host replacement drops the tokens.
|
|
372
|
-
|
|
373
|
-
Save the pair when the install flow completes, then refresh on demand:
|
|
374
|
-
|
|
375
|
-
```ts
|
|
376
|
-
import type { HostKvApi } from "@cursor/july/kv";
|
|
377
|
-
|
|
378
|
-
interface LinearTokens {
|
|
379
|
-
accessToken: string;
|
|
380
|
-
refreshToken: string;
|
|
381
|
-
expiresAtMs: number;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const TOKENS_KEY = "linear/oauth-tokens";
|
|
385
|
-
|
|
386
|
-
export async function linearAccessToken(kv: HostKvApi): Promise<string> {
|
|
387
|
-
const tokens = (await kv.get(TOKENS_KEY)) as LinearTokens | undefined;
|
|
388
|
-
if (tokens === undefined) {
|
|
389
|
-
throw new Error("No Linear tokens stored. Complete the install flow first.");
|
|
390
|
-
}
|
|
391
|
-
if (Date.now() < tokens.expiresAtMs - 60_000) {
|
|
392
|
-
return tokens.accessToken;
|
|
393
|
-
}
|
|
394
|
-
const response = await fetch("https://api.linear.app/oauth/token", {
|
|
395
|
-
method: "POST",
|
|
396
|
-
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
397
|
-
body: new URLSearchParams({
|
|
398
|
-
grant_type: "refresh_token",
|
|
399
|
-
refresh_token: tokens.refreshToken,
|
|
400
|
-
client_id: process.env.LINEAR_CLIENT_ID ?? "",
|
|
401
|
-
client_secret: process.env.LINEAR_CLIENT_SECRET ?? "",
|
|
402
|
-
}),
|
|
403
|
-
});
|
|
404
|
-
if (!response.ok) {
|
|
405
|
-
throw new Error(`Linear token refresh failed: ${response.status}`);
|
|
406
|
-
}
|
|
407
|
-
const next = (await response.json()) as {
|
|
408
|
-
access_token: string;
|
|
409
|
-
refresh_token?: string;
|
|
410
|
-
expires_in: number;
|
|
411
|
-
};
|
|
412
|
-
const rotated: LinearTokens = {
|
|
413
|
-
accessToken: next.access_token,
|
|
414
|
-
refreshToken: next.refresh_token ?? tokens.refreshToken,
|
|
415
|
-
expiresAtMs: Date.now() + next.expires_in * 1000,
|
|
416
|
-
};
|
|
417
|
-
await kv.put(TOKENS_KEY, rotated);
|
|
418
|
-
return rotated.accessToken;
|
|
419
|
-
}
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
Then authorize GraphQL calls with `Bearer ${await
|
|
423
|
-
linearAccessToken(host.kv)}` in place of the static `apiKey` above.
|
|
424
|
-
Writes to `host.kv` await the durable sink and propagate errors, so a
|
|
425
|
-
failed save surfaces instead of silently losing the rotated refresh
|
|
426
|
-
token.
|
|
427
|
-
|
|
428
|
-
To test without a public URL, save a payload from the webhook's
|
|
429
|
-
delivery log (or the sample in
|
|
430
|
-
[Linear's webhook docs](https://linear.app/developers/webhooks)) under
|
|
431
|
-
`fixtures/`, refresh its `webhookTimestamp`, and sign it yourself:
|
|
205
|
+
Run the agent in development mode, then replay the same payload the
|
|
206
|
+
provider will send. The response should return immediately, and the
|
|
207
|
+
resulting session should appear in the playground while the reply is
|
|
208
|
+
delivered.
|
|
432
209
|
|
|
433
210
|
```bash
|
|
434
|
-
|
|
435
|
-
process.stdout.write(createHmac("sha256",process.env.LINEAR_WEBHOOK_SECRET)
|
|
436
|
-
.update(fs.readFileSync("fixtures/issue-create.json")).digest("hex"))')
|
|
437
|
-
curl -X POST http://127.0.0.1:3000/<slug>/v1/channels/linear/ \
|
|
438
|
-
-H 'content-type: application/json' -H "linear-signature: $SIG" \
|
|
439
|
-
--data-binary @fixtures/issue-create.json
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
## Test a channel
|
|
211
|
+
agent-sdk serve --dir . --dev
|
|
443
212
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
there. When something looks wrong, inspect the session event stream.
|
|
450
|
-
The stream is the record of what happened.
|
|
451
|
-
|
|
452
|
-
For GitHub specifically, don't hand-roll fixtures.
|
|
453
|
-
`agent-sdk github replay` synthesizes real-shaped, signed payloads
|
|
454
|
-
from any PR you can read. See the [GitHub guide](/docs/guides/github.md).
|
|
455
|
-
|
|
456
|
-
## What's next
|
|
457
|
-
|
|
458
|
-
Continue with these pages:
|
|
213
|
+
curl -sS -X POST \
|
|
214
|
+
http://127.0.0.1:3000/<slug>/v1/channels/tickets/ticket \
|
|
215
|
+
-H 'content-type: application/json' \
|
|
216
|
+
-d '{"ticketId":"ENG-142","message":"CSV export returns 500"}'
|
|
217
|
+
```
|
|
459
218
|
|
|
460
|
-
|
|
461
|
-
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
219
|
+
Keep representative payloads under `fixtures/` and pass them with
|
|
220
|
+
`--data-binary @fixtures/<event>.json`. You can also open the route's
|
|
221
|
+
**Try** action in the playground for manual probes.
|
|
222
|
+
|
|
223
|
+
## Related
|
|
224
|
+
|
|
225
|
+
- [Channels reference](/docs/reference/channels.md): route methods,
|
|
226
|
+
handler arguments, events, state, and auth policies
|
|
227
|
+
- [Triage Linear or Jira issues](/docs/templates/triage.md): a complete
|
|
228
|
+
signed tracker webhook with reply delivery
|
|
229
|
+
- [HTTP API](/docs/reference/http-api.md): built-in session, follow-up,
|
|
230
|
+
stream, and tool routes
|
|
231
|
+
- [Deployment](/docs/deployment.md#use-the-hosted-agent): stable hosted
|
|
232
|
+
URLs and alias-token behavior
|
|
233
|
+
- [Evals](/docs/evals.md): turn saved payloads into regression fixtures
|
package/dist/docs/hashmap.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"building-with-agents.md":"
|
|
1
|
+
{"building-with-agents.md":"BBCx0AUo","deployment.md":"D2jQZuFx","evals.md":"BYvfZ-PO","guides_agent-to-agent.md":"8oDTfu-E","guides_bitbucket.md":"mpevW-VP","guides_cloud-agents.md":"Cp1O3u-X","guides_convert-automation.md":"CqEyfP6Y","guides_github.md":"BwpBp3ed","guides_gitlab.md":"DaEC3nMk","guides_grokbot-agents.md":"CMhZNdEU","guides_improve.md":"Bnp4F99w","guides_mcp-oauth.md":"bSFakfCY","guides_opentelemetry.md":"BKDxQmmd","guides_slack.md":"Bo96y42E","guides_webhooks.md":"1A72_VEE","hillclimbing.md":"D4E1o5Sa","index.md":"C-t81M5J","quickstart.md":"DAvVhuuU","reference_agent-config.md":"DGPyw7ms","reference_artifacts.md":"Bu_4HmsD","reference_channels.md":"nFWbzAic","reference_cli.md":"DLWDz9ij","reference_connections.md":"CmyrlXfY","reference_evals.md":"DNJzM_yf","reference_extensions.md":"Ceq-qT8d","reference_hooks.md":"B7uzNENk","reference_http-api.md":"CduHavZ2","reference_instructions.md":"CU1My5My","reference_playground.md":"Ch2d0Iqi","reference_project-layout.md":"BGhgpy9V","reference_prompt.md":"Ccp0R53H","reference_schedules.md":"B2Nm6FaD","reference_sessions.md":"1_6Vyv7x","reference_skills.md":"DjQkRefx","reference_subagents.md":"BHsSMMyO","reference_tools.md":"BYzUTeVA","templates_agentic-owners.md":"9M575F5C","templates_pr-autofixer.md":"ws0DDXDy","templates_security-reviewer.md":"KEFYXzfK","templates_thermo-quality-review.md":"VNJ_mohX","templates_thermo-review.md":"Hi3zWOkP","templates_triage.md":"CVGe_FG6","troubleshooting.md":"mnfFG2Em"}
|