@cursor/july 0.1.96 → 0.1.99
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 +1 -1
- package/README.md +3 -2
- package/dist/bin/agent-serve.js +13 -3
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +16 -0
- package/dist/channels/origin/api.d.ts +15 -4
- package/dist/channels/origin/api.d.ts.map +1 -1
- package/dist/channels/origin/api.js +19 -3
- package/dist/channels/origin/binding.d.ts +11 -0
- package/dist/channels/origin/binding.d.ts.map +1 -1
- package/dist/channels/origin/binding.js +41 -25
- package/dist/channels/origin/index.d.ts +1 -0
- package/dist/channels/origin/index.d.ts.map +1 -1
- package/dist/channels/origin/index.js +1 -0
- package/dist/channels/origin/origin-channel.d.ts +2 -0
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +40 -4
- package/dist/channels/origin/reactions.d.ts +56 -0
- package/dist/channels/origin/reactions.d.ts.map +1 -0
- package/dist/channels/origin/reactions.js +67 -0
- package/dist/channels/origin/types.d.ts +11 -0
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/approvals.d.ts +16 -0
- package/dist/channels/slack/approvals.d.ts.map +1 -1
- package/dist/channels/slack/approvals.js +86 -0
- package/dist/channels/slack/cli-project.d.ts +19 -0
- package/dist/channels/slack/cli-project.d.ts.map +1 -0
- package/dist/channels/slack/cli-project.js +234 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +142 -63
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +1 -1
- package/dist/channels/slack/init.d.ts +3 -2
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +5 -5
- package/dist/channels/slack/interactive.d.ts +2 -1
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +15 -4
- package/dist/channels/slack/live-delivery.d.ts +1 -1
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +4 -2
- package/dist/channels/slack/manifest.d.ts +1 -1
- package/dist/channels/slack/manifest.js +1 -1
- package/dist/channels/slack/progress-delivery.d.ts +28 -0
- package/dist/channels/slack/progress-delivery.d.ts.map +1 -0
- package/dist/channels/slack/progress-delivery.js +115 -0
- package/dist/channels/slack/setup.d.ts +1 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +10 -6
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +1 -0
- package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
- package/dist/channels/slack/tool-approval-events.js +91 -1
- package/dist/channels/slack/types.d.ts +9 -1
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.jXleCmOc.js → app.BplEAZ3S.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DpuI4i7Z.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.8LhyglIT.js → VPLocalSearchBox.CHXyv4wP.js} +1 -1
- package/dist/docs/assets/chunks/{theme.9ged-pr2.js → theme.BTcsZmjQ.js} +2 -2
- package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
- package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
- package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
- package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
- package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
- package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
- package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.CCnG-nJx.js → reference_cli.md.DfoeyvL0.js} +9 -6
- package/dist/docs/assets/{reference_cli.md.CCnG-nJx.lean.js → reference_cli.md.DfoeyvL0.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
- package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.BEJx9XVj.js} +2 -2
- package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
- package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.CvAHsdSp.js} +10 -2
- package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.CvAHsdSp.lean.js} +1 -1
- package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
- package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
- package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +7 -7
- package/dist/docs/deployment.md +5 -4
- package/dist/docs/design/runtime-abstraction.md +1757 -0
- package/dist/docs/evals.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +8 -8
- package/dist/docs/guides/mcp-oauth.md +26 -8
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +17 -33
- package/dist/docs/guides/slack.md +92 -201
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +5 -3
- package/dist/docs/llms-full.txt +2065 -637
- package/dist/docs/llms.txt +3 -2
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +6 -6
- package/dist/docs/reference/agent-config.md +2 -2
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +13 -10
- package/dist/docs/reference/cli.md +32 -16
- package/dist/docs/reference/connections.html +9 -8
- package/dist/docs/reference/connections.md +6 -3
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +7 -7
- package/dist/docs/reference/http-api.md +3 -1
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/sessions.md +4 -2
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +15 -7
- package/dist/docs/reference/tools.md +34 -2
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/agents-md.html +28 -0
- package/dist/docs/templates/agents-md.md +105 -0
- package/dist/docs/templates/code-wiki.html +5 -5
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +5 -5
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +5 -5
- package/dist/docs/troubleshooting.md +2 -2
- package/dist/evals/run-facts.d.ts.map +1 -1
- package/dist/evals/run-facts.js +27 -0
- package/dist/files-backends/cursor-hosted.d.ts +3 -2
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +15 -9
- package/dist/internal/approval-gate.d.ts +12 -13
- package/dist/internal/approval-gate.d.ts.map +1 -1
- package/dist/internal/approval-gate.js +16 -21
- package/dist/internal/as-of.d.ts +19 -0
- package/dist/internal/as-of.d.ts.map +1 -0
- package/dist/internal/as-of.js +82 -0
- package/dist/internal/chat-client.js +10 -0
- package/dist/internal/cli-deploy.d.ts +6 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +149 -21
- package/dist/internal/cli-mcp-oauth.js +8 -18
- package/dist/internal/cli-slack-manual.d.ts +24 -2
- package/dist/internal/cli-slack-manual.d.ts.map +1 -1
- package/dist/internal/cli-slack-manual.js +251 -20
- package/dist/internal/cli-slack.d.ts +9 -2
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +29 -82
- package/dist/internal/cursor/account-mcp.d.ts +1 -0
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
- package/dist/internal/cursor/account-mcp.js +17 -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 +1 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +5 -6
- package/dist/internal/deploy-client.d.ts +17 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +31 -10
- package/dist/internal/env-file.d.ts +19 -0
- package/dist/internal/env-file.d.ts.map +1 -0
- package/dist/internal/env-file.js +90 -0
- package/dist/internal/framework-file-storage.d.ts +11 -17
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +17 -40
- package/dist/internal/framework-storage-selection.d.ts +13 -11
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +37 -26
- package/dist/internal/hosted-admission-adapter.d.ts +28 -0
- package/dist/internal/hosted-admission-adapter.d.ts.map +1 -0
- package/dist/internal/hosted-admission-adapter.js +7 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +13 -1
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +8 -1
- package/dist/internal/hosted-delivery.d.ts +21 -1
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +101 -34
- package/dist/internal/hosted-execution-diag.d.ts +59 -0
- package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
- package/dist/internal/hosted-execution-diag.js +187 -0
- package/dist/internal/http-channel.d.ts.map +1 -1
- package/dist/internal/http-channel.js +85 -2
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +2 -0
- package/dist/internal/logs-client.d.ts +5 -0
- package/dist/internal/logs-client.d.ts.map +1 -1
- package/dist/internal/logs-client.js +5 -0
- package/dist/internal/mcp-endpoint.js +2 -3
- package/dist/internal/mcp-host.d.ts +10 -0
- package/dist/internal/mcp-host.d.ts.map +1 -1
- package/dist/internal/mcp-host.js +57 -8
- package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
- package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
- package/dist/internal/mcp-oauth-on-demand.js +287 -0
- package/dist/internal/mcp-oauth-persist.d.ts +42 -0
- package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
- package/dist/internal/mcp-oauth-persist.js +92 -0
- package/dist/internal/mcp-oauth.d.ts +1 -0
- package/dist/internal/mcp-oauth.d.ts.map +1 -1
- package/dist/internal/mcp-oauth.js +10 -2
- package/dist/internal/null-kv-storage.d.ts +48 -0
- package/dist/internal/null-kv-storage.d.ts.map +1 -0
- package/dist/internal/null-kv-storage.js +58 -0
- package/dist/internal/otel/collector.d.ts.map +1 -1
- package/dist/internal/otel/collector.js +22 -9
- package/dist/internal/server.d.ts +6 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +123 -33
- package/dist/internal/session-engine.d.ts +88 -3
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +538 -46
- package/dist/internal/session-run-log.d.ts +120 -0
- package/dist/internal/session-run-log.d.ts.map +1 -0
- package/dist/internal/session-run-log.js +359 -0
- package/dist/internal/sessions-client.d.ts +9 -7
- package/dist/internal/sessions-client.d.ts.map +1 -1
- package/dist/internal/sessions-client.js +3 -1
- package/dist/internal/storage-coordinator.d.ts +13 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +37 -6
- package/dist/internal/storage-roles.d.ts +5 -0
- package/dist/internal/storage-roles.d.ts.map +1 -1
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +10 -0
- package/dist/internal/tool-policy.d.ts +29 -9
- package/dist/internal/tool-policy.d.ts.map +1 -1
- package/dist/internal/tool-policy.js +24 -0
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +10 -0
- package/dist/internal/turn-outbox.d.ts +24 -0
- package/dist/internal/turn-outbox.d.ts.map +1 -0
- package/dist/internal/turn-outbox.js +80 -0
- package/dist/playground/assets/index-D7rGZNjy.css +1 -0
- package/dist/playground/assets/index-jzNbJENa.js +69 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +1 -1
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +12 -0
- package/dist/storage-protocol.d.ts +8 -0
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +8 -0
- package/dist/storage.d.ts +8 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/tools.d.ts +12 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/types.d.ts +88 -7
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +5 -3
- package/docs/deployment.md +5 -4
- package/docs/design/runtime-abstraction.md +1757 -0
- package/docs/guides/mcp-oauth.md +26 -8
- package/docs/guides/slack.md +93 -202
- package/docs/reference/agent-config.md +2 -2
- package/docs/reference/cli.md +32 -16
- package/docs/reference/connections.md +6 -3
- package/docs/reference/http-api.md +3 -1
- package/docs/reference/sessions.md +4 -2
- package/docs/reference/tools.md +34 -2
- package/docs/templates/agents-md.md +110 -0
- package/docs/troubleshooting.md +2 -2
- package/package.json +1 -1
- package/skills/create-agent/SKILL.md +2 -1
- package/skills/mcp-auth/SKILL.md +6 -3
- package/skills/setup-slack/SKILL.md +23 -13
- package/src/bin/agent-serve.ts +12 -1
- package/src/channels/github/github-channel.ts +17 -0
- package/src/channels/origin/api.ts +24 -5
- package/src/channels/origin/binding.ts +55 -26
- package/src/channels/origin/index.ts +1 -0
- package/src/channels/origin/origin-channel.ts +78 -10
- package/src/channels/origin/reactions.ts +82 -0
- package/src/channels/origin/types.ts +11 -0
- package/src/channels/slack/approvals.ts +105 -0
- package/src/channels/slack/cli-project.ts +267 -0
- package/src/channels/slack/defaults.ts +165 -74
- package/src/channels/slack/dispatch.ts +2 -0
- package/src/channels/slack/init.ts +10 -5
- package/src/channels/slack/interactive.ts +35 -9
- package/src/channels/slack/live-delivery.ts +5 -3
- package/src/channels/slack/manifest.ts +1 -1
- package/src/channels/slack/progress-delivery.ts +133 -0
- package/src/channels/slack/setup.ts +10 -6
- package/src/channels/slack/slack-channel.ts +1 -0
- package/src/channels/slack/tool-approval-events.ts +93 -0
- package/src/channels/slack/types.ts +9 -1
- package/src/evals/run-facts.ts +32 -0
- package/src/files-backends/cursor-hosted.ts +3 -2
- package/src/index.ts +4 -0
- package/src/internal/advertise-tools.ts +31 -10
- package/src/internal/approval-gate.ts +20 -29
- package/src/internal/as-of.ts +107 -0
- package/src/internal/chat-client.ts +19 -0
- package/src/internal/cli-deploy.ts +203 -13
- package/src/internal/cli-mcp-oauth.ts +7 -21
- package/src/internal/cli-slack-manual.ts +350 -18
- package/src/internal/cli-slack.ts +40 -84
- package/src/internal/cursor/account-mcp.ts +21 -0
- package/src/internal/cursor-agent-template.ts +1 -0
- package/src/internal/cursor-event-relay.ts +5 -6
- package/src/internal/deploy-client.ts +43 -0
- package/src/internal/env-file.ts +84 -0
- package/src/internal/framework-file-storage.ts +18 -46
- package/src/internal/framework-storage-selection.ts +41 -25
- package/src/internal/hosted-admission-adapter.ts +42 -0
- package/src/internal/hosted-delivery-protocol.ts +14 -2
- package/src/internal/hosted-delivery.ts +169 -44
- package/src/internal/hosted-execution-diag.ts +252 -0
- package/src/internal/http-channel.ts +107 -0
- package/src/internal/init-project.ts +2 -0
- package/src/internal/logs-client.ts +5 -0
- package/src/internal/mcp-endpoint.ts +13 -4
- package/src/internal/mcp-host.ts +77 -11
- package/src/internal/mcp-oauth-on-demand.ts +352 -0
- package/src/internal/mcp-oauth-persist.ts +127 -0
- package/src/internal/mcp-oauth.ts +17 -1
- package/src/internal/null-kv-storage.ts +74 -0
- package/src/internal/otel/collector.ts +30 -0
- package/src/internal/server.ts +159 -11
- package/src/internal/session-engine.ts +691 -57
- package/src/internal/session-run-log.ts +584 -0
- package/src/internal/sessions-client.ts +17 -8
- package/src/internal/storage-coordinator.ts +49 -9
- package/src/internal/storage-roles.ts +7 -0
- package/src/internal/stream-progress.ts +19 -0
- package/src/internal/tool-policy.ts +49 -9
- package/src/internal/trajectory.ts +10 -0
- package/src/internal/turn-outbox.ts +85 -0
- package/src/storage-backends/cursor-hosted.ts +13 -1
- package/src/storage-protocol.ts +10 -0
- package/src/storage.ts +12 -0
- package/src/tools.ts +12 -2
- package/src/types.ts +93 -8
- package/templates/agents-md/README.md +39 -0
- package/templates/agents-md/agent/agent.ts +8 -0
- package/templates/agents-md/agent/channels/github.ts +10 -0
- package/templates/agents-md/agent/channels/queue.ts +28 -0
- package/templates/agents-md/agent/channels/slack.ts +9 -0
- package/templates/agents-md/agent/instructions.md +39 -0
- package/templates/agents-md/agent/lib/collect.ts +439 -0
- package/templates/agents-md/agent/lib/config.ts +8 -0
- package/templates/agents-md/agent/lib/paths.ts +51 -0
- package/templates/agents-md/agent/schedules/weekly.ts +17 -0
- package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
- package/templates/agents-md/evals/agents.eval.ts +135 -0
- package/templates/agents-md/evals/evals.config.ts +5 -0
- package/templates/agents-md/init.json +38 -0
- package/templates/agents-md/package.json +18 -0
- package/templates/agents-md/tsconfig.json +12 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +0 -1
- package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
- package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
- package/dist/docs/assets/index.md.CI93Ltlb.js +0 -5
- package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
- package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
- package/dist/docs/design/agsh.md +0 -406
- package/dist/playground/assets/index-B1DDvBeC.css +0 -1
- package/dist/playground/assets/index-Cx9CclK_.js +0 -88
- package/docs/design/agsh.md +0 -406
- /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
- /package/dist/docs/assets/{index.md.CI93Ltlb.lean.js → index.md.CVeRUOeZ.lean.js} +0 -0
- /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.BEJx9XVj.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
- /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
continuationSource,
|
|
11
11
|
normalizeIdentity,
|
|
12
12
|
} from "../../internal/continuation-identity.js";
|
|
13
|
+
import { isDeferredChannelSession } from "../../internal/deferred-channel-session.js";
|
|
13
14
|
import { isDevMode } from "../../internal/dev-mode.js";
|
|
15
|
+
import { attachHostedAdmissionAdapter } from "../../internal/hosted-admission-adapter.js";
|
|
14
16
|
import { bindLocalIngressSend } from "../../internal/local-ingress.js";
|
|
15
17
|
import type {
|
|
16
18
|
AgentCloudOptions,
|
|
@@ -306,6 +308,7 @@ export function parseOriginPullRequestEvent(input: {
|
|
|
306
308
|
repository,
|
|
307
309
|
pullRequestNumber: number,
|
|
308
310
|
pullRequestUrl: url,
|
|
311
|
+
pullRequestAuthor: author,
|
|
309
312
|
payload,
|
|
310
313
|
sender: originSender(input.envelope, payload),
|
|
311
314
|
},
|
|
@@ -432,16 +435,43 @@ function enrichEventContext(input: {
|
|
|
432
435
|
origin: buildOriginBinding({
|
|
433
436
|
repository: input.ctx.repository,
|
|
434
437
|
installationId: input.ctx.installationId,
|
|
438
|
+
cursorAccount:
|
|
439
|
+
input.options.cursorAccount !== undefined &&
|
|
440
|
+
input.options.cursorAccount !== false,
|
|
435
441
|
app: input.options.app,
|
|
436
442
|
}),
|
|
437
443
|
};
|
|
438
444
|
}
|
|
439
445
|
|
|
446
|
+
export type OriginDispatchOutcome = "skip" | "send" | "task";
|
|
447
|
+
|
|
448
|
+
const dispatchOutcomeByResponse = new WeakMap<
|
|
449
|
+
Response,
|
|
450
|
+
OriginDispatchOutcome
|
|
451
|
+
>();
|
|
452
|
+
|
|
453
|
+
function withDispatchOutcome(
|
|
454
|
+
response: Response,
|
|
455
|
+
outcome: OriginDispatchOutcome
|
|
456
|
+
): Response {
|
|
457
|
+
dispatchOutcomeByResponse.set(response, outcome);
|
|
458
|
+
return response;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export function getOriginDispatchOutcome(
|
|
462
|
+
response: Response
|
|
463
|
+
): OriginDispatchOutcome | undefined {
|
|
464
|
+
return dispatchOutcomeByResponse.get(response);
|
|
465
|
+
}
|
|
466
|
+
|
|
440
467
|
function skipped(
|
|
441
468
|
reason: string,
|
|
442
469
|
extra: Record<string, unknown> = {}
|
|
443
470
|
): Response {
|
|
444
|
-
return
|
|
471
|
+
return withDispatchOutcome(
|
|
472
|
+
Response.json({ ok: true, skipped: true, reason, ...extra }),
|
|
473
|
+
"skip"
|
|
474
|
+
);
|
|
445
475
|
}
|
|
446
476
|
|
|
447
477
|
function acknowledgeTask(
|
|
@@ -458,9 +488,12 @@ function acknowledgeTask(
|
|
|
458
488
|
});
|
|
459
489
|
})
|
|
460
490
|
);
|
|
461
|
-
return
|
|
462
|
-
|
|
463
|
-
|
|
491
|
+
return withDispatchOutcome(
|
|
492
|
+
Response.json(
|
|
493
|
+
{ ok: true, dispatched: true, mode: "task", ...extra },
|
|
494
|
+
{ status: 202 }
|
|
495
|
+
),
|
|
496
|
+
"task"
|
|
464
497
|
);
|
|
465
498
|
}
|
|
466
499
|
|
|
@@ -481,12 +514,26 @@ async function startTurn(input: {
|
|
|
481
514
|
title: input.dispatch.title ?? defaultOriginTitle(input.ctx),
|
|
482
515
|
...(input.cloud === undefined ? {} : { cloud: input.cloud }),
|
|
483
516
|
});
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
517
|
+
if (isDeferredChannelSession(session)) {
|
|
518
|
+
// Hosted admission captured the send; the control plane allocates the
|
|
519
|
+
// session after acknowledgement, so there is nothing to report yet.
|
|
520
|
+
return withDispatchOutcome(
|
|
521
|
+
Response.json(
|
|
522
|
+
{ ok: true, dispatched: true, mode: "turn" },
|
|
523
|
+
{ status: 202 }
|
|
524
|
+
),
|
|
525
|
+
"send"
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
return withDispatchOutcome(
|
|
529
|
+
Response.json({
|
|
530
|
+
ok: true,
|
|
531
|
+
sessionId: session.id,
|
|
532
|
+
isNew: session.isNew,
|
|
533
|
+
continuationToken: session.continuationToken,
|
|
534
|
+
}),
|
|
535
|
+
"send"
|
|
536
|
+
);
|
|
490
537
|
}
|
|
491
538
|
|
|
492
539
|
async function resolveCloudOptions(
|
|
@@ -808,6 +855,27 @@ export function originChannel(
|
|
|
808
855
|
],
|
|
809
856
|
});
|
|
810
857
|
originChannelOptionsByDefinition.set(definition, channelOptions);
|
|
858
|
+
attachHostedAdmissionAdapter(definition, {
|
|
859
|
+
kind: ORIGIN_CHANNEL_KIND,
|
|
860
|
+
dispatch: async ({ payload, args }) => {
|
|
861
|
+
const envelope = parseOriginWebhookEnvelope(payload);
|
|
862
|
+
if (envelope === null) {
|
|
863
|
+
return Response.json(
|
|
864
|
+
{ ok: false, error: "invalid_origin_payload" },
|
|
865
|
+
{ status: 400 }
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
return dispatchOriginWebhook({
|
|
869
|
+
options: channelOptions,
|
|
870
|
+
envelope,
|
|
871
|
+
args,
|
|
872
|
+
});
|
|
873
|
+
},
|
|
874
|
+
getOutcome: (response) => {
|
|
875
|
+
const outcome = getOriginDispatchOutcome(response);
|
|
876
|
+
return outcome === "skip" || outcome === "task" ? outcome : undefined;
|
|
877
|
+
},
|
|
878
|
+
});
|
|
811
879
|
if (usesCursorAccount) {
|
|
812
880
|
registerOriginCursorAccountRuntime(definition, {
|
|
813
881
|
options: channelOptions,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origin PR comment reactions — the Origin analogue of the GitHub channel's
|
|
3
|
+
* `thread.react("eyes")`.
|
|
4
|
+
*
|
|
5
|
+
* Unlike checks and comments, reactions have no `/v1/origin/...` REST
|
|
6
|
+
* binding. The only write is Connect unary JSON against Origin's first-party
|
|
7
|
+
* service (`origin.v1.OriginService/SetCommentReaction`), which lives on a
|
|
8
|
+
* different host than the public REST API — {@link originRpcBaseUrl}, not
|
|
9
|
+
* {@link originPublicApiBaseUrl}. `ctx.origin.reactToComment` already points
|
|
10
|
+
* at the right one; a hand-built client must too.
|
|
11
|
+
*
|
|
12
|
+
* Writing needs `repository:pull_requests:reviews:write`: an `oit_…`
|
|
13
|
+
* installation token for app channels, or a deployment service-account
|
|
14
|
+
* session (hosted v2 forks). Origin rejects reactions on comments that
|
|
15
|
+
* belong to an unsubmitted review. API failures throw `OriginApiError`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { OriginApiMethod } from "./api.js";
|
|
19
|
+
|
|
20
|
+
/** Any client that can call Origin's ConnectRPC host. */
|
|
21
|
+
export interface OriginReactionClient {
|
|
22
|
+
request<T = unknown>(input: {
|
|
23
|
+
method: OriginApiMethod;
|
|
24
|
+
path: string;
|
|
25
|
+
body?: unknown;
|
|
26
|
+
}): Promise<T>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Connect unary route backing {@link setOriginCommentReaction}. */
|
|
30
|
+
export const SET_ORIGIN_COMMENT_REACTION_PATH =
|
|
31
|
+
"/origin.v1.OriginService/SetCommentReaction";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The eight reactions Origin accepts. Anything else is rejected with
|
|
35
|
+
* `invalid_argument`, so channels get a compile error instead of a 400.
|
|
36
|
+
*/
|
|
37
|
+
export const ORIGIN_COMMENT_REACTIONS = [
|
|
38
|
+
"👍",
|
|
39
|
+
"👎",
|
|
40
|
+
"😄",
|
|
41
|
+
"🎉",
|
|
42
|
+
"😕",
|
|
43
|
+
"❤️",
|
|
44
|
+
"🚀",
|
|
45
|
+
"👀",
|
|
46
|
+
] as const;
|
|
47
|
+
|
|
48
|
+
export type OriginCommentReaction = (typeof ORIGIN_COMMENT_REACTIONS)[number];
|
|
49
|
+
|
|
50
|
+
export interface OriginCommentReactionInput {
|
|
51
|
+
/** Origin comment TypeID (`cmt_…`), i.e. `comment.id` on a comment hook. */
|
|
52
|
+
commentId: string;
|
|
53
|
+
emoji: OriginCommentReaction;
|
|
54
|
+
/** `false` removes the reaction. Removing one that is absent is a no-op. */
|
|
55
|
+
active?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Add (or, with `active: false`, remove) one reaction on an Origin PR
|
|
60
|
+
* comment as the client's own principal.
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
63
|
+
* await setOriginCommentReaction({
|
|
64
|
+
* origin: createOriginClient({ apiBaseUrl: originRpcBaseUrl() }),
|
|
65
|
+
* commentId: comment.id,
|
|
66
|
+
* emoji: "👀",
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export async function setOriginCommentReaction(
|
|
71
|
+
input: OriginCommentReactionInput & { origin: OriginReactionClient }
|
|
72
|
+
): Promise<void> {
|
|
73
|
+
await input.origin.request({
|
|
74
|
+
method: "POST",
|
|
75
|
+
path: SET_ORIGIN_COMMENT_REACTION_PATH,
|
|
76
|
+
body: {
|
|
77
|
+
commentId: input.commentId,
|
|
78
|
+
emoji: input.emoji,
|
|
79
|
+
active: input.active ?? true,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -58,6 +58,11 @@ export interface OriginEventContext {
|
|
|
58
58
|
repository: OriginRepositoryRef;
|
|
59
59
|
pullRequestNumber: number;
|
|
60
60
|
pullRequestUrl: string;
|
|
61
|
+
/**
|
|
62
|
+
* Who opened the pull request, when the payload carries it. Distinct from
|
|
63
|
+
* {@link sender} — on a comment event the sender is the commenter.
|
|
64
|
+
*/
|
|
65
|
+
pullRequestAuthor?: OriginActor;
|
|
61
66
|
/**
|
|
62
67
|
* Raw parsed `event.payload` record (`{}` when absent), for consumers
|
|
63
68
|
* whose normalization needs more than the typed event — the GitHub
|
|
@@ -152,6 +157,12 @@ export interface OriginAppOptions {
|
|
|
152
157
|
token?: string | OriginTokenProvider;
|
|
153
158
|
/** Public Origin REST base, e.g. `https://api.cursor.com`. */
|
|
154
159
|
apiBaseUrl?: string;
|
|
160
|
+
/**
|
|
161
|
+
* Origin ConnectRPC base for operations without a REST binding (comment
|
|
162
|
+
* reactions), e.g. `https://api.origin.cursor.com`. Falls back to
|
|
163
|
+
* `ORIGIN_RPC_BASE_URL`.
|
|
164
|
+
*/
|
|
165
|
+
rpcBaseUrl?: string;
|
|
155
166
|
}
|
|
156
167
|
|
|
157
168
|
export interface OriginChannelOptions {
|
|
@@ -6,6 +6,8 @@ import type { ApprovalDecision } from "../../types.js";
|
|
|
6
6
|
|
|
7
7
|
export const SLACK_APPROVE_ACTION_ID = "agent_serve_approve";
|
|
8
8
|
export const SLACK_DENY_ACTION_ID = "agent_serve_deny";
|
|
9
|
+
export const SLACK_AUTH_CONNECTED_ACTION_ID = "agent_serve_auth_connected";
|
|
10
|
+
export const SLACK_AUTH_CANCEL_ACTION_ID = "agent_serve_auth_cancel";
|
|
9
11
|
|
|
10
12
|
export interface SlackApprovalActionValue {
|
|
11
13
|
sessionId: string;
|
|
@@ -54,6 +56,29 @@ export function decisionFromActionId(
|
|
|
54
56
|
return null;
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
export function decisionFromAuthActionId(
|
|
60
|
+
actionId: string
|
|
61
|
+
): ApprovalDecision | null {
|
|
62
|
+
if (actionId === SLACK_AUTH_CONNECTED_ACTION_ID) {
|
|
63
|
+
return "approve";
|
|
64
|
+
}
|
|
65
|
+
if (actionId === SLACK_AUTH_CANCEL_ACTION_ID) {
|
|
66
|
+
return "deny";
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function authThreadStatus(connection: string): string {
|
|
72
|
+
const prefix = "Waiting for ";
|
|
73
|
+
const suffix = " auth…";
|
|
74
|
+
const budget = 50 - prefix.length - suffix.length;
|
|
75
|
+
const name =
|
|
76
|
+
connection.length <= budget
|
|
77
|
+
? connection
|
|
78
|
+
: `${connection.slice(0, Math.max(0, budget - 1))}…`;
|
|
79
|
+
return `${prefix}${name}${suffix}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
57
82
|
const REDACTED = "[REDACTED]";
|
|
58
83
|
const SENSITIVE_KEY =
|
|
59
84
|
/(?:pass(?:word|wd)?|secret|token|api[_-]?key|authorization|credential|private[_-]?key|access[_-]?key)/i;
|
|
@@ -176,6 +201,86 @@ export function buildApprovalBlocks(args: {
|
|
|
176
201
|
];
|
|
177
202
|
}
|
|
178
203
|
|
|
204
|
+
export function buildAuthBlocks(args: {
|
|
205
|
+
sessionId: string;
|
|
206
|
+
callId: string;
|
|
207
|
+
toolName: string;
|
|
208
|
+
connection: string;
|
|
209
|
+
authUrl: string;
|
|
210
|
+
}): unknown[] {
|
|
211
|
+
const value = encodeApprovalActionValue({
|
|
212
|
+
sessionId: args.sessionId,
|
|
213
|
+
callId: args.callId,
|
|
214
|
+
});
|
|
215
|
+
const label =
|
|
216
|
+
args.connection.length > 20
|
|
217
|
+
? `Authorize ${args.connection.slice(0, 17)}…`
|
|
218
|
+
: `Authorize ${args.connection}`;
|
|
219
|
+
return [
|
|
220
|
+
{
|
|
221
|
+
type: "header",
|
|
222
|
+
text: {
|
|
223
|
+
type: "plain_text",
|
|
224
|
+
text: "MCP authorization needed",
|
|
225
|
+
emoji: true,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: "section",
|
|
230
|
+
text: {
|
|
231
|
+
type: "mrkdwn",
|
|
232
|
+
text: `Connect \`${args.connection}\` so \`${args.toolName}\` can continue.`,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
type: "actions",
|
|
237
|
+
block_id: `auth_${args.callId}`.slice(0, 255),
|
|
238
|
+
elements: [
|
|
239
|
+
{
|
|
240
|
+
type: "button",
|
|
241
|
+
text: { type: "plain_text", text: label, emoji: true },
|
|
242
|
+
url: args.authUrl,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
type: "button",
|
|
246
|
+
action_id: SLACK_AUTH_CONNECTED_ACTION_ID,
|
|
247
|
+
text: { type: "plain_text", text: "Connected", emoji: true },
|
|
248
|
+
style: "primary",
|
|
249
|
+
value,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
type: "button",
|
|
253
|
+
action_id: SLACK_AUTH_CANCEL_ACTION_ID,
|
|
254
|
+
text: { type: "plain_text", text: "Cancel", emoji: true },
|
|
255
|
+
style: "danger",
|
|
256
|
+
value,
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function buildResolvedAuthBlocks(args: {
|
|
264
|
+
connection: string;
|
|
265
|
+
decision: ApprovalDecision;
|
|
266
|
+
byUserId?: string;
|
|
267
|
+
}): unknown[] {
|
|
268
|
+
const verb = args.decision === "approve" ? "Connected" : "Cancelled";
|
|
269
|
+
const by =
|
|
270
|
+
args.byUserId === undefined || args.byUserId === ""
|
|
271
|
+
? ""
|
|
272
|
+
: ` by <@${args.byUserId}>`;
|
|
273
|
+
return [
|
|
274
|
+
{
|
|
275
|
+
type: "section",
|
|
276
|
+
text: {
|
|
277
|
+
type: "mrkdwn",
|
|
278
|
+
text: `*${verb}*${by} — \`${args.connection}\``,
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
];
|
|
282
|
+
}
|
|
283
|
+
|
|
179
284
|
export function buildResolvedApprovalBlocks(args: {
|
|
180
285
|
toolName: string;
|
|
181
286
|
decision: ApprovalDecision;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official Slack CLI project files for `slack init --manual`.
|
|
3
|
+
*
|
|
4
|
+
* `.slack/` is the committed Slack CLI project: hook, manifests, hooks.json.
|
|
5
|
+
* Agent SDK serve owns the socket; do not `slack deploy` / `slack run`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
|
|
14
|
+
export const SLACK_CLI_HOME_BIN = ".slack/bin/slack";
|
|
15
|
+
|
|
16
|
+
export const SLACK_CLI_GET_MANIFEST = "node .slack/get-manifest.mjs";
|
|
17
|
+
|
|
18
|
+
export type SlackCliEnvironment = "local" | "deployed";
|
|
19
|
+
|
|
20
|
+
const TEAM_ID_RE = /\(Team ID: ([TE][A-Z0-9]+)\)/g;
|
|
21
|
+
|
|
22
|
+
const GET_MANIFEST_JS = `import { readFileSync } from "node:fs";
|
|
23
|
+
import { dirname, join } from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
|
|
26
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
|
|
28
|
+
function target() {
|
|
29
|
+
const env = process.env.SLACK_ENV ?? process.env.SLACK_APP_ENVIRONMENT;
|
|
30
|
+
if (env === "deployed" || env === "prod") return "manifest.prod.json";
|
|
31
|
+
if (env === "local" || env === "dev") return "manifest.dev.json";
|
|
32
|
+
try {
|
|
33
|
+
const raw = readFileSync(join(here, "cli-environment"), "utf8").trim();
|
|
34
|
+
if (raw === "deployed" || raw === "prod") return "manifest.prod.json";
|
|
35
|
+
} catch {
|
|
36
|
+
// default local
|
|
37
|
+
}
|
|
38
|
+
return "manifest.dev.json";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
process.stdout.write(readFileSync(join(here, target()), "utf8"));
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
function isEnoent(error: unknown): boolean {
|
|
45
|
+
return (
|
|
46
|
+
error instanceof Error &&
|
|
47
|
+
"code" in error &&
|
|
48
|
+
(error as NodeJS.ErrnoException).code === "ENOENT"
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Official Slack CLI, if present. `SLACK_CLI` overrides. */
|
|
53
|
+
export function detectSlackCli(
|
|
54
|
+
env: NodeJS.ProcessEnv = process.env
|
|
55
|
+
): string | undefined {
|
|
56
|
+
const override = env.SLACK_CLI;
|
|
57
|
+
if (override !== undefined && override !== "") {
|
|
58
|
+
return override;
|
|
59
|
+
}
|
|
60
|
+
const home = env.HOME ?? env.USERPROFILE ?? homedir();
|
|
61
|
+
const homeBin = join(home, SLACK_CLI_HOME_BIN);
|
|
62
|
+
return existsSync(homeBin) ? homeBin : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Hook + manifests under `.slack/`. Merge hooks.json; keep existing config. */
|
|
66
|
+
export async function writeSlackCliProject(
|
|
67
|
+
rootDir: string,
|
|
68
|
+
manifests: ReadonlyArray<{ name: string; contents: string }>
|
|
69
|
+
): Promise<string[]> {
|
|
70
|
+
const slackDir = join(rootDir, ".slack");
|
|
71
|
+
await mkdir(slackDir, { recursive: true });
|
|
72
|
+
const created: string[] = [];
|
|
73
|
+
|
|
74
|
+
await writeFile(join(slackDir, "get-manifest.mjs"), GET_MANIFEST_JS);
|
|
75
|
+
created.push(".slack/get-manifest.mjs");
|
|
76
|
+
|
|
77
|
+
for (const file of manifests) {
|
|
78
|
+
await writeFile(join(slackDir, file.name), file.contents);
|
|
79
|
+
created.push(`.slack/${file.name}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (await upsertGetManifestHook(slackDir)) {
|
|
83
|
+
created.push(".slack/hooks.json");
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
await writeIfMissing(
|
|
87
|
+
join(slackDir, "config.json"),
|
|
88
|
+
`${JSON.stringify(
|
|
89
|
+
{
|
|
90
|
+
manifest: { source: "local" },
|
|
91
|
+
project_id: randomUUID(),
|
|
92
|
+
},
|
|
93
|
+
null,
|
|
94
|
+
2
|
|
95
|
+
)}\n`
|
|
96
|
+
)
|
|
97
|
+
) {
|
|
98
|
+
created.push(".slack/config.json");
|
|
99
|
+
}
|
|
100
|
+
if (await mergeGitignore(join(slackDir, ".gitignore"))) {
|
|
101
|
+
created.push(".slack/.gitignore");
|
|
102
|
+
}
|
|
103
|
+
return created;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function upsertGetManifestHook(slackDir: string): Promise<boolean> {
|
|
107
|
+
const path = join(slackDir, "hooks.json");
|
|
108
|
+
let existing: { hooks?: Record<string, string> };
|
|
109
|
+
try {
|
|
110
|
+
const parsed: unknown = JSON.parse(await readFile(path, "utf8"));
|
|
111
|
+
if (
|
|
112
|
+
parsed === null ||
|
|
113
|
+
typeof parsed !== "object" ||
|
|
114
|
+
Array.isArray(parsed)
|
|
115
|
+
) {
|
|
116
|
+
throw new Error(".slack/hooks.json is not a JSON object");
|
|
117
|
+
}
|
|
118
|
+
existing = parsed as { hooks?: Record<string, string> };
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (!isEnoent(error)) {
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
await writeFile(
|
|
124
|
+
path,
|
|
125
|
+
`${JSON.stringify({ hooks: { "get-manifest": SLACK_CLI_GET_MANIFEST } }, null, 2)}\n`
|
|
126
|
+
);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
const hooks = existing.hooks ?? {};
|
|
130
|
+
if (hooks["get-manifest"] === SLACK_CLI_GET_MANIFEST) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
hooks["get-manifest"] = SLACK_CLI_GET_MANIFEST;
|
|
134
|
+
existing.hooks = hooks;
|
|
135
|
+
await writeFile(path, `${JSON.stringify(existing, null, 2)}\n`);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function writeIfMissing(
|
|
140
|
+
path: string,
|
|
141
|
+
contents: string
|
|
142
|
+
): Promise<boolean> {
|
|
143
|
+
try {
|
|
144
|
+
await writeFile(path, contents, { flag: "wx" });
|
|
145
|
+
return true;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (
|
|
148
|
+
error instanceof Error &&
|
|
149
|
+
"code" in error &&
|
|
150
|
+
(error as NodeJS.ErrnoException).code === "EEXIST"
|
|
151
|
+
) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function mergeGitignore(path: string): Promise<boolean> {
|
|
159
|
+
const lines = ["apps.dev.json", "cache/", "cli-environment"];
|
|
160
|
+
let existing = "";
|
|
161
|
+
try {
|
|
162
|
+
existing = await readFile(path, "utf8");
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (!isEnoent(error)) {
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
await writeFile(path, `${lines.join("\n")}\n`);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
const have = new Set(
|
|
171
|
+
existing
|
|
172
|
+
.split(/\r?\n/)
|
|
173
|
+
.map((line) => line.trim())
|
|
174
|
+
.filter((line) => line !== "")
|
|
175
|
+
);
|
|
176
|
+
const missing = lines.filter((line) => !have.has(line));
|
|
177
|
+
if (missing.length === 0) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
const prefix =
|
|
181
|
+
existing === "" || existing.endsWith("\n") ? existing : `${existing}\n`;
|
|
182
|
+
await writeFile(path, `${prefix}${missing.join("\n")}\n`);
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function parseSlackAuthTeams(text: string): string[] {
|
|
187
|
+
const ids: string[] = [];
|
|
188
|
+
for (const match of text.matchAll(TEAM_ID_RE)) {
|
|
189
|
+
const id = match[1];
|
|
190
|
+
if (id !== undefined && !ids.includes(id)) {
|
|
191
|
+
ids.push(id);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return ids;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export async function readSlackCliAppId(
|
|
198
|
+
dir: string,
|
|
199
|
+
environment: SlackCliEnvironment,
|
|
200
|
+
team?: string
|
|
201
|
+
): Promise<string | undefined> {
|
|
202
|
+
const apps = await loadAppMap(dir, environment);
|
|
203
|
+
if (apps === undefined) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
if (team !== undefined) {
|
|
207
|
+
return appIdOf(apps[team]);
|
|
208
|
+
}
|
|
209
|
+
return firstAppId(apps);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function loadAppMap(
|
|
213
|
+
dir: string,
|
|
214
|
+
environment: SlackCliEnvironment
|
|
215
|
+
): Promise<Record<string, unknown> | undefined> {
|
|
216
|
+
if (environment === "local") {
|
|
217
|
+
return readJson(join(dir, ".slack/apps.dev.json"));
|
|
218
|
+
}
|
|
219
|
+
const deployed = await readJson(join(dir, ".slack/apps.json"));
|
|
220
|
+
if (deployed === undefined) {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
const apps = deployed.apps;
|
|
224
|
+
if (apps !== undefined && typeof apps === "object" && apps !== null) {
|
|
225
|
+
return apps as Record<string, unknown>;
|
|
226
|
+
}
|
|
227
|
+
return deployed;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function firstAppId(value: Record<string, unknown>): string | undefined {
|
|
231
|
+
for (const entry of Object.values(value)) {
|
|
232
|
+
const id = appIdOf(entry);
|
|
233
|
+
if (id !== undefined) {
|
|
234
|
+
return id;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function appIdOf(entry: unknown): string | undefined {
|
|
241
|
+
if (entry === undefined || entry === null || typeof entry !== "object") {
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
const appId = (entry as { app_id?: unknown }).app_id;
|
|
245
|
+
if (typeof appId === "string" && appId.startsWith("A")) {
|
|
246
|
+
return appId;
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function readJson(
|
|
252
|
+
path: string
|
|
253
|
+
): Promise<Record<string, unknown> | undefined> {
|
|
254
|
+
try {
|
|
255
|
+
const parsed: unknown = JSON.parse(await readFile(path, "utf8"));
|
|
256
|
+
if (
|
|
257
|
+
parsed === null ||
|
|
258
|
+
typeof parsed !== "object" ||
|
|
259
|
+
Array.isArray(parsed)
|
|
260
|
+
) {
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
return parsed as Record<string, unknown>;
|
|
264
|
+
} catch {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
}
|