@cursor/july 0.1.90 → 0.1.91
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/AGENTS.md +8 -0
- package/README.md +8 -7
- package/dist/channels/slack/channel-watch.d.ts +1 -1
- package/dist/channels/slack/channel-watch.js +1 -1
- package/dist/channels/slack/slack-channel.js +1 -1
- package/dist/channels/slack/types.d.ts +2 -4
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +3 -3
- package/dist/docs/ab.html +7 -7
- package/dist/docs/assets/{ab.md.DYjwREAP.js → ab.md.CVzWxLoB.js} +1 -1
- package/dist/docs/assets/{ab.md.DYjwREAP.lean.js → ab.md.CVzWxLoB.lean.js} +1 -1
- package/dist/docs/assets/{app.wiNkt6G7.js → app.Bci6CM9E.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.PeZaZA1P.js → building-with-agents.md.DH8A_cHA.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.PeZaZA1P.lean.js → building-with-agents.md.DH8A_cHA.lean.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.Dv-Q0XtU.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.ByhUGu47.js → VPLocalSearchBox.BCPT6xA-.js} +1 -1
- package/dist/docs/assets/chunks/{framework.CAZyNGu9.js → framework.BCISBCiQ.js} +1 -1
- package/dist/docs/assets/chunks/theme.BEA8BF3c.js +2 -0
- package/dist/docs/assets/{concepts.md.2NfkGjqM.js → concepts.md.CRfU3bVg.js} +1 -1
- package/dist/docs/assets/{concepts.md.2NfkGjqM.lean.js → concepts.md.CRfU3bVg.lean.js} +1 -1
- package/dist/docs/assets/{deployment.md.B8kW-h7P.js → deployment.md.DX_hc3ze.js} +6 -5
- package/dist/docs/assets/{deployment.md.B8kW-h7P.lean.js → deployment.md.DX_hc3ze.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.CVe_O75-.js → evals.md.a0SMN6r9.js} +3 -3
- package/dist/docs/assets/{evals.md.CVe_O75-.lean.js → evals.md.a0SMN6r9.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_approval-buddy.md.CIiZ9coo.js → example-agents_approval-buddy.md.DNL83puR.js} +1 -1
- package/dist/docs/assets/{example-agents_approval-buddy.md.CIiZ9coo.lean.js → example-agents_approval-buddy.md.DNL83puR.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_benny.md.B-LIDGja.js → example-agents_benny.md.C40vHRLc.js} +1 -1
- package/dist/docs/assets/{example-agents_benny.md.B-LIDGja.lean.js → example-agents_benny.md.C40vHRLc.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_bugbot.md.Dp5JqHSQ.js → example-agents_bugbot.md.BRGMi9O2.js} +1 -1
- package/dist/docs/assets/{example-agents_bugbot.md.Dp5JqHSQ.lean.js → example-agents_bugbot.md.BRGMi9O2.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_codebase-wiki.md.D-lteFf0.js → example-agents_codebase-wiki.md.Dftj_tPp.js} +1 -1
- package/dist/docs/assets/{example-agents_codebase-wiki.md.D-lteFf0.lean.js → example-agents_codebase-wiki.md.Dftj_tPp.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_codeowners-review.md.BU2ZXLf-.js → example-agents_codeowners-review.md.Bfta-lBU.js} +1 -1
- package/dist/docs/assets/{example-agents_codeowners-review.md.BU2ZXLf-.lean.js → example-agents_codeowners-review.md.Bfta-lBU.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_concierge.md.DA2al_NK.js → example-agents_concierge.md.MrKpQndp.js} +1 -1
- package/dist/docs/assets/{example-agents_concierge.md.DA2al_NK.lean.js → example-agents_concierge.md.MrKpQndp.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_fsd.md.ZeGEpAw_.js → example-agents_fsd.md.ZWHWWZPE.js} +1 -1
- package/dist/docs/assets/{example-agents_fsd.md.ZeGEpAw_.lean.js → example-agents_fsd.md.ZWHWWZPE.lean.js} +1 -1
- package/dist/docs/assets/example-agents_index.md.QZ8mhr6n.js +2 -0
- package/dist/docs/assets/{example-agents_index.md.xmJ87d_3.lean.js → example-agents_index.md.QZ8mhr6n.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_knowledge-base.md.IneynQSR.js → example-agents_knowledge-base.md.DqKqHQ9u.js} +1 -1
- package/dist/docs/assets/{example-agents_knowledge-base.md.IneynQSR.lean.js → example-agents_knowledge-base.md.DqKqHQ9u.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_oncall.md.CBmyuAKc.js → example-agents_oncall.md.DK4XkYTd.js} +1 -1
- package/dist/docs/assets/{example-agents_oncall.md.CBmyuAKc.lean.js → example-agents_oncall.md.DK4XkYTd.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_security-reviewer.md.DBL1TwtP.js → example-agents_security-reviewer.md.Bai6D0Ee.js} +4 -4
- package/dist/docs/assets/{example-agents_security-reviewer.md.DBL1TwtP.lean.js → example-agents_security-reviewer.md.Bai6D0Ee.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_slack-agent.md.06jQXTAI.js → example-agents_slack-agent.md.D7Kdj5BV.js} +1 -1
- package/dist/docs/assets/{example-agents_slack-agent.md.06jQXTAI.lean.js → example-agents_slack-agent.md.D7Kdj5BV.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_weather-agent.md.DC3lINjo.js → example-agents_weather-agent.md.lVEAbWFf.js} +5 -5
- package/dist/docs/assets/example-agents_weather-agent.md.lVEAbWFf.lean.js +1 -0
- package/dist/docs/assets/{guides_agent-to-agent.md.Bmbxy-FA.js → guides_agent-to-agent.md.BCeVdJRJ.js} +1 -1
- package/dist/docs/assets/{guides_agent-to-agent.md.Bmbxy-FA.lean.js → guides_agent-to-agent.md.BCeVdJRJ.lean.js} +1 -1
- package/dist/docs/assets/{guides_cloud-runtime.md.CbklWfzh.js → guides_cloud-runtime.md.BSMLIBHr.js} +1 -1
- package/dist/docs/assets/{guides_cloud-runtime.md.CbklWfzh.lean.js → guides_cloud-runtime.md.BSMLIBHr.lean.js} +1 -1
- package/dist/docs/assets/{guides_convert-automation.md.BhMzTkE5.js → guides_convert-automation.md.D06eIzea.js} +1 -1
- package/dist/docs/assets/{guides_convert-automation.md.BhMzTkE5.lean.js → guides_convert-automation.md.D06eIzea.lean.js} +1 -1
- package/dist/docs/assets/{guides_github.md.CLLQJKRB.js → guides_github.md.Cdt1s2QC.js} +4 -4
- package/dist/docs/assets/{guides_github.md.CLLQJKRB.lean.js → guides_github.md.Cdt1s2QC.lean.js} +1 -1
- package/dist/docs/assets/{guides_human-in-the-loop.md.Cf8kIIqC.js → guides_human-in-the-loop.md.By1G2T3_.js} +1 -1
- package/dist/docs/assets/{guides_human-in-the-loop.md.Cf8kIIqC.lean.js → guides_human-in-the-loop.md.By1G2T3_.lean.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.CzEB6RaG.js → guides_mcp-oauth.md.Du0f7pGU.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.CzEB6RaG.lean.js → guides_mcp-oauth.md.Du0f7pGU.lean.js} +1 -1
- package/dist/docs/assets/{guides_opentelemetry.md.Csn7ZI25.js → guides_opentelemetry.md.bmPmkvJu.js} +1 -1
- package/dist/docs/assets/{guides_opentelemetry.md.Csn7ZI25.lean.js → guides_opentelemetry.md.bmPmkvJu.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.DP4H75WP.js → guides_slack.md.DiUmk_Oi.js} +5 -5
- package/dist/docs/assets/{guides_slack.md.DP4H75WP.lean.js → guides_slack.md.DiUmk_Oi.lean.js} +1 -1
- package/dist/docs/assets/{guides_webhooks.md.DB-r_er9.js → guides_webhooks.md.BpnIdO0i.js} +5 -6
- package/dist/docs/assets/{guides_webhooks.md.DB-r_er9.lean.js → guides_webhooks.md.BpnIdO0i.lean.js} +1 -1
- package/dist/docs/assets/{hillclimbing.md.yXqdlv2R.js → hillclimbing.md.ywF3yDAd.js} +1 -1
- package/dist/docs/assets/{hillclimbing.md.yXqdlv2R.lean.js → hillclimbing.md.ywF3yDAd.lean.js} +1 -1
- package/dist/docs/assets/index.md.BAaMXLFd.js +5 -0
- package/dist/docs/assets/{index.md.DhRHS_-L.lean.js → index.md.BAaMXLFd.lean.js} +1 -1
- package/dist/docs/assets/{quickstart.md.DZxBu44y.js → quickstart.md.DsrarzEg.js} +1 -1
- package/dist/docs/assets/{quickstart.md.DZxBu44y.lean.js → quickstart.md.DsrarzEg.lean.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.CTWp4DnU.js → reference_agent-config.md.Bqylgw50.js} +1 -1
- package/dist/docs/assets/{reference_agent-config.md.CTWp4DnU.lean.js → reference_agent-config.md.Bqylgw50.lean.js} +1 -1
- package/dist/docs/assets/{reference_artifacts.md.BGG4bZo-.js → reference_artifacts.md.Dior32Qw.js} +1 -1
- package/dist/docs/assets/{reference_artifacts.md.BGG4bZo-.lean.js → reference_artifacts.md.Dior32Qw.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.CboFd5IH.js → reference_channels.md.DQZjCnyh.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.CboFd5IH.lean.js → reference_channels.md.DQZjCnyh.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.TAaYU8br.js → reference_cli.md.B7GkAJRC.js} +8 -7
- package/dist/docs/assets/{reference_cli.md.TAaYU8br.lean.js → reference_cli.md.B7GkAJRC.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.Cu3N-S3Q.js → reference_connections.md.DYidrb-j.js} +5 -5
- package/dist/docs/assets/{reference_connections.md.Cu3N-S3Q.lean.js → reference_connections.md.DYidrb-j.lean.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.DJE5DXcT.js → reference_hooks.md.B9FSgdDe.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.DJE5DXcT.lean.js → reference_hooks.md.B9FSgdDe.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DMbdFGVQ.js → reference_http-api.md.CSHVobzG.js} +4 -4
- package/dist/docs/assets/{reference_http-api.md.DMbdFGVQ.lean.js → reference_http-api.md.CSHVobzG.lean.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.CgoV-YEb.js → reference_instructions.md.DhNCOl7r.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.CgoV-YEb.lean.js → reference_instructions.md.DhNCOl7r.lean.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.CPZhfYaO.js → reference_playground.md.Dfb92yQf.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.CPZhfYaO.lean.js → reference_playground.md.Dfb92yQf.lean.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.CueaKpjr.js → reference_project-layout.md.CwkSbEWT.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.CueaKpjr.lean.js → reference_project-layout.md.CwkSbEWT.lean.js} +1 -1
- package/dist/docs/assets/{reference_prompt.md.BaiweQxE.js → reference_prompt.md.DZUMtLPD.js} +1 -1
- package/dist/docs/assets/{reference_prompt.md.BaiweQxE.lean.js → reference_prompt.md.DZUMtLPD.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.gmfYzf_I.js → reference_schedules.md.DNipebiG.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.gmfYzf_I.lean.js → reference_schedules.md.DNipebiG.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.B0DdlM-K.js → reference_sessions.md.tUFzz98S.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.B0DdlM-K.lean.js → reference_sessions.md.tUFzz98S.lean.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.BRF2nDv9.js → reference_skills.md.B5ZEuHfG.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.BRF2nDv9.lean.js → reference_skills.md.B5ZEuHfG.lean.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.DSrGLIuB.js → reference_subagents.md.Xoav0AII.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.DSrGLIuB.lean.js → reference_subagents.md.Xoav0AII.lean.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.XmeFP_3d.js → reference_tools.md.wpaJtHn6.js} +2 -3
- package/dist/docs/assets/{reference_tools.md.XmeFP_3d.lean.js → reference_tools.md.wpaJtHn6.lean.js} +1 -1
- package/dist/docs/assets/{scaffolding-agents.md.BpMFXv2J.js → scaffolding-agents.md.CRDDUtYJ.js} +1 -1
- package/dist/docs/assets/{scaffolding-agents.md.BpMFXv2J.lean.js → scaffolding-agents.md.CRDDUtYJ.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.ks1u64_R.js → storage.md.JbjlHWZ6.js} +1 -1
- package/dist/docs/assets/{storage.md.ks1u64_R.lean.js → storage.md.JbjlHWZ6.lean.js} +1 -1
- package/dist/docs/assets/{style.kTsvp4pE.css → style.BRuM8477.css} +1 -1
- package/dist/docs/assets/{templates_agentic-owners.md.BkTLORaU.js → templates_agentic-owners.md.DSJSIpWU.js} +1 -1
- package/dist/docs/assets/{templates_agentic-owners.md.BkTLORaU.lean.js → templates_agentic-owners.md.DSJSIpWU.lean.js} +1 -1
- package/dist/docs/assets/{templates_demo.md.Bgd6MBaZ.js → templates_demo.md.DhFcWN6j.js} +1 -1
- package/dist/docs/assets/{templates_demo.md.Bgd6MBaZ.lean.js → templates_demo.md.DhFcWN6j.lean.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DcmoeUNZ.js → templates_pr-autofixer.md.1HAR3RXE.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DcmoeUNZ.lean.js → templates_pr-autofixer.md.1HAR3RXE.lean.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.C0yIUaYs.js → templates_security-reviewer.md.ByFyRta2.js} +1 -1
- package/dist/docs/assets/{templates_security-reviewer.md.C0yIUaYs.lean.js → templates_security-reviewer.md.ByFyRta2.lean.js} +1 -1
- package/dist/docs/assets/{templates_triage.md.DWuQ1bZz.js → templates_triage.md.CVlpctKS.js} +2 -2
- package/dist/docs/assets/{templates_triage.md.DWuQ1bZz.lean.js → templates_triage.md.CVlpctKS.lean.js} +1 -1
- package/dist/docs/assets/troubleshooting.md.DYECCZiJ.js +1 -0
- package/dist/docs/assets/{troubleshooting.md.KgmmaCgw.lean.js → troubleshooting.md.DYECCZiJ.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +7 -7
- package/dist/docs/concepts.html +7 -7
- package/dist/docs/deployment.html +11 -10
- package/dist/docs/evals.html +8 -8
- package/dist/docs/example-agents/approval-buddy.html +7 -7
- package/dist/docs/example-agents/benny.html +7 -7
- package/dist/docs/example-agents/bugbot.html +7 -7
- package/dist/docs/example-agents/codebase-wiki.html +7 -7
- package/dist/docs/example-agents/codeowners-review.html +7 -7
- package/dist/docs/example-agents/concierge.html +7 -7
- package/dist/docs/example-agents/fsd.html +7 -7
- package/dist/docs/example-agents/index.html +7 -7
- package/dist/docs/example-agents/knowledge-base.html +7 -7
- package/dist/docs/example-agents/oncall.html +7 -7
- package/dist/docs/example-agents/security-reviewer.html +10 -10
- package/dist/docs/example-agents/slack-agent.html +7 -7
- package/dist/docs/example-agents/weather-agent.html +12 -12
- package/dist/docs/guides/agent-to-agent.html +7 -7
- package/dist/docs/guides/cloud-runtime.html +7 -7
- package/dist/docs/guides/convert-automation.html +7 -7
- package/dist/docs/guides/github.html +9 -9
- package/dist/docs/guides/human-in-the-loop.html +7 -7
- package/dist/docs/guides/mcp-oauth.html +7 -7
- package/dist/docs/guides/opentelemetry.html +7 -7
- package/dist/docs/guides/slack.html +10 -10
- package/dist/docs/guides/webhooks.html +10 -11
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +7 -7
- package/dist/docs/index.html +8 -8
- package/dist/docs/quickstart.html +7 -7
- package/dist/docs/reference/agent-config.html +7 -7
- package/dist/docs/reference/artifacts.html +7 -7
- package/dist/docs/reference/channels.html +8 -8
- package/dist/docs/reference/cli.html +13 -12
- package/dist/docs/reference/connections.html +10 -10
- package/dist/docs/reference/hooks.html +7 -7
- package/dist/docs/reference/http-api.html +10 -10
- package/dist/docs/reference/instructions.html +7 -7
- package/dist/docs/reference/playground.html +7 -7
- package/dist/docs/reference/project-layout.html +7 -7
- package/dist/docs/reference/prompt.html +7 -7
- package/dist/docs/reference/schedules.html +7 -7
- package/dist/docs/reference/sessions.html +7 -7
- package/dist/docs/reference/skills.html +7 -7
- package/dist/docs/reference/subagents.html +7 -7
- package/dist/docs/reference/tools.html +8 -9
- package/dist/docs/scaffolding-agents.html +7 -7
- package/dist/docs/storage.html +7 -7
- package/dist/docs/templates/agentic-owners.html +7 -7
- package/dist/docs/templates/demo.html +7 -7
- package/dist/docs/templates/pr-autofixer.html +7 -7
- package/dist/docs/templates/security-reviewer.html +7 -7
- package/dist/docs/templates/triage.html +8 -8
- package/dist/docs/troubleshooting.html +7 -7
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +21 -3
- 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 +1 -0
- package/dist/internal/deploy-client.d.ts +18 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +25 -1
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +5 -1
- package/dist/internal/discovery.d.ts +5 -1
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +16 -0
- package/dist/internal/http-channel.d.ts +2 -2
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +11 -31
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +2 -0
- package/dist/internal/session-engine.d.ts +8 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +47 -5
- package/dist/playground/assets/index-D9N7-q97.css +1 -0
- package/dist/playground/assets/{index-DxapiDj_.js → index-DDvyC2z6.js} +49 -49
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +8 -5
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +3 -1
- package/docs/concepts.md +1 -1
- package/docs/deployment.md +9 -6
- package/docs/evals.md +1 -5
- package/docs/example-agents/codebase-wiki.md +2 -3
- package/docs/example-agents/fsd.md +1 -1
- package/docs/example-agents/index.md +2 -2
- package/docs/example-agents/knowledge-base.md +3 -3
- package/docs/example-agents/security-reviewer.md +17 -48
- package/docs/example-agents/weather-agent.md +14 -45
- package/docs/guides/github.md +7 -4
- package/docs/guides/slack.md +7 -2
- package/docs/guides/webhooks.md +12 -15
- package/docs/reference/channels.md +4 -0
- package/docs/reference/cli.md +21 -7
- package/docs/reference/connections.md +13 -32
- package/docs/reference/http-api.md +14 -9
- package/docs/reference/tools.md +1 -3
- package/docs/templates/triage.md +3 -5
- package/docs/troubleshooting.md +1 -1
- package/package.json +1 -1
- package/skills/create-agent/SKILL.md +6 -7
- package/skills/framework-map/SKILL.md +6 -6
- package/skills/setup-slack/SKILL.md +1 -1
- package/src/channels/slack/channel-watch.ts +1 -1
- package/src/channels/slack/slack-channel.ts +1 -1
- package/src/channels/slack/types.ts +2 -4
- package/src/internal/cli-deploy.ts +27 -7
- package/src/internal/cursor-agent-template.ts +1 -0
- package/src/internal/deploy-client.ts +40 -1
- package/src/internal/deploy-manifest.ts +10 -1
- package/src/internal/discovery.ts +20 -0
- package/src/internal/http-channel.ts +14 -41
- package/src/internal/init-project.ts +2 -0
- package/src/internal/session-engine.ts +58 -8
- package/src/types.ts +8 -5
- package/templates/security-help/README.md +37 -0
- package/templates/security-help/agent/agent.ts +18 -0
- package/templates/security-help/agent/channels/github.ts +13 -0
- package/templates/security-help/agent/channels/slack.ts +89 -0
- package/templates/security-help/agent/instructions.md +20 -0
- package/templates/security-help/agent/knowledge/faq/approvals.md +5 -0
- package/templates/security-help/agent/knowledge/faq/channels.md +6 -0
- package/templates/security-help/agent/knowledge/faq/phishing.md +10 -0
- package/templates/security-help/agent/lib/pr-first-pass.ts +42 -0
- package/templates/security-help/agent/lib/repos.ts +5 -0
- package/templates/security-help/agent/skills/access-request.md +10 -0
- package/templates/security-help/agent/skills/security-first-pass.md +15 -0
- package/templates/security-help/agent/skills/security-playbooks.md +12 -0
- package/templates/security-help/agent/skills/security-pr-first-pass.md +12 -0
- package/templates/security-help/evals/evals.config.ts +5 -0
- package/templates/security-help/evals/security-help.eval.ts +53 -0
- package/templates/security-help/init.json +31 -0
- package/templates/security-help/package.json +18 -0
- package/templates/security-help/tsconfig.json +12 -0
- package/templates/triage/agent/channels/webhook.ts +2 -2
- package/dist/docs/assets/chunks/@localSearchIndexroot.FV0R6kOb.js +0 -1
- package/dist/docs/assets/chunks/theme.Dx7j_-0n.js +0 -2
- package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +0 -2
- package/dist/docs/assets/example-agents_weather-agent.md.DC3lINjo.lean.js +0 -1
- package/dist/docs/assets/index.md.DhRHS_-L.js +0 -5
- package/dist/docs/assets/troubleshooting.md.KgmmaCgw.js +0 -1
- package/dist/playground/assets/index-BpVS-paP.css +0 -1
|
@@ -28,6 +28,7 @@ import { readDeployTemplate } from "./cursor-agent-template.js";
|
|
|
28
28
|
import {
|
|
29
29
|
type AgentkitDeployAccepted,
|
|
30
30
|
type AgentkitDeployStatus,
|
|
31
|
+
type AgentkitStopAccepted,
|
|
31
32
|
AgentServeDeployClient,
|
|
32
33
|
type DeleteAccepted,
|
|
33
34
|
type DeployAccepted,
|
|
@@ -1187,11 +1188,25 @@ export async function cmdStop(
|
|
|
1187
1188
|
if (typeof ctx === "number") {
|
|
1188
1189
|
return ctx;
|
|
1189
1190
|
}
|
|
1190
|
-
|
|
1191
|
+
// Stop takes only a slug, so there is no manifest to dispatch on (unlike
|
|
1192
|
+
// deploy). The v2 agentkit control plane goes first: v1 endpoints refuse
|
|
1193
|
+
// `architecture: "v2"` slugs with a 409 rather than a 404, so v1-first
|
|
1194
|
+
// could not fall through. A v2 404 (including an older backend without
|
|
1195
|
+
// the agentkit mount) falls back to the v1 stop.
|
|
1196
|
+
let architecture: "v1" | "v2" = "v2";
|
|
1197
|
+
let accepted: StopAccepted | AgentkitStopAccepted;
|
|
1191
1198
|
try {
|
|
1192
|
-
accepted = await ctx.client.
|
|
1199
|
+
accepted = await ctx.client.stopAgentkit({ teamId: ctx.teamId, slug });
|
|
1193
1200
|
} catch (error) {
|
|
1194
|
-
|
|
1201
|
+
if (!(error instanceof DeployApiError) || error.status !== 404) {
|
|
1202
|
+
return renderApiError(error, ctx.err);
|
|
1203
|
+
}
|
|
1204
|
+
try {
|
|
1205
|
+
accepted = await ctx.client.stopDeployment({ teamId: ctx.teamId, slug });
|
|
1206
|
+
architecture = "v1";
|
|
1207
|
+
} catch (v1Error) {
|
|
1208
|
+
return renderApiError(v1Error, ctx.err);
|
|
1209
|
+
}
|
|
1195
1210
|
}
|
|
1196
1211
|
if (ctx.noWait) {
|
|
1197
1212
|
if (ctx.json) {
|
|
@@ -1201,11 +1216,16 @@ export async function cmdStop(
|
|
|
1201
1216
|
}
|
|
1202
1217
|
return 0;
|
|
1203
1218
|
}
|
|
1204
|
-
let detail: DeploymentDetail;
|
|
1219
|
+
let detail: DeploymentDetail | AgentkitDeployStatus;
|
|
1205
1220
|
try {
|
|
1206
|
-
detail =
|
|
1207
|
-
|
|
1208
|
-
|
|
1221
|
+
detail =
|
|
1222
|
+
architecture === "v2"
|
|
1223
|
+
? await pollUntil(ctx, slug, new Set(["stopped"]), () =>
|
|
1224
|
+
ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug })
|
|
1225
|
+
)
|
|
1226
|
+
: await pollUntil(ctx, slug, new Set(["stopped"]), () =>
|
|
1227
|
+
ctx.client.getDeployment({ teamId: ctx.teamId, slug })
|
|
1228
|
+
);
|
|
1209
1229
|
} catch (error) {
|
|
1210
1230
|
return renderApiError(error, ctx.err);
|
|
1211
1231
|
}
|
|
@@ -255,6 +255,17 @@ export interface AgentkitDeployStatus {
|
|
|
255
255
|
export const TERMINAL_AGENTKIT_DEPLOY_STATUSES: ReadonlySet<AgentkitCustomerStatus> =
|
|
256
256
|
new Set(["running", "failed", "stopped"]);
|
|
257
257
|
|
|
258
|
+
/**
|
|
259
|
+
* `POST /internal/agentkit/deployments/:slug/stop` 202 body. Like v1
|
|
260
|
+
* {@link StopAccepted} but keyed by catalog ids instead of the numeric
|
|
261
|
+
* deployment row id.
|
|
262
|
+
*/
|
|
263
|
+
export interface AgentkitStopAccepted {
|
|
264
|
+
applicationId: string;
|
|
265
|
+
releaseId: string;
|
|
266
|
+
status: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
258
269
|
/** One secret's metadata from the list endpoint — names only, never values. */
|
|
259
270
|
export interface SecretInfo {
|
|
260
271
|
name: string;
|
|
@@ -332,6 +343,14 @@ const agentkitDeployStatusSchema = z
|
|
|
332
343
|
})
|
|
333
344
|
.passthrough();
|
|
334
345
|
|
|
346
|
+
const agentkitStopAcceptedSchema = z
|
|
347
|
+
.object({
|
|
348
|
+
applicationId: z.string().min(1),
|
|
349
|
+
releaseId: z.string().min(1),
|
|
350
|
+
status: z.string(),
|
|
351
|
+
})
|
|
352
|
+
.passthrough();
|
|
353
|
+
|
|
335
354
|
const deploymentSchema = z.object({
|
|
336
355
|
id: z.number(),
|
|
337
356
|
slug: z.string(),
|
|
@@ -602,6 +621,22 @@ export class AgentServeDeployClient {
|
|
|
602
621
|
return agentkitDeployStatusSchema.parse(raw);
|
|
603
622
|
}
|
|
604
623
|
|
|
624
|
+
/**
|
|
625
|
+
* Stop a v2 deployment (`POST /internal/agentkit/deployments/:slug/stop`).
|
|
626
|
+
* 202 means accepted; poll {@link getAgentkitDeploy} until `stopped`.
|
|
627
|
+
*/
|
|
628
|
+
async stopAgentkit(args: {
|
|
629
|
+
teamId: number;
|
|
630
|
+
slug: string;
|
|
631
|
+
}): Promise<AgentkitStopAccepted> {
|
|
632
|
+
const raw = await this.request({
|
|
633
|
+
method: "POST",
|
|
634
|
+
path: `/internal/agentkit/deployments/${encodeURIComponent(args.slug)}/stop?teamId=${args.teamId}`,
|
|
635
|
+
context: { verb: "stop", slug: args.slug },
|
|
636
|
+
});
|
|
637
|
+
return agentkitStopAcceptedSchema.parse(raw);
|
|
638
|
+
}
|
|
639
|
+
|
|
605
640
|
async listDeployments(args: { teamId: number }): Promise<Deployment[]> {
|
|
606
641
|
const raw = await this.request({
|
|
607
642
|
method: "GET",
|
|
@@ -888,8 +923,12 @@ function mapErrorResponse(
|
|
|
888
923
|
);
|
|
889
924
|
}
|
|
890
925
|
case 409:
|
|
926
|
+
// The server's 409 body distinguishes real conflicts (CAS races,
|
|
927
|
+
// "still deploying", architecture-v2 slugs on the v1 surface); keep
|
|
928
|
+
// its message when present.
|
|
891
929
|
return new DeployApiError(
|
|
892
|
-
|
|
930
|
+
serverError ??
|
|
931
|
+
`A concurrent deploy or stop is changing deployment${slugPart}; retry in a moment.`,
|
|
893
932
|
409
|
|
894
933
|
);
|
|
895
934
|
case 429: {
|
|
@@ -40,7 +40,10 @@ import {
|
|
|
40
40
|
handshakeChannelContinuation,
|
|
41
41
|
} from "./continuation-channel.js";
|
|
42
42
|
import { CONTINUATION_SELECTORS } from "./continuation-identity.js";
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
projectInfo,
|
|
45
|
+
runtimeArchitectureCompatibilityError,
|
|
46
|
+
} from "./discovery.js";
|
|
44
47
|
import { packageVersion } from "./distribution.js";
|
|
45
48
|
|
|
46
49
|
export const DEPLOY_MANIFEST_VERSION: 1 = 1;
|
|
@@ -125,6 +128,12 @@ export function buildAgentDeployManifest(
|
|
|
125
128
|
project: AgentProject,
|
|
126
129
|
options?: { nowMs?: number; cliVersion?: string }
|
|
127
130
|
): AgentDeployManifestV1 {
|
|
131
|
+
const runtimeArchitectureError = runtimeArchitectureCompatibilityError(
|
|
132
|
+
project.agent
|
|
133
|
+
);
|
|
134
|
+
if (runtimeArchitectureError !== undefined) {
|
|
135
|
+
throw new Error(runtimeArchitectureError);
|
|
136
|
+
}
|
|
128
137
|
applyAgentContinuationDefaults(project);
|
|
129
138
|
const channels = project.channels.map((channel) => {
|
|
130
139
|
const handshake = handshakeChannelContinuation(channel);
|
|
@@ -524,6 +524,17 @@ async function loadAgent(
|
|
|
524
524
|
const hosting = resolveHosting(ctx, agentDir, config?.hosting);
|
|
525
525
|
const concurrency = resolveConcurrency(ctx, agentDir, config?.concurrency);
|
|
526
526
|
const architecture = resolveArchitecture(ctx, agentDir, config?.architecture);
|
|
527
|
+
const runtimeArchitectureError = runtimeArchitectureCompatibilityError({
|
|
528
|
+
runtime,
|
|
529
|
+
architecture,
|
|
530
|
+
});
|
|
531
|
+
if (runtimeArchitectureError !== undefined) {
|
|
532
|
+
ctx.diagnostics.push({
|
|
533
|
+
severity: "error",
|
|
534
|
+
path: displayPath(ctx, join(agentDir, "agent.ts")),
|
|
535
|
+
message: runtimeArchitectureError,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
527
538
|
|
|
528
539
|
if (runtime === "cloud") {
|
|
529
540
|
warnCloudRuntimeLimitations(ctx, agentDir, {
|
|
@@ -570,6 +581,15 @@ async function loadAgent(
|
|
|
570
581
|
};
|
|
571
582
|
}
|
|
572
583
|
|
|
584
|
+
export function runtimeArchitectureCompatibilityError(agent: {
|
|
585
|
+
runtime: AgentRuntime;
|
|
586
|
+
architecture?: AgentArchitecture;
|
|
587
|
+
}): string | undefined {
|
|
588
|
+
return agent.architecture === "v2" && agent.runtime === "grokbot"
|
|
589
|
+
? 'architecture: "v2" cannot use runtime: "grokbot": the grokbot runtime executes through the signed-in account\'s hosted /v0/grokbot box, not a deployment-scoped v2 runtime.'
|
|
590
|
+
: undefined;
|
|
591
|
+
}
|
|
592
|
+
|
|
573
593
|
function resolveArchitecture(
|
|
574
594
|
ctx: DiscoveryContext,
|
|
575
595
|
agentDir: string,
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Continuation semantics: `POST /v1/session` returns a `continuationToken`;
|
|
8
8
|
* each accepted follow-up rotates it and returns the replacement, and a
|
|
9
9
|
* stale token is rejected with 409. Follow-ups address any chat session by
|
|
10
|
-
* id (including custom channels such as `drive`) when the token matches
|
|
11
|
-
*
|
|
10
|
+
* id (including custom channels such as `drive`) when the token matches its
|
|
11
|
+
* active HTTP follow-up key; task sessions stay fire-and-forget.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type {
|
|
@@ -20,11 +20,7 @@ import type {
|
|
|
20
20
|
SessionRecord,
|
|
21
21
|
} from "../types.js";
|
|
22
22
|
import { samePrincipal } from "./auth.js";
|
|
23
|
-
import {
|
|
24
|
-
formatContinuationToken,
|
|
25
|
-
newContinuationKey,
|
|
26
|
-
parseContinuationToken,
|
|
27
|
-
} from "./ids.js";
|
|
23
|
+
import { formatContinuationToken, parseContinuationToken } from "./ids.js";
|
|
28
24
|
import { isLoopbackAddress } from "./net.js";
|
|
29
25
|
import type { ServerRoute } from "./router.js";
|
|
30
26
|
import {
|
|
@@ -32,7 +28,6 @@ import {
|
|
|
32
28
|
ApprovalNotFoundError,
|
|
33
29
|
HTTP_CHANNEL_ID,
|
|
34
30
|
SessionAuthError,
|
|
35
|
-
SessionBusyError,
|
|
36
31
|
type SessionEngine,
|
|
37
32
|
} from "./session-engine.js";
|
|
38
33
|
import {
|
|
@@ -143,10 +138,8 @@ export function buildHttpChannelRoutes(args: {
|
|
|
143
138
|
`Unknown session ${sessionId}.`
|
|
144
139
|
);
|
|
145
140
|
}
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
// session's own continuation token. Task/schedule sessions stay
|
|
149
|
-
// fire-and-forget.
|
|
141
|
+
// HTTP can follow any chat session. Its credential is separate from the
|
|
142
|
+
// owning channel's continuation key.
|
|
150
143
|
if (record.mode === "task") {
|
|
151
144
|
return errorResponse(
|
|
152
145
|
409,
|
|
@@ -178,12 +171,7 @@ export function buildHttpChannelRoutes(args: {
|
|
|
178
171
|
);
|
|
179
172
|
}
|
|
180
173
|
const presented = parseContinuationToken(body.continuationToken);
|
|
181
|
-
if (
|
|
182
|
-
presented === null ||
|
|
183
|
-
presented.channelId !== record.channelId ||
|
|
184
|
-
record.continuationKey === null ||
|
|
185
|
-
presented.key !== record.continuationKey
|
|
186
|
-
) {
|
|
174
|
+
if (presented === null) {
|
|
187
175
|
return errorResponse(
|
|
188
176
|
409,
|
|
189
177
|
"stale_continuation_token",
|
|
@@ -192,34 +180,19 @@ export function buildHttpChannelRoutes(args: {
|
|
|
192
180
|
}
|
|
193
181
|
|
|
194
182
|
const message = await transformMessage(body.message, ctx.auth);
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
});
|
|
203
|
-
} catch (error) {
|
|
204
|
-
if (error instanceof SessionBusyError) {
|
|
205
|
-
return errorResponse(
|
|
206
|
-
409,
|
|
207
|
-
"session_busy",
|
|
208
|
-
"A turn is already running; wait for session.waiting before sending a follow-up."
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
throw error;
|
|
183
|
+
const rotated = await engine.followUpHttp(sessionId, presented, message);
|
|
184
|
+
if (rotated === undefined) {
|
|
185
|
+
return errorResponse(
|
|
186
|
+
409,
|
|
187
|
+
"stale_continuation_token",
|
|
188
|
+
"The continuation token does not address this session's active continuation."
|
|
189
|
+
);
|
|
212
190
|
}
|
|
213
|
-
|
|
214
|
-
// Rotate only after the message is accepted so a rejected send leaves
|
|
215
|
-
// the caller's token valid for retry.
|
|
216
|
-
const rotated = newContinuationKey();
|
|
217
|
-
await engine.setContinuationToken(sessionId, rotated);
|
|
218
191
|
return jsonResponse(
|
|
219
192
|
{
|
|
220
193
|
ok: true,
|
|
221
194
|
sessionId,
|
|
222
|
-
continuationToken: formatContinuationToken(
|
|
195
|
+
continuationToken: formatContinuationToken(HTTP_CHANNEL_ID, rotated),
|
|
223
196
|
},
|
|
224
197
|
{ headers: { [SESSION_ID_HEADER]: sessionId } }
|
|
225
198
|
);
|
|
@@ -76,6 +76,7 @@ const TEMPLATES: Readonly<Record<TemplateName, TemplateEntry>> = {
|
|
|
76
76
|
"agentic-owners": { dir: "agentic-owners" },
|
|
77
77
|
demo: { dir: "demo" },
|
|
78
78
|
"pr-autofixer": { dir: "pr-autofixer" },
|
|
79
|
+
"security-help": { dir: "security-help" },
|
|
79
80
|
"security-reviewer": { dir: "security-reviewer" },
|
|
80
81
|
"triage-linear": { dir: "triage", overlay: "linear" },
|
|
81
82
|
"triage-jira": { dir: "triage", overlay: "jira" },
|
|
@@ -709,6 +710,7 @@ Scaffold a project, then open the playground:
|
|
|
709
710
|
npx ${PACKAGE_NAME} init ./my-agent # installs deps + links agent-sdk onto PATH
|
|
710
711
|
npx ${PACKAGE_NAME} init ./my-demo --template demo # record a PR walkthrough
|
|
711
712
|
npx ${PACKAGE_NAME} init ./my-reviewer --template security-reviewer # review PRs for security bugs
|
|
713
|
+
npx ${PACKAGE_NAME} init ./security-help --template security-help # answer security questions in Slack
|
|
712
714
|
npx ${PACKAGE_NAME} init ./my-triage --template triage-linear # comment on Linear issues
|
|
713
715
|
npx ${PACKAGE_NAME} init ./my-triage --template triage-jira # comment on Jira issues
|
|
714
716
|
npx ${PACKAGE_NAME} init ./my-owners --template agentic-owners # review PRs via owners policies
|
|
@@ -925,6 +925,51 @@ export class SessionEngine {
|
|
|
925
925
|
return this.channelSession(record.sessionId, record, true, false, since);
|
|
926
926
|
}
|
|
927
927
|
|
|
928
|
+
/**
|
|
929
|
+
* Atomically validate and rotate an HTTP follow-up credential, then admit
|
|
930
|
+
* the message to its exact session without changing the owning channel key.
|
|
931
|
+
*/
|
|
932
|
+
async followUpHttp(
|
|
933
|
+
sessionId: string,
|
|
934
|
+
token: { channelId: string; key: string },
|
|
935
|
+
message: string
|
|
936
|
+
): Promise<string | undefined> {
|
|
937
|
+
const next = newContinuationKey();
|
|
938
|
+
const stale = new Error("stale HTTP continuation");
|
|
939
|
+
let previous: string | undefined;
|
|
940
|
+
try {
|
|
941
|
+
await this.updateRecord(sessionId, (record) => {
|
|
942
|
+
const expectedChannel =
|
|
943
|
+
record.httpContinuationKey === undefined
|
|
944
|
+
? record.channelId
|
|
945
|
+
: HTTP_CHANNEL_ID;
|
|
946
|
+
const expectedKey =
|
|
947
|
+
record.httpContinuationKey ?? record.continuationKey;
|
|
948
|
+
if (token.channelId !== expectedChannel || token.key !== expectedKey) {
|
|
949
|
+
throw stale;
|
|
950
|
+
}
|
|
951
|
+
previous = record.httpContinuationKey;
|
|
952
|
+
return { ...record, httpContinuationKey: next };
|
|
953
|
+
});
|
|
954
|
+
} catch (error) {
|
|
955
|
+
if (error === stale) {
|
|
956
|
+
return undefined;
|
|
957
|
+
}
|
|
958
|
+
throw error;
|
|
959
|
+
}
|
|
960
|
+
try {
|
|
961
|
+
await this.startTurn(sessionId, message);
|
|
962
|
+
return next;
|
|
963
|
+
} catch (error) {
|
|
964
|
+
await this.updateRecord(sessionId, (record) =>
|
|
965
|
+
record.httpContinuationKey === next
|
|
966
|
+
? { ...record, httpContinuationKey: previous }
|
|
967
|
+
: record
|
|
968
|
+
);
|
|
969
|
+
throw error;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
928
973
|
/** Whether a continuation token already maps to a session on this channel. */
|
|
929
974
|
async hasContinuationSession(
|
|
930
975
|
channelId: string,
|
|
@@ -3315,12 +3360,17 @@ export class SessionEngine {
|
|
|
3315
3360
|
createdAt: record.createdAt,
|
|
3316
3361
|
updatedAt: record.updatedAt,
|
|
3317
3362
|
continuationToken:
|
|
3318
|
-
record.
|
|
3319
|
-
?
|
|
3320
|
-
|
|
3321
|
-
record.
|
|
3322
|
-
|
|
3323
|
-
|
|
3363
|
+
record.httpContinuationKey !== undefined
|
|
3364
|
+
? formatContinuationToken(
|
|
3365
|
+
HTTP_CHANNEL_ID,
|
|
3366
|
+
record.httpContinuationKey
|
|
3367
|
+
)
|
|
3368
|
+
: record.continuationKey === null
|
|
3369
|
+
? null
|
|
3370
|
+
: formatContinuationToken(
|
|
3371
|
+
record.channelId,
|
|
3372
|
+
record.continuationKey
|
|
3373
|
+
),
|
|
3324
3374
|
externalUrl: links.slack ?? links.github,
|
|
3325
3375
|
prUrl: links.github,
|
|
3326
3376
|
};
|
|
@@ -3606,8 +3656,8 @@ export class SessionEngine {
|
|
|
3606
3656
|
...current,
|
|
3607
3657
|
continuationKey: token,
|
|
3608
3658
|
}));
|
|
3609
|
-
// Keep armed reminders addressed at the conversation across
|
|
3610
|
-
//
|
|
3659
|
+
// Keep armed reminders addressed at the conversation across channel
|
|
3660
|
+
// continuation rotation.
|
|
3611
3661
|
if (
|
|
3612
3662
|
previous?.continuationKey != null &&
|
|
3613
3663
|
token !== null &&
|
package/src/types.ts
CHANGED
|
@@ -1201,10 +1201,8 @@ export type ConnectionConfig = (
|
|
|
1201
1201
|
*
|
|
1202
1202
|
* Derive the identity from durable session facts — `session.auth`,
|
|
1203
1203
|
* `session.id`, or your channel's own session state. Do **not** key it
|
|
1204
|
-
* off `session.continuationKey`:
|
|
1205
|
-
*
|
|
1206
|
-
* keyed on it silently breaks mid-conversation. (Channels that mint
|
|
1207
|
-
* stable, parseable tokens by design are the exception.)
|
|
1204
|
+
* off `session.continuationKey`: it is a channel routing key, and channels
|
|
1205
|
+
* may re-key it independently of the authenticated principal.
|
|
1208
1206
|
*
|
|
1209
1207
|
* Works attached or advertised. Advertised connections
|
|
1210
1208
|
* ({@link advertiseTools}) open per-operation clients with the
|
|
@@ -1593,6 +1591,11 @@ export interface SessionRecord {
|
|
|
1593
1591
|
abs?: Record<string, string | null>;
|
|
1594
1592
|
/** Channel-local continuation key; null when the session is not addressable. */
|
|
1595
1593
|
continuationKey: string | null;
|
|
1594
|
+
/**
|
|
1595
|
+
* Rotating HTTP follow-up credential for a channel-owned session.
|
|
1596
|
+
* Omitted until HTTP accepts the first follow-up.
|
|
1597
|
+
*/
|
|
1598
|
+
httpContinuationKey?: string;
|
|
1596
1599
|
auth: AuthContext | null;
|
|
1597
1600
|
title?: string;
|
|
1598
1601
|
channelState?: JsonValue;
|
|
@@ -1668,7 +1671,7 @@ export interface SessionSummary {
|
|
|
1668
1671
|
queued?: boolean;
|
|
1669
1672
|
createdAt: string;
|
|
1670
1673
|
updatedAt: string;
|
|
1671
|
-
/**
|
|
1674
|
+
/** Active wire token for HTTP follow-ups, or null when not addressable. */
|
|
1672
1675
|
continuationToken: string | null;
|
|
1673
1676
|
/**
|
|
1674
1677
|
* Conversation permalink (Slack thread, else GitHub PR).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Security help
|
|
2
|
+
|
|
3
|
+
Answers security questions in Slack from your FAQ files and takes a first
|
|
4
|
+
look when someone pastes a GitHub pull request.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx @cursor/july init ./security-help --template security-help
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`init` asks which repos it may read. Skip the prompt with
|
|
11
|
+
`--var repos=owner/repo`.
|
|
12
|
+
|
|
13
|
+
## Run
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
agent-sdk login
|
|
17
|
+
agent-sdk slack create --name "Security Help" --channel-posts
|
|
18
|
+
agent-sdk dev
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Slack is a dedicated bot (`@Security Help`). Mentions, DMs, and channel
|
|
22
|
+
watch go through that app. GitHub reads use your Cursor GitHub connection
|
|
23
|
+
for the repos in `agent/lib/repos.ts`. Paste a PR URL in Slack, or replay
|
|
24
|
+
one in the playground.
|
|
25
|
+
|
|
26
|
+
## Edit
|
|
27
|
+
|
|
28
|
+
- `agent/lib/repos.ts`: repos it may read
|
|
29
|
+
- `agent/channels/slack.ts`: channel ids to watch (`watch`)
|
|
30
|
+
- `agent/knowledge/faq/`: answers for your company
|
|
31
|
+
- `agent/skills/`: how to look at a PR, a leak, or an access ask
|
|
32
|
+
- `agent/instructions.md`: routing
|
|
33
|
+
|
|
34
|
+
`--channel-posts` is required to watch channels. Mentions and DMs work
|
|
35
|
+
without it.
|
|
36
|
+
|
|
37
|
+
`agent-sdk eval` runs three smoke turns and writes nothing to Slack or GitHub.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineAgent } from "@cursor/july";
|
|
2
|
+
|
|
3
|
+
export default defineAgent({
|
|
4
|
+
name: "Security Help",
|
|
5
|
+
description:
|
|
6
|
+
"Answers security questions in Slack and takes a first look at a GitHub pull request.",
|
|
7
|
+
model: {
|
|
8
|
+
id: "grok-4.6",
|
|
9
|
+
params: [
|
|
10
|
+
{ id: "effort", value: "high" },
|
|
11
|
+
{ id: "fast", value: "true" },
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
tools: ["read", "grep"],
|
|
15
|
+
local: {
|
|
16
|
+
sandbox: true,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { githubChannel } from "@cursor/july/channels/github";
|
|
2
|
+
import { REPOS } from "../lib/repos.js";
|
|
3
|
+
|
|
4
|
+
export default githubChannel({
|
|
5
|
+
webhookEvents: [],
|
|
6
|
+
deliverReplies: false,
|
|
7
|
+
cursorAccount: {
|
|
8
|
+
repos: REPOS,
|
|
9
|
+
permissions: "read",
|
|
10
|
+
},
|
|
11
|
+
onPullRequest: () => null,
|
|
12
|
+
onComment: () => null,
|
|
13
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultSlackAuth,
|
|
3
|
+
extractGithubPrRef,
|
|
4
|
+
type SlackMessageHandler,
|
|
5
|
+
slackChannel,
|
|
6
|
+
} from "@cursor/july/channels/slack";
|
|
7
|
+
import { loadPrFiles } from "../lib/pr-first-pass.js";
|
|
8
|
+
import { REPOS, watches } from "../lib/repos.js";
|
|
9
|
+
|
|
10
|
+
const watch: string[] = [];
|
|
11
|
+
|
|
12
|
+
const clear = {
|
|
13
|
+
"pr/meta.md": "",
|
|
14
|
+
"pr/diff.patch": "",
|
|
15
|
+
"pr/head.sha": "",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const handleSlack: SlackMessageHandler = async (ctx, message) => {
|
|
19
|
+
const auth = defaultSlackAuth(message, ctx);
|
|
20
|
+
if (auth === null) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const pr = extractGithubPrRef(message.markdown);
|
|
25
|
+
if (pr === undefined) {
|
|
26
|
+
return { auth };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const title = `Security Help ${pr.label}`;
|
|
30
|
+
const fullName = `${pr.owner}/${pr.repo}`;
|
|
31
|
+
if (!watches(fullName)) {
|
|
32
|
+
return {
|
|
33
|
+
auth,
|
|
34
|
+
title,
|
|
35
|
+
workspaceFiles: clear,
|
|
36
|
+
context: [
|
|
37
|
+
`Security help can only fetch ${REPOS.join(", ")} (got ${fullName}).`,
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const loaded = await loadPrFiles({
|
|
43
|
+
github: ctx.host.github,
|
|
44
|
+
ref: pr,
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
auth,
|
|
48
|
+
title,
|
|
49
|
+
workspaceFiles: loaded ?? clear,
|
|
50
|
+
context:
|
|
51
|
+
loaded === undefined
|
|
52
|
+
? ["Could not fetch the pull request. Connect GitHub or check the URL."]
|
|
53
|
+
: undefined,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default slackChannel({
|
|
58
|
+
envPrefix: "SECURITY_HELP",
|
|
59
|
+
policy: {
|
|
60
|
+
blockExternals: true,
|
|
61
|
+
},
|
|
62
|
+
engagement: {
|
|
63
|
+
channelPosts:
|
|
64
|
+
watch.length === 0
|
|
65
|
+
? undefined
|
|
66
|
+
: {
|
|
67
|
+
allow: watch,
|
|
68
|
+
posts: "top-level" as const,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
onAppMention: handleSlack,
|
|
72
|
+
onDirectMessage: handleSlack,
|
|
73
|
+
onChannelPost: watch.length === 0 ? undefined : handleSlack,
|
|
74
|
+
suggestedPrompts: [
|
|
75
|
+
{
|
|
76
|
+
title: "Look at a PR",
|
|
77
|
+
message: "First look at https://github.com/owner/repo/pull/1",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
title: "How urgent",
|
|
81
|
+
message: "How urgent is this?",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
title: "Ask for context",
|
|
85
|
+
message: "What else do we need before answering?",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
suggestedPromptsTitle: "Ask security",
|
|
89
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Security help
|
|
2
|
+
|
|
3
|
+
Answer security questions in Slack from the FAQ and skills.
|
|
4
|
+
If you do not know, say so and ask a human.
|
|
5
|
+
|
|
6
|
+
Open the skill or FAQ for the ask. Those files are under `agent/skills/` and `agent/knowledge/faq/`.
|
|
7
|
+
|
|
8
|
+
| If the ask is about | Open |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| A GitHub pull request | `agent/skills/security-pr-first-pass.md` |
|
|
11
|
+
| An access request | `agent/skills/access-request.md` |
|
|
12
|
+
| A leak, alert, or incident | `agent/skills/security-playbooks.md` |
|
|
13
|
+
| Who can approve, privacy, or policy | `agent/knowledge/faq/approvals.md` |
|
|
14
|
+
| Phishing text, email, or a call | `agent/knowledge/faq/phishing.md` |
|
|
15
|
+
| Which team or channel owns a request | `agent/knowledge/faq/channels.md` |
|
|
16
|
+
| Another security question | `agent/skills/security-first-pass.md` |
|
|
17
|
+
|
|
18
|
+
A pull request earlier in the thread is not this one.
|
|
19
|
+
|
|
20
|
+
If you say an incident is over or a system is safe, show why. Looking at a pull request is not that.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Phishing
|
|
2
|
+
|
|
3
|
+
`#security` is where phishing and unexpected texts, emails, or calls go.
|
|
4
|
+
If the thread is already about that, keep it there.
|
|
5
|
+
|
|
6
|
+
Leave the original message alone. Do not reply, click, or send a 2FA code on it.
|
|
7
|
+
Confirm unknown texts or calls over Slack or in person before acting.
|
|
8
|
+
|
|
9
|
+
If an account looks compromised, they should lock it now and wait for a human.
|
|
10
|
+
If security already gave a verdict in-thread, follow that.
|