@cursor/july 0.1.1
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 +290 -0
- package/LICENSE.md +3 -0
- package/README.md +1233 -0
- package/dist/ab.d.ts +290 -0
- package/dist/ab.d.ts.map +1 -0
- package/dist/ab.js +386 -0
- package/dist/bin/agent-serve.d.ts +15 -0
- package/dist/bin/agent-serve.d.ts.map +1 -0
- package/dist/bin/agent-serve.js +754 -0
- package/dist/channels/github/api.d.ts +101 -0
- package/dist/channels/github/api.d.ts.map +1 -0
- package/dist/channels/github/api.js +229 -0
- package/dist/channels/github/auth.d.ts +67 -0
- package/dist/channels/github/auth.d.ts.map +1 -0
- package/dist/channels/github/auth.js +239 -0
- package/dist/channels/github/binding.d.ts +73 -0
- package/dist/channels/github/binding.d.ts.map +1 -0
- package/dist/channels/github/binding.js +114 -0
- package/dist/channels/github/defaults.d.ts +24 -0
- package/dist/channels/github/defaults.d.ts.map +1 -0
- package/dist/channels/github/defaults.js +100 -0
- package/dist/channels/github/events.d.ts +18 -0
- package/dist/channels/github/events.d.ts.map +1 -0
- package/dist/channels/github/events.js +59 -0
- package/dist/channels/github/forward.d.ts +137 -0
- package/dist/channels/github/forward.d.ts.map +1 -0
- package/dist/channels/github/forward.js +271 -0
- package/dist/channels/github/github-channel.d.ts +127 -0
- package/dist/channels/github/github-channel.d.ts.map +1 -0
- package/dist/channels/github/github-channel.js +1688 -0
- package/dist/channels/github/index.d.ts +52 -0
- package/dist/channels/github/index.d.ts.map +1 -0
- package/dist/channels/github/index.js +51 -0
- package/dist/channels/github/replay.d.ts +115 -0
- package/dist/channels/github/replay.d.ts.map +1 -0
- package/dist/channels/github/replay.js +282 -0
- package/dist/channels/github/state.d.ts +26 -0
- package/dist/channels/github/state.d.ts.map +1 -0
- package/dist/channels/github/state.js +50 -0
- package/dist/channels/github/types.d.ts +385 -0
- package/dist/channels/github/types.d.ts.map +1 -0
- package/dist/channels/github/types.js +1 -0
- package/dist/channels/slack/api.d.ts +117 -0
- package/dist/channels/slack/api.d.ts.map +1 -0
- package/dist/channels/slack/api.js +437 -0
- package/dist/channels/slack/approvals.d.ts +32 -0
- package/dist/channels/slack/approvals.d.ts.map +1 -0
- package/dist/channels/slack/approvals.js +157 -0
- package/dist/channels/slack/assistant.d.ts +23 -0
- package/dist/channels/slack/assistant.d.ts.map +1 -0
- package/dist/channels/slack/assistant.js +67 -0
- package/dist/channels/slack/auth.d.ts +40 -0
- package/dist/channels/slack/auth.d.ts.map +1 -0
- package/dist/channels/slack/auth.js +71 -0
- package/dist/channels/slack/channel-watch.d.ts +46 -0
- package/dist/channels/slack/channel-watch.d.ts.map +1 -0
- package/dist/channels/slack/channel-watch.js +180 -0
- package/dist/channels/slack/constants.d.ts +17 -0
- package/dist/channels/slack/constants.d.ts.map +1 -0
- package/dist/channels/slack/constants.js +27 -0
- package/dist/channels/slack/credentials.d.ts +35 -0
- package/dist/channels/slack/credentials.d.ts.map +1 -0
- package/dist/channels/slack/credentials.js +88 -0
- package/dist/channels/slack/cursor-account.d.ts +76 -0
- package/dist/channels/slack/cursor-account.d.ts.map +1 -0
- package/dist/channels/slack/cursor-account.js +88 -0
- package/dist/channels/slack/defaults.d.ts +32 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -0
- package/dist/channels/slack/defaults.js +380 -0
- package/dist/channels/slack/dispatch.d.ts +43 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -0
- package/dist/channels/slack/dispatch.js +185 -0
- package/dist/channels/slack/doctor.d.ts +24 -0
- package/dist/channels/slack/doctor.d.ts.map +1 -0
- package/dist/channels/slack/doctor.js +115 -0
- package/dist/channels/slack/event-id-dedupe.d.ts +10 -0
- package/dist/channels/slack/event-id-dedupe.d.ts.map +1 -0
- package/dist/channels/slack/event-id-dedupe.js +23 -0
- package/dist/channels/slack/inbound.d.ts +41 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -0
- package/dist/channels/slack/inbound.js +166 -0
- package/dist/channels/slack/index.d.ts +45 -0
- package/dist/channels/slack/index.d.ts.map +1 -0
- package/dist/channels/slack/index.js +44 -0
- package/dist/channels/slack/init.d.ts +32 -0
- package/dist/channels/slack/init.d.ts.map +1 -0
- package/dist/channels/slack/init.js +82 -0
- package/dist/channels/slack/interactive.d.ts +19 -0
- package/dist/channels/slack/interactive.d.ts.map +1 -0
- package/dist/channels/slack/interactive.js +142 -0
- package/dist/channels/slack/links.d.ts +10 -0
- package/dist/channels/slack/links.d.ts.map +1 -0
- package/dist/channels/slack/links.js +19 -0
- package/dist/channels/slack/live-delivery.d.ts +75 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -0
- package/dist/channels/slack/live-delivery.js +143 -0
- package/dist/channels/slack/log.d.ts +25 -0
- package/dist/channels/slack/log.d.ts.map +1 -0
- package/dist/channels/slack/log.js +47 -0
- package/dist/channels/slack/manifest.d.ts +57 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -0
- package/dist/channels/slack/manifest.js +110 -0
- package/dist/channels/slack/pr-ref.d.ts +18 -0
- package/dist/channels/slack/pr-ref.d.ts.map +1 -0
- package/dist/channels/slack/pr-ref.js +36 -0
- package/dist/channels/slack/setup.d.ts +14 -0
- package/dist/channels/slack/setup.d.ts.map +1 -0
- package/dist/channels/slack/setup.js +86 -0
- package/dist/channels/slack/slack-channel.d.ts +15 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -0
- package/dist/channels/slack/slack-channel.js +281 -0
- package/dist/channels/slack/socket-mode.d.ts +26 -0
- package/dist/channels/slack/socket-mode.d.ts.map +1 -0
- package/dist/channels/slack/socket-mode.js +116 -0
- package/dist/channels/slack/stream.d.ts +26 -0
- package/dist/channels/slack/stream.d.ts.map +1 -0
- package/dist/channels/slack/stream.js +39 -0
- package/dist/channels/slack/tool-approval-events.d.ts +33 -0
- package/dist/channels/slack/tool-approval-events.d.ts.map +1 -0
- package/dist/channels/slack/tool-approval-events.js +129 -0
- package/dist/channels/slack/types.d.ts +326 -0
- package/dist/channels/slack/types.d.ts.map +1 -0
- package/dist/channels/slack/types.js +4 -0
- package/dist/channels.d.ts +116 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +294 -0
- package/dist/connections.d.ts +75 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +75 -0
- package/dist/docs/404.html +22 -0
- package/dist/docs/ab.html +87 -0
- package/dist/docs/assets/ab.md.COdXkces.js +63 -0
- package/dist/docs/assets/ab.md.COdXkces.lean.js +1 -0
- package/dist/docs/assets/app.DqfFEmJd.js +1 -0
- package/dist/docs/assets/building-with-agents.md.CJCtZCyi.js +13 -0
- package/dist/docs/assets/building-with-agents.md.CJCtZCyi.lean.js +1 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.CcVk1uKq.js +1 -0
- package/dist/docs/assets/chunks/VPLocalSearchBox.BaLEdS15.js +9 -0
- package/dist/docs/assets/chunks/framework.CAZyNGu9.js +19 -0
- package/dist/docs/assets/chunks/theme.CZRvu_0q.js +2 -0
- package/dist/docs/assets/concepts.md.Cfb9b-k1.js +4 -0
- package/dist/docs/assets/concepts.md.Cfb9b-k1.lean.js +1 -0
- package/dist/docs/assets/deployment.md.Dx1TYNk5.js +14 -0
- package/dist/docs/assets/deployment.md.Dx1TYNk5.lean.js +1 -0
- package/dist/docs/assets/evals.md.DPZ_MAnI.js +85 -0
- package/dist/docs/assets/evals.md.DPZ_MAnI.lean.js +1 -0
- package/dist/docs/assets/guides_agent-to-agent.md.CrtrsySy.js +10 -0
- package/dist/docs/assets/guides_agent-to-agent.md.CrtrsySy.lean.js +1 -0
- package/dist/docs/assets/guides_cloud-runtime.md.CYlNMTNp.js +9 -0
- package/dist/docs/assets/guides_cloud-runtime.md.CYlNMTNp.lean.js +1 -0
- package/dist/docs/assets/guides_github.md.DwbKhCeS.js +20 -0
- package/dist/docs/assets/guides_github.md.DwbKhCeS.lean.js +1 -0
- package/dist/docs/assets/guides_human-in-the-loop.md.Dvuctx7s.js +28 -0
- package/dist/docs/assets/guides_human-in-the-loop.md.Dvuctx7s.lean.js +1 -0
- package/dist/docs/assets/guides_slack.md.bv41fHfW.js +37 -0
- package/dist/docs/assets/guides_slack.md.bv41fHfW.lean.js +1 -0
- package/dist/docs/assets/guides_webhooks.md.hFTik3lf.js +50 -0
- package/dist/docs/assets/guides_webhooks.md.hFTik3lf.lean.js +1 -0
- package/dist/docs/assets/hillclimbing.md.DHNast08.js +4 -0
- package/dist/docs/assets/hillclimbing.md.DHNast08.lean.js +1 -0
- package/dist/docs/assets/index.md.BPKcj5AI.js +20 -0
- package/dist/docs/assets/index.md.BPKcj5AI.lean.js +1 -0
- package/dist/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/dist/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/dist/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/dist/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/dist/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/dist/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/dist/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/dist/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/dist/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/dist/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/dist/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/dist/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/dist/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/dist/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/dist/docs/assets/quickstart.md.tVPiGK_L.js +35 -0
- package/dist/docs/assets/quickstart.md.tVPiGK_L.lean.js +1 -0
- package/dist/docs/assets/reference_agent-config.md.Bpd7HQwf.js +34 -0
- package/dist/docs/assets/reference_agent-config.md.Bpd7HQwf.lean.js +1 -0
- package/dist/docs/assets/reference_channels.md.D7JTR03W.js +53 -0
- package/dist/docs/assets/reference_channels.md.D7JTR03W.lean.js +1 -0
- package/dist/docs/assets/reference_cli.md.DA730zCu.js +33 -0
- package/dist/docs/assets/reference_cli.md.DA730zCu.lean.js +1 -0
- package/dist/docs/assets/reference_connections.md.C3vNH_DE.js +26 -0
- package/dist/docs/assets/reference_connections.md.C3vNH_DE.lean.js +1 -0
- package/dist/docs/assets/reference_hooks.md.BCEc3MyM.js +12 -0
- package/dist/docs/assets/reference_hooks.md.BCEc3MyM.lean.js +1 -0
- package/dist/docs/assets/reference_http-api.md.DBAahtdz.js +11 -0
- package/dist/docs/assets/reference_http-api.md.DBAahtdz.lean.js +1 -0
- package/dist/docs/assets/reference_instructions.md.BC05LEQ8.js +12 -0
- package/dist/docs/assets/reference_instructions.md.BC05LEQ8.lean.js +1 -0
- package/dist/docs/assets/reference_playground.md.CPZhfYaO.js +1 -0
- package/dist/docs/assets/reference_playground.md.CPZhfYaO.lean.js +1 -0
- package/dist/docs/assets/reference_project-layout.md.Bd_CKtNS.js +31 -0
- package/dist/docs/assets/reference_project-layout.md.Bd_CKtNS.lean.js +1 -0
- package/dist/docs/assets/reference_schedules.md.D7qijxLk.js +82 -0
- package/dist/docs/assets/reference_schedules.md.D7qijxLk.lean.js +1 -0
- package/dist/docs/assets/reference_sessions.md.DdjWabnN.js +8 -0
- package/dist/docs/assets/reference_sessions.md.DdjWabnN.lean.js +1 -0
- package/dist/docs/assets/reference_skills.md.VQnlBT3Q.js +15 -0
- package/dist/docs/assets/reference_skills.md.VQnlBT3Q.lean.js +1 -0
- package/dist/docs/assets/reference_subagents.md.CIRAVcPK.js +10 -0
- package/dist/docs/assets/reference_subagents.md.CIRAVcPK.lean.js +1 -0
- package/dist/docs/assets/reference_tools.md.DF5kwlt0.js +46 -0
- package/dist/docs/assets/reference_tools.md.DF5kwlt0.lean.js +1 -0
- package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.js +1 -0
- package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.lean.js +1 -0
- package/dist/docs/assets/style.Bj-IXa5W.css +1 -0
- package/dist/docs/assets/troubleshooting.md.DkovjS7h.js +1 -0
- package/dist/docs/assets/troubleshooting.md.DkovjS7h.lean.js +1 -0
- package/dist/docs/building-with-agents.html +37 -0
- package/dist/docs/concepts.html +28 -0
- package/dist/docs/deployment.html +38 -0
- package/dist/docs/evals.html +109 -0
- package/dist/docs/guides/agent-to-agent.html +34 -0
- package/dist/docs/guides/cloud-runtime.html +33 -0
- package/dist/docs/guides/github.html +44 -0
- package/dist/docs/guides/human-in-the-loop.html +52 -0
- package/dist/docs/guides/slack.html +61 -0
- package/dist/docs/guides/webhooks.html +74 -0
- package/dist/docs/hashmap.json +1 -0
- package/dist/docs/hillclimbing.html +28 -0
- package/dist/docs/index.html +44 -0
- package/dist/docs/quickstart.html +59 -0
- package/dist/docs/reference/agent-config.html +58 -0
- package/dist/docs/reference/channels.html +77 -0
- package/dist/docs/reference/cli.html +57 -0
- package/dist/docs/reference/connections.html +50 -0
- package/dist/docs/reference/hooks.html +36 -0
- package/dist/docs/reference/http-api.html +35 -0
- package/dist/docs/reference/instructions.html +36 -0
- package/dist/docs/reference/playground.html +25 -0
- package/dist/docs/reference/project-layout.html +55 -0
- package/dist/docs/reference/schedules.html +106 -0
- package/dist/docs/reference/sessions.html +32 -0
- package/dist/docs/reference/skills.html +39 -0
- package/dist/docs/reference/subagents.html +34 -0
- package/dist/docs/reference/tools.html +70 -0
- package/dist/docs/scaffolding-agents.html +25 -0
- package/dist/docs/troubleshooting.html +25 -0
- package/dist/docs/vp-icons.css +0 -0
- package/dist/evals.d.ts +312 -0
- package/dist/evals.d.ts.map +1 -0
- package/dist/evals.js +254 -0
- package/dist/hooks.d.ts +23 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +23 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +101 -0
- package/dist/internal/ab-collector.d.ts +42 -0
- package/dist/internal/ab-collector.d.ts.map +1 -0
- package/dist/internal/ab-collector.js +153 -0
- package/dist/internal/ab-fold.d.ts +36 -0
- package/dist/internal/ab-fold.d.ts.map +1 -0
- package/dist/internal/ab-fold.js +171 -0
- package/dist/internal/ab-snapshot.d.ts +70 -0
- package/dist/internal/ab-snapshot.d.ts.map +1 -0
- package/dist/internal/ab-snapshot.js +208 -0
- package/dist/internal/approval-gate.d.ts +34 -0
- package/dist/internal/approval-gate.d.ts.map +1 -0
- package/dist/internal/approval-gate.js +85 -0
- package/dist/internal/auth.d.ts +8 -0
- package/dist/internal/auth.d.ts.map +1 -0
- package/dist/internal/auth.js +27 -0
- package/dist/internal/authored-alias-hooks.d.ts +31 -0
- package/dist/internal/authored-alias-hooks.d.ts.map +1 -0
- package/dist/internal/authored-alias-hooks.js +43 -0
- package/dist/internal/authored-loaders.d.ts +25 -0
- package/dist/internal/authored-loaders.d.ts.map +1 -0
- package/dist/internal/authored-loaders.js +129 -0
- package/dist/internal/bounded-int.d.ts +11 -0
- package/dist/internal/bounded-int.d.ts.map +1 -0
- package/dist/internal/bounded-int.js +13 -0
- package/dist/internal/brand.d.ts +6 -0
- package/dist/internal/brand.d.ts.map +1 -0
- package/dist/internal/brand.js +17 -0
- package/dist/internal/chat-client.d.ts +19 -0
- package/dist/internal/chat-client.d.ts.map +1 -0
- package/dist/internal/chat-client.js +327 -0
- package/dist/internal/cli-ax.d.ts +58 -0
- package/dist/internal/cli-ax.d.ts.map +1 -0
- package/dist/internal/cli-ax.js +345 -0
- package/dist/internal/cli-cursor.d.ts +20 -0
- package/dist/internal/cli-cursor.d.ts.map +1 -0
- package/dist/internal/cli-cursor.js +227 -0
- package/dist/internal/cli-github.d.ts +47 -0
- package/dist/internal/cli-github.d.ts.map +1 -0
- package/dist/internal/cli-github.js +644 -0
- package/dist/internal/cli-slack.d.ts +18 -0
- package/dist/internal/cli-slack.d.ts.map +1 -0
- package/dist/internal/cli-slack.js +144 -0
- package/dist/internal/cloud-merge.d.ts +23 -0
- package/dist/internal/cloud-merge.d.ts.map +1 -0
- package/dist/internal/cloud-merge.js +28 -0
- package/dist/internal/cron.d.ts +17 -0
- package/dist/internal/cron.d.ts.map +1 -0
- package/dist/internal/cron.js +60 -0
- package/dist/internal/cursor/account-mcp.d.ts +95 -0
- package/dist/internal/cursor/account-mcp.d.ts.map +1 -0
- package/dist/internal/cursor/account-mcp.js +342 -0
- package/dist/internal/cursor/backend-client.d.ts +118 -0
- package/dist/internal/cursor/backend-client.d.ts.map +1 -0
- package/dist/internal/cursor/backend-client.js +477 -0
- package/dist/internal/cursor/credentials.d.ts +112 -0
- package/dist/internal/cursor/credentials.d.ts.map +1 -0
- package/dist/internal/cursor/credentials.js +329 -0
- package/dist/internal/cursor-event-relay.d.ts +111 -0
- package/dist/internal/cursor-event-relay.d.ts.map +1 -0
- package/dist/internal/cursor-event-relay.js +181 -0
- package/dist/internal/cursor-relay-core.d.ts +113 -0
- package/dist/internal/cursor-relay-core.d.ts.map +1 -0
- package/dist/internal/cursor-relay-core.js +364 -0
- package/dist/internal/cursor-slack-relay.d.ts +94 -0
- package/dist/internal/cursor-slack-relay.d.ts.map +1 -0
- package/dist/internal/cursor-slack-relay.js +171 -0
- package/dist/internal/describe-error.d.ts +3 -0
- package/dist/internal/describe-error.d.ts.map +1 -0
- package/dist/internal/describe-error.js +4 -0
- package/dist/internal/dev-mode.d.ts +13 -0
- package/dist/internal/dev-mode.d.ts.map +1 -0
- package/dist/internal/dev-mode.js +17 -0
- package/dist/internal/discovery.d.ts +55 -0
- package/dist/internal/discovery.d.ts.map +1 -0
- package/dist/internal/discovery.js +1427 -0
- package/dist/internal/distribution.d.ts +47 -0
- package/dist/internal/distribution.d.ts.map +1 -0
- package/dist/internal/distribution.js +82 -0
- package/dist/internal/docs-site.d.ts +28 -0
- package/dist/internal/docs-site.d.ts.map +1 -0
- package/dist/internal/docs-site.js +169 -0
- package/dist/internal/duration.d.ts +8 -0
- package/dist/internal/duration.d.ts.map +1 -0
- package/dist/internal/duration.js +35 -0
- package/dist/internal/eval-run-store.d.ts +81 -0
- package/dist/internal/eval-run-store.d.ts.map +1 -0
- package/dist/internal/eval-run-store.js +396 -0
- package/dist/internal/eval-runner.d.ts +76 -0
- package/dist/internal/eval-runner.d.ts.map +1 -0
- package/dist/internal/eval-runner.js +336 -0
- package/dist/internal/event-log.d.ts +51 -0
- package/dist/internal/event-log.d.ts.map +1 -0
- package/dist/internal/event-log.js +167 -0
- package/dist/internal/event-mapper.d.ts +46 -0
- package/dist/internal/event-mapper.d.ts.map +1 -0
- package/dist/internal/event-mapper.js +226 -0
- package/dist/internal/frontmatter.d.ts +12 -0
- package/dist/internal/frontmatter.d.ts.map +1 -0
- package/dist/internal/frontmatter.js +61 -0
- package/dist/internal/github-fanout.d.ts +32 -0
- package/dist/internal/github-fanout.d.ts.map +1 -0
- package/dist/internal/github-fanout.js +122 -0
- package/dist/internal/handleAgentServeTrigger.d.ts +59 -0
- package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -0
- package/dist/internal/handleAgentServeTrigger.js +115 -0
- package/dist/internal/host-platforms.d.ts +40 -0
- package/dist/internal/host-platforms.d.ts.map +1 -0
- package/dist/internal/host-platforms.js +113 -0
- package/dist/internal/http-channel.d.ts +54 -0
- package/dist/internal/http-channel.d.ts.map +1 -0
- package/dist/internal/http-channel.js +382 -0
- package/dist/internal/ids.d.ts +19 -0
- package/dist/internal/ids.d.ts.map +1 -0
- package/dist/internal/ids.js +34 -0
- package/dist/internal/init-project.d.ts +22 -0
- package/dist/internal/init-project.d.ts.map +1 -0
- package/dist/internal/init-project.js +125 -0
- package/dist/internal/json-dir-store.d.ts +32 -0
- package/dist/internal/json-dir-store.d.ts.map +1 -0
- package/dist/internal/json-dir-store.js +100 -0
- package/dist/internal/json-schema.d.ts +18 -0
- package/dist/internal/json-schema.d.ts.map +1 -0
- package/dist/internal/json-schema.js +53 -0
- package/dist/internal/log-ring.d.ts +23 -0
- package/dist/internal/log-ring.d.ts.map +1 -0
- package/dist/internal/log-ring.js +42 -0
- package/dist/internal/map-pool.d.ts +6 -0
- package/dist/internal/map-pool.d.ts.map +1 -0
- package/dist/internal/map-pool.js +41 -0
- package/dist/internal/mcp-endpoint.d.ts +59 -0
- package/dist/internal/mcp-endpoint.d.ts.map +1 -0
- package/dist/internal/mcp-endpoint.js +355 -0
- package/dist/internal/mcp-host.d.ts +28 -0
- package/dist/internal/mcp-host.d.ts.map +1 -0
- package/dist/internal/mcp-host.js +162 -0
- package/dist/internal/net.d.ts +5 -0
- package/dist/internal/net.d.ts.map +1 -0
- package/dist/internal/net.js +30 -0
- package/dist/internal/peer-connections.d.ts +44 -0
- package/dist/internal/peer-connections.d.ts.map +1 -0
- package/dist/internal/peer-connections.js +67 -0
- package/dist/internal/playground/static.d.ts +35 -0
- package/dist/internal/playground/static.d.ts.map +1 -0
- package/dist/internal/playground/static.js +162 -0
- package/dist/internal/playground/toolchain.d.ts +57 -0
- package/dist/internal/playground/toolchain.d.ts.map +1 -0
- package/dist/internal/playground/toolchain.js +226 -0
- package/dist/internal/reminder-runner.d.ts +62 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -0
- package/dist/internal/reminder-runner.js +582 -0
- package/dist/internal/reminder-schedule.d.ts +22 -0
- package/dist/internal/reminder-schedule.d.ts.map +1 -0
- package/dist/internal/reminder-schedule.js +82 -0
- package/dist/internal/reminder-store.d.ts +58 -0
- package/dist/internal/reminder-store.d.ts.map +1 -0
- package/dist/internal/reminder-store.js +106 -0
- package/dist/internal/resolved-connections.d.ts +41 -0
- package/dist/internal/resolved-connections.d.ts.map +1 -0
- package/dist/internal/resolved-connections.js +73 -0
- package/dist/internal/review-comments.d.ts +50 -0
- package/dist/internal/review-comments.d.ts.map +1 -0
- package/dist/internal/review-comments.js +194 -0
- package/dist/internal/router.d.ts +33 -0
- package/dist/internal/router.d.ts.map +1 -0
- package/dist/internal/router.js +93 -0
- package/dist/internal/run-client.d.ts +49 -0
- package/dist/internal/run-client.d.ts.map +1 -0
- package/dist/internal/run-client.js +208 -0
- package/dist/internal/schedule-runner.d.ts +31 -0
- package/dist/internal/schedule-runner.d.ts.map +1 -0
- package/dist/internal/schedule-runner.js +126 -0
- package/dist/internal/sdk-runner.d.ts +41 -0
- package/dist/internal/sdk-runner.d.ts.map +1 -0
- package/dist/internal/sdk-runner.js +221 -0
- package/dist/internal/server.d.ts +25 -0
- package/dist/internal/server.d.ts.map +1 -0
- package/dist/internal/server.js +1374 -0
- package/dist/internal/session-engine.d.ts +287 -0
- package/dist/internal/session-engine.d.ts.map +1 -0
- package/dist/internal/session-engine.js +1377 -0
- package/dist/internal/session-store.d.ts +29 -0
- package/dist/internal/session-store.d.ts.map +1 -0
- package/dist/internal/session-store.js +140 -0
- package/dist/internal/session-urls.d.ts +10 -0
- package/dist/internal/session-urls.d.ts.map +1 -0
- package/dist/internal/session-urls.js +25 -0
- package/dist/internal/stream-progress.d.ts +14 -0
- package/dist/internal/stream-progress.d.ts.map +1 -0
- package/dist/internal/stream-progress.js +195 -0
- package/dist/internal/tool-result.d.ts +20 -0
- package/dist/internal/tool-result.d.ts.map +1 -0
- package/dist/internal/tool-result.js +45 -0
- package/dist/internal/trajectory.d.ts +56 -0
- package/dist/internal/trajectory.d.ts.map +1 -0
- package/dist/internal/trajectory.js +248 -0
- package/dist/internal/workspace.d.ts +42 -0
- package/dist/internal/workspace.d.ts.map +1 -0
- package/dist/internal/workspace.js +199 -0
- package/dist/playground/assets/cursor-icons-outline-oY2V_mvK.woff2 +0 -0
- package/dist/playground/assets/index-1K-hG-7p.css +1 -0
- package/dist/playground/assets/index-FlWjhg3x.js +79 -0
- package/dist/playground/index.html +17 -0
- package/dist/reminders.d.ts +23 -0
- package/dist/reminders.d.ts.map +1 -0
- package/dist/reminders.js +22 -0
- package/dist/schedules.d.ts +23 -0
- package/dist/schedules.d.ts.map +1 -0
- package/dist/schedules.js +26 -0
- package/dist/skills.d.ts +22 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +22 -0
- package/dist/tools.d.ts +92 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +68 -0
- package/dist/types.d.ts +1609 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +80 -0
- package/docs/README.md +174 -0
- package/docs/ab.md +355 -0
- package/docs/building-with-agents.md +129 -0
- package/docs/concepts.md +177 -0
- package/docs/deployment.md +218 -0
- package/docs/evals.md +383 -0
- package/docs/guides/agent-to-agent.md +118 -0
- package/docs/guides/cloud-runtime.md +122 -0
- package/docs/guides/github.md +172 -0
- package/docs/guides/human-in-the-loop.md +131 -0
- package/docs/guides/slack.md +245 -0
- package/docs/guides/webhooks.md +201 -0
- package/docs/hillclimbing.md +93 -0
- package/docs/quickstart.md +183 -0
- package/docs/reference/agent-config.md +154 -0
- package/docs/reference/channels.md +206 -0
- package/docs/reference/cli.md +257 -0
- package/docs/reference/connections.md +137 -0
- package/docs/reference/hooks.md +74 -0
- package/docs/reference/http-api.md +219 -0
- package/docs/reference/instructions.md +77 -0
- package/docs/reference/playground.md +67 -0
- package/docs/reference/project-layout.md +119 -0
- package/docs/reference/schedules.md +220 -0
- package/docs/reference/sessions.md +165 -0
- package/docs/reference/skills.md +79 -0
- package/docs/reference/subagents.md +74 -0
- package/docs/reference/tools.md +203 -0
- package/docs/scaffolding-agents.md +113 -0
- package/docs/troubleshooting.md +95 -0
- package/package.json +185 -0
- package/skills/ab/SKILL.md +139 -0
- package/skills/create-agent/SKILL.md +219 -0
- package/skills/debug/SKILL.md +71 -0
- package/skills/evals/SKILL.md +217 -0
- package/skills/framework-map/SKILL.md +142 -0
- package/skills/github/SKILL.md +144 -0
- package/skills/hillclimb/SKILL.md +162 -0
- package/skills/setup-slack/SKILL.md +180 -0
- package/src/ab.ts +675 -0
- package/src/bin/agent-serve.ts +949 -0
- package/src/channels/github/api.ts +374 -0
- package/src/channels/github/auth.ts +275 -0
- package/src/channels/github/binding.ts +223 -0
- package/src/channels/github/defaults.ts +111 -0
- package/src/channels/github/events.ts +72 -0
- package/src/channels/github/forward.ts +381 -0
- package/src/channels/github/github-channel.ts +2270 -0
- package/src/channels/github/index.ts +52 -0
- package/src/channels/github/replay.ts +387 -0
- package/src/channels/github/state.ts +95 -0
- package/src/channels/github/types.ts +490 -0
- package/src/channels/slack/api.ts +580 -0
- package/src/channels/slack/approvals.ts +198 -0
- package/src/channels/slack/assistant.ts +76 -0
- package/src/channels/slack/auth.ts +112 -0
- package/src/channels/slack/channel-watch.ts +219 -0
- package/src/channels/slack/constants.ts +30 -0
- package/src/channels/slack/credentials.ts +90 -0
- package/src/channels/slack/cursor-account.ts +166 -0
- package/src/channels/slack/defaults.ts +450 -0
- package/src/channels/slack/dispatch.ts +293 -0
- package/src/channels/slack/doctor.ts +135 -0
- package/src/channels/slack/event-id-dedupe.ts +30 -0
- package/src/channels/slack/inbound.ts +219 -0
- package/src/channels/slack/index.ts +45 -0
- package/src/channels/slack/init.ts +133 -0
- package/src/channels/slack/interactive.ts +194 -0
- package/src/channels/slack/links.ts +23 -0
- package/src/channels/slack/live-delivery.ts +201 -0
- package/src/channels/slack/log.ts +83 -0
- package/src/channels/slack/manifest.ts +179 -0
- package/src/channels/slack/pr-ref.ts +50 -0
- package/src/channels/slack/setup.ts +97 -0
- package/src/channels/slack/slack-channel.ts +374 -0
- package/src/channels/slack/socket-mode.ts +154 -0
- package/src/channels/slack/stream.ts +63 -0
- package/src/channels/slack/tool-approval-events.ts +136 -0
- package/src/channels/slack/types.ts +349 -0
- package/src/channels.ts +385 -0
- package/src/connections.ts +89 -0
- package/src/evals.ts +501 -0
- package/src/hooks.ts +33 -0
- package/src/index.ts +184 -0
- package/src/internal/ab-collector.ts +210 -0
- package/src/internal/ab-fold.ts +228 -0
- package/src/internal/ab-snapshot.ts +335 -0
- package/src/internal/approval-gate.ts +115 -0
- package/src/internal/auth.ts +39 -0
- package/src/internal/authored-alias-hooks.ts +69 -0
- package/src/internal/authored-loaders.ts +138 -0
- package/src/internal/bounded-int.ts +27 -0
- package/src/internal/brand.ts +29 -0
- package/src/internal/chat-client.ts +407 -0
- package/src/internal/cli-ax.ts +474 -0
- package/src/internal/cli-cursor.ts +275 -0
- package/src/internal/cli-github.ts +849 -0
- package/src/internal/cli-slack.ts +175 -0
- package/src/internal/cloud-merge.ts +41 -0
- package/src/internal/cron.ts +78 -0
- package/src/internal/cursor/account-mcp.ts +472 -0
- package/src/internal/cursor/backend-client.ts +614 -0
- package/src/internal/cursor/credentials.ts +401 -0
- package/src/internal/cursor-event-relay.ts +281 -0
- package/src/internal/cursor-relay-core.ts +444 -0
- package/src/internal/cursor-slack-relay.ts +242 -0
- package/src/internal/describe-error.ts +4 -0
- package/src/internal/dev-mode.ts +20 -0
- package/src/internal/discovery.ts +1709 -0
- package/src/internal/distribution.ts +97 -0
- package/src/internal/docs-site.ts +191 -0
- package/src/internal/duration.ts +39 -0
- package/src/internal/eval-run-store.ts +519 -0
- package/src/internal/eval-runner.ts +522 -0
- package/src/internal/event-log.ts +175 -0
- package/src/internal/event-mapper.ts +272 -0
- package/src/internal/frontmatter.ts +77 -0
- package/src/internal/github-fanout.ts +159 -0
- package/src/internal/handleAgentServeTrigger.ts +156 -0
- package/src/internal/host-platforms.ts +144 -0
- package/src/internal/http-channel.ts +546 -0
- package/src/internal/ids.ts +44 -0
- package/src/internal/init-project.ts +165 -0
- package/src/internal/json-dir-store.ts +109 -0
- package/src/internal/json-schema.ts +69 -0
- package/src/internal/log-ring.ts +59 -0
- package/src/internal/map-pool.ts +32 -0
- package/src/internal/mcp-endpoint.ts +518 -0
- package/src/internal/mcp-host.ts +211 -0
- package/src/internal/net.ts +31 -0
- package/src/internal/peer-connections.ts +100 -0
- package/src/internal/playground/static.ts +189 -0
- package/src/internal/playground/toolchain.ts +277 -0
- package/src/internal/reminder-runner.ts +756 -0
- package/src/internal/reminder-schedule.ts +106 -0
- package/src/internal/reminder-store.ts +145 -0
- package/src/internal/resolved-connections.ts +145 -0
- package/src/internal/review-comments.ts +268 -0
- package/src/internal/router.ts +145 -0
- package/src/internal/run-client.ts +320 -0
- package/src/internal/schedule-runner.ts +161 -0
- package/src/internal/sdk-runner.ts +315 -0
- package/src/internal/server.ts +1737 -0
- package/src/internal/session-engine.ts +1810 -0
- package/src/internal/session-store.ts +147 -0
- package/src/internal/session-urls.ts +40 -0
- package/src/internal/stream-progress.ts +254 -0
- package/src/internal/tool-result.ts +54 -0
- package/src/internal/trajectory.ts +306 -0
- package/src/internal/workspace.ts +223 -0
- package/src/reminders.ts +35 -0
- package/src/schedules.ts +37 -0
- package/src/skills.ts +27 -0
- package/src/tools.ts +127 -0
- package/src/types.ts +1848 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-side GitHub + Slack clients shared across tools, channel routes,
|
|
3
|
+
* schedules, and channel packs — same injection pattern as MCP.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { WebClient } from "@slack/web-api";
|
|
7
|
+
import { createGitHubOctokit } from "../channels/github/api.js";
|
|
8
|
+
import {
|
|
9
|
+
ensureGhCliTokenEnv,
|
|
10
|
+
hasGitHubAppCredentials,
|
|
11
|
+
resolveCredentialValue,
|
|
12
|
+
resolveGitHubInstallationId,
|
|
13
|
+
tryResolveGhAuthToken,
|
|
14
|
+
} from "../channels/github/auth.js";
|
|
15
|
+
import { tryResolveBotToken } from "../channels/slack/credentials.js";
|
|
16
|
+
import type { HostGitHubClient, HostSlackClient } from "../types.js";
|
|
17
|
+
|
|
18
|
+
export interface HostPlatforms {
|
|
19
|
+
github: HostGitHubClient;
|
|
20
|
+
slack: HostSlackClient;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* How ambient host GitHub auth was resolved.
|
|
25
|
+
* `app` = GitHub App installation token (preferred in production).
|
|
26
|
+
* `env` / `gh` = local PAT / CLI fallbacks when App creds are unset.
|
|
27
|
+
*/
|
|
28
|
+
export type HostGitHubAuthSource = "app" | "env" | "gh" | "unavailable";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build host platforms from ambient credentials. Prefer App installation
|
|
32
|
+
* auth when configured; otherwise fall back to PAT / `gh auth` for local
|
|
33
|
+
* testing. Webhook-scoped calls should still prefer `ctx.github`.
|
|
34
|
+
*/
|
|
35
|
+
export function createHostPlatforms(): HostPlatforms {
|
|
36
|
+
let octokitPromise: ReturnType<HostGitHubClient["getOctokit"]> | undefined;
|
|
37
|
+
let slackPromise: ReturnType<HostSlackClient["getClient"]> | undefined;
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
github: {
|
|
41
|
+
getOctokit: () => {
|
|
42
|
+
octokitPromise ??= createGitHubOctokit({});
|
|
43
|
+
return octokitPromise;
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
slack: {
|
|
47
|
+
getClient: async () => {
|
|
48
|
+
if (slackPromise === undefined) {
|
|
49
|
+
slackPromise = (async () => {
|
|
50
|
+
const token = await tryResolveBotToken(undefined);
|
|
51
|
+
if (token === undefined) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
"No Slack bot token available (set SLACK_BOT_TOKEN or a channel envPrefix)."
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return new WebClient(token);
|
|
57
|
+
})();
|
|
58
|
+
}
|
|
59
|
+
return slackPromise;
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Detect ambient host GitHub auth without throwing.
|
|
67
|
+
* Order matches {@link createGitHubOctokit}: App installation, then
|
|
68
|
+
* `GITHUB_TOKEN` / `GH_TOKEN`, then `gh auth token`.
|
|
69
|
+
*/
|
|
70
|
+
export async function resolveHostGitHubAuthSource(): Promise<HostGitHubAuthSource> {
|
|
71
|
+
if (
|
|
72
|
+
(await hasGitHubAppCredentials()) &&
|
|
73
|
+
(await resolveGitHubInstallationId()) !== undefined
|
|
74
|
+
) {
|
|
75
|
+
return "app";
|
|
76
|
+
}
|
|
77
|
+
const fromEnv =
|
|
78
|
+
(await resolveCredentialValue(process.env.GITHUB_TOKEN)) ??
|
|
79
|
+
(await resolveCredentialValue(process.env.GH_TOKEN));
|
|
80
|
+
if (fromEnv !== undefined) {
|
|
81
|
+
return "env";
|
|
82
|
+
}
|
|
83
|
+
const fromGh = await tryResolveGhAuthToken();
|
|
84
|
+
return fromGh === undefined ? "unavailable" : "gh";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Soft boot-time GitHub auth check: log the resolved source and optionally
|
|
89
|
+
* prime `github.getOctokit()` so the first request does not pay CLI latency.
|
|
90
|
+
* When auth is App-backed, also export an installation token as `GH_TOKEN`
|
|
91
|
+
* so tools that shell out to `gh` (a host-side `prepare_pr` tool, say)
|
|
92
|
+
* authenticate on corp hosts that have no PAT / `gh
|
|
93
|
+
* auth login`. Never fails serve — missing auth is logged as a warning.
|
|
94
|
+
*/
|
|
95
|
+
export async function warmupHostGitHubAuth(options: {
|
|
96
|
+
logger: (line: string) => void;
|
|
97
|
+
github?: HostGitHubClient;
|
|
98
|
+
}): Promise<HostGitHubAuthSource> {
|
|
99
|
+
const source = await resolveHostGitHubAuthSource();
|
|
100
|
+
if (source === "unavailable") {
|
|
101
|
+
options.logger(
|
|
102
|
+
"[agent-serve] GitHub auth: unavailable (set GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY + GITHUB_APP_INSTALLATION_ID, or GITHUB_TOKEN / GH_TOKEN, or run `gh auth login`)"
|
|
103
|
+
);
|
|
104
|
+
return source;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let exportedGhToken = false;
|
|
108
|
+
if (source === "app") {
|
|
109
|
+
try {
|
|
110
|
+
exportedGhToken = await ensureGhCliTokenEnv();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
options.logger(
|
|
113
|
+
`[agent-serve] GitHub auth: failed to export GH_TOKEN for gh CLI: ${
|
|
114
|
+
error instanceof Error ? error.message : String(error)
|
|
115
|
+
}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const label =
|
|
121
|
+
source === "app"
|
|
122
|
+
? exportedGhToken
|
|
123
|
+
? "GitHub App installation token (also exported as GH_TOKEN for gh CLI)"
|
|
124
|
+
: "GitHub App installation token"
|
|
125
|
+
: source === "env"
|
|
126
|
+
? "GITHUB_TOKEN/GH_TOKEN"
|
|
127
|
+
: "gh auth token";
|
|
128
|
+
if (options.github === undefined) {
|
|
129
|
+
options.logger(`[agent-serve] GitHub auth: ${label}`);
|
|
130
|
+
return source;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
await options.github.getOctokit();
|
|
135
|
+
options.logger(`[agent-serve] GitHub auth: ${label}`);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
options.logger(
|
|
138
|
+
`[agent-serve] GitHub auth: ${label} resolved but Octokit warmup failed: ${
|
|
139
|
+
error instanceof Error ? error.message : String(error)
|
|
140
|
+
}`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
return source;
|
|
144
|
+
}
|
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The built-in HTTP session channel: the default API that `curl`, SDK
|
|
3
|
+
* clients, and frontends talk to. Mounted at `/v1/session*` and enabled even
|
|
4
|
+
* when `agent/channels/http.ts` does not exist; author that file with
|
|
5
|
+
* `httpChannel({ ... })` to override auth or observe events.
|
|
6
|
+
*
|
|
7
|
+
* Continuation semantics: `POST /v1/session` returns a `continuationToken`;
|
|
8
|
+
* each accepted follow-up rotates it and returns the replacement, and a
|
|
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
|
+
* that session's channel + key; task sessions stay fire-and-forget.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
AuthContext,
|
|
16
|
+
AuthPolicy,
|
|
17
|
+
HttpChannelDefinition,
|
|
18
|
+
JsonValue,
|
|
19
|
+
SessionRecord,
|
|
20
|
+
} from "../types.js";
|
|
21
|
+
import { samePrincipal } from "./auth.js";
|
|
22
|
+
import {
|
|
23
|
+
formatContinuationToken,
|
|
24
|
+
newContinuationKey,
|
|
25
|
+
parseContinuationToken,
|
|
26
|
+
} from "./ids.js";
|
|
27
|
+
import { isLoopbackAddress } from "./net.js";
|
|
28
|
+
import type { ServerRoute } from "./router.js";
|
|
29
|
+
import {
|
|
30
|
+
ApprovalInterruptedError,
|
|
31
|
+
ApprovalNotFoundError,
|
|
32
|
+
HTTP_CHANNEL_ID,
|
|
33
|
+
SessionAuthError,
|
|
34
|
+
SessionBusyError,
|
|
35
|
+
type SessionEngine,
|
|
36
|
+
} from "./session-engine.js";
|
|
37
|
+
import {
|
|
38
|
+
eventsUrlForSession,
|
|
39
|
+
playgroundUrlForSession,
|
|
40
|
+
} from "./session-urls.js";
|
|
41
|
+
|
|
42
|
+
const SESSION_ID_HEADER = "x-agent-serve-session-id";
|
|
43
|
+
|
|
44
|
+
export function buildHttpChannelRoutes(args: {
|
|
45
|
+
engine: SessionEngine;
|
|
46
|
+
config: HttpChannelDefinition;
|
|
47
|
+
auth: AuthPolicy[];
|
|
48
|
+
/** Path prefix ("" single-agent, "/<slug>" multi-agent). */
|
|
49
|
+
basePath?: string;
|
|
50
|
+
/**
|
|
51
|
+
* When true (server `--dev` without bearer/custom auth), session
|
|
52
|
+
* stream/events/follow-up are readable without matching the creating
|
|
53
|
+
* principal — matching `GET /v1/sessions` includeAll so the playground
|
|
54
|
+
* can open every listed session. Still requires a loopback caller unless
|
|
55
|
+
* {@link relaxSessionReadAuthBeyondLoopback} is also set.
|
|
56
|
+
*/
|
|
57
|
+
relaxSessionReadAuth?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* With {@link relaxSessionReadAuth}, skip the loopback IP check so remote
|
|
60
|
+
* callers (e.g. Tailscale + `--allow-anonymous`) can open listed sessions.
|
|
61
|
+
*/
|
|
62
|
+
relaxSessionReadAuthBeyondLoopback?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* `--dev` bridge: allow playground / HTTP callers to Approve/Deny parked
|
|
65
|
+
* tools on Slack-owned sessions (Slack principals never match local /
|
|
66
|
+
* anonymous auth). Does not open approval writes on HTTP-owned sessions.
|
|
67
|
+
* Respects the same loopback / beyondLoopback gate as session reads.
|
|
68
|
+
*/
|
|
69
|
+
relaxSessionApprovalAuth?: boolean;
|
|
70
|
+
}): ServerRoute[] {
|
|
71
|
+
const { engine, config, auth } = args;
|
|
72
|
+
const base = args.basePath ?? "";
|
|
73
|
+
const relaxSessionReadAuth = args.relaxSessionReadAuth ?? false;
|
|
74
|
+
const relaxSessionReadAuthBeyondLoopback =
|
|
75
|
+
args.relaxSessionReadAuthBeyondLoopback ?? false;
|
|
76
|
+
const relaxSessionApprovalAuth = args.relaxSessionApprovalAuth ?? false;
|
|
77
|
+
|
|
78
|
+
const transformMessage = async (
|
|
79
|
+
message: string,
|
|
80
|
+
authContext: AuthContext | null
|
|
81
|
+
): Promise<string> => {
|
|
82
|
+
if (config.onMessage === undefined) {
|
|
83
|
+
return message;
|
|
84
|
+
}
|
|
85
|
+
return config.onMessage(message, { auth: authContext });
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const createSession: ServerRoute = {
|
|
89
|
+
method: "POST",
|
|
90
|
+
pattern: `${base}/v1/session`,
|
|
91
|
+
auth,
|
|
92
|
+
handler: async (request, ctx) => {
|
|
93
|
+
const body = await readJsonObject(request);
|
|
94
|
+
if (body === undefined || typeof body.message !== "string") {
|
|
95
|
+
return errorResponse(
|
|
96
|
+
400,
|
|
97
|
+
"invalid_request",
|
|
98
|
+
"Expected a JSON body with a string `message`."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
const message = await transformMessage(body.message, ctx.auth);
|
|
102
|
+
const workspaceFiles = readWorkspaceFiles(body.workspaceFiles);
|
|
103
|
+
const session = await engine.send(HTTP_CHANNEL_ID, message, {
|
|
104
|
+
auth: ctx.auth,
|
|
105
|
+
...(body.state === undefined ? {} : { state: body.state as JsonValue }),
|
|
106
|
+
...(typeof body.title === "string" ? { title: body.title } : {}),
|
|
107
|
+
...(body.purpose === "eval" ? { purpose: "eval" as const } : {}),
|
|
108
|
+
...(workspaceFiles === undefined ? {} : { workspaceFiles }),
|
|
109
|
+
});
|
|
110
|
+
return jsonResponse(
|
|
111
|
+
{
|
|
112
|
+
ok: true,
|
|
113
|
+
sessionId: session.id,
|
|
114
|
+
continuationToken: formatContinuationToken(
|
|
115
|
+
HTTP_CHANNEL_ID,
|
|
116
|
+
session.continuationToken ?? ""
|
|
117
|
+
),
|
|
118
|
+
playgroundUrl: playgroundUrlForSession(request, base, session.id),
|
|
119
|
+
traceUrl: eventsUrlForSession(request.url, base, session.id),
|
|
120
|
+
},
|
|
121
|
+
{ headers: { [SESSION_ID_HEADER]: session.id } }
|
|
122
|
+
);
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const followUp: ServerRoute = {
|
|
127
|
+
method: "POST",
|
|
128
|
+
pattern: `${base}/v1/session/:sessionId`,
|
|
129
|
+
auth,
|
|
130
|
+
handler: async (request, ctx) => {
|
|
131
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
132
|
+
const record = await engine.sessions.get(sessionId);
|
|
133
|
+
if (record === undefined) {
|
|
134
|
+
return errorResponse(
|
|
135
|
+
404,
|
|
136
|
+
"session_not_found",
|
|
137
|
+
`Unknown session ${sessionId}.`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
// Playground (and other HTTP clients) may follow up on any chat
|
|
141
|
+
// session — including custom channels like `drive` — using that
|
|
142
|
+
// session's own continuation token. Task/schedule sessions stay
|
|
143
|
+
// fire-and-forget.
|
|
144
|
+
if (record.mode === "task") {
|
|
145
|
+
return errorResponse(
|
|
146
|
+
409,
|
|
147
|
+
"session_not_followable",
|
|
148
|
+
"Task sessions are fire-and-forget; they do not accept follow-ups."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
152
|
+
relax: relaxSessionReadAuth,
|
|
153
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
154
|
+
requestIp: ctx.requestIp,
|
|
155
|
+
});
|
|
156
|
+
if (ownership !== undefined) {
|
|
157
|
+
return ownership;
|
|
158
|
+
}
|
|
159
|
+
const body = await readJsonObject(request);
|
|
160
|
+
if (body === undefined || typeof body.message !== "string") {
|
|
161
|
+
return errorResponse(
|
|
162
|
+
400,
|
|
163
|
+
"invalid_request",
|
|
164
|
+
"Expected a JSON body with a string `message`."
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (typeof body.continuationToken !== "string") {
|
|
168
|
+
return errorResponse(
|
|
169
|
+
400,
|
|
170
|
+
"invalid_request",
|
|
171
|
+
"Expected a `continuationToken` from the previous response."
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const presented = parseContinuationToken(body.continuationToken);
|
|
175
|
+
if (
|
|
176
|
+
presented === null ||
|
|
177
|
+
presented.channelId !== record.channelId ||
|
|
178
|
+
record.continuationKey === null ||
|
|
179
|
+
presented.key !== record.continuationKey
|
|
180
|
+
) {
|
|
181
|
+
return errorResponse(
|
|
182
|
+
409,
|
|
183
|
+
"stale_continuation_token",
|
|
184
|
+
"The continuation token does not address this session's active continuation."
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const message = await transformMessage(body.message, ctx.auth);
|
|
189
|
+
try {
|
|
190
|
+
// Continue as the session owner after the HTTP ownership gate so
|
|
191
|
+
// `--dev` relaxed reads can follow up on channel-owned sessions
|
|
192
|
+
// (drive/slack/…) without failing SessionAuthError.
|
|
193
|
+
await engine.send(record.channelId, message, {
|
|
194
|
+
auth: record.auth,
|
|
195
|
+
continuationToken: record.continuationKey,
|
|
196
|
+
});
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (error instanceof SessionBusyError) {
|
|
199
|
+
return errorResponse(
|
|
200
|
+
409,
|
|
201
|
+
"session_busy",
|
|
202
|
+
"A turn is already running; wait for session.waiting before sending a follow-up."
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Rotate only after the message is accepted so a rejected send leaves
|
|
209
|
+
// the caller's token valid for retry.
|
|
210
|
+
const rotated = newContinuationKey();
|
|
211
|
+
await engine.setContinuationToken(sessionId, rotated);
|
|
212
|
+
return jsonResponse(
|
|
213
|
+
{
|
|
214
|
+
ok: true,
|
|
215
|
+
sessionId,
|
|
216
|
+
continuationToken: formatContinuationToken(record.channelId, rotated),
|
|
217
|
+
},
|
|
218
|
+
{ headers: { [SESSION_ID_HEADER]: sessionId } }
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const stream: ServerRoute = {
|
|
224
|
+
method: "GET",
|
|
225
|
+
pattern: `${base}/v1/session/:sessionId/stream`,
|
|
226
|
+
auth,
|
|
227
|
+
handler: async (request, ctx) => {
|
|
228
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
229
|
+
// The stream-and-inspect handle is runtime-owned: sessions started by
|
|
230
|
+
// custom channels or schedules are observable here too when the caller
|
|
231
|
+
// matches the session's stored principal (or `--dev` relax). Follow-ups
|
|
232
|
+
// use the same ownership gate plus the session's continuation token.
|
|
233
|
+
const record = await engine.sessions.get(sessionId);
|
|
234
|
+
if (record === undefined) {
|
|
235
|
+
return errorResponse(
|
|
236
|
+
404,
|
|
237
|
+
"session_not_found",
|
|
238
|
+
`Unknown session ${sessionId}.`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
242
|
+
relax: relaxSessionReadAuth,
|
|
243
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
244
|
+
requestIp: ctx.requestIp,
|
|
245
|
+
});
|
|
246
|
+
if (ownership !== undefined) {
|
|
247
|
+
return ownership;
|
|
248
|
+
}
|
|
249
|
+
const url = new URL(request.url);
|
|
250
|
+
const rawStartIndex = url.searchParams.get("startIndex");
|
|
251
|
+
const startIndex =
|
|
252
|
+
rawStartIndex === null ? 0 : Number.parseInt(rawStartIndex, 10);
|
|
253
|
+
if (Number.isNaN(startIndex) || startIndex < 0) {
|
|
254
|
+
return errorResponse(
|
|
255
|
+
400,
|
|
256
|
+
"invalid_request",
|
|
257
|
+
"startIndex must be a non-negative integer."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
const body = await engine.eventStream(sessionId, startIndex);
|
|
261
|
+
return new Response(body, {
|
|
262
|
+
status: 200,
|
|
263
|
+
headers: {
|
|
264
|
+
"content-type": "application/x-ndjson; charset=utf-8",
|
|
265
|
+
"cache-control": "no-store",
|
|
266
|
+
[SESSION_ID_HEADER]: sessionId,
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
/** One-shot NDJSON (or JSON) dump of the session trace. */
|
|
273
|
+
const events: ServerRoute = {
|
|
274
|
+
method: "GET",
|
|
275
|
+
pattern: `${base}/v1/session/:sessionId/events`,
|
|
276
|
+
auth,
|
|
277
|
+
handler: async (request, ctx) => {
|
|
278
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
279
|
+
const record = await engine.sessions.get(sessionId);
|
|
280
|
+
if (record === undefined) {
|
|
281
|
+
return errorResponse(
|
|
282
|
+
404,
|
|
283
|
+
"session_not_found",
|
|
284
|
+
`Unknown session ${sessionId}.`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
288
|
+
relax: relaxSessionReadAuth,
|
|
289
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
290
|
+
requestIp: ctx.requestIp,
|
|
291
|
+
});
|
|
292
|
+
if (ownership !== undefined) {
|
|
293
|
+
return ownership;
|
|
294
|
+
}
|
|
295
|
+
const url = new URL(request.url);
|
|
296
|
+
const asJson = url.searchParams.get("format") === "json";
|
|
297
|
+
const snapshot = await engine.listEvents(sessionId, 0);
|
|
298
|
+
if (asJson) {
|
|
299
|
+
return jsonResponse({
|
|
300
|
+
sessionId,
|
|
301
|
+
events: snapshot,
|
|
302
|
+
playgroundUrl: playgroundUrlForSession(request, base, sessionId),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
const ndjson = `${snapshot.map((e) => JSON.stringify(e)).join("\n")}${
|
|
306
|
+
snapshot.length > 0 ? "\n" : ""
|
|
307
|
+
}`;
|
|
308
|
+
return new Response(ndjson, {
|
|
309
|
+
status: 200,
|
|
310
|
+
headers: {
|
|
311
|
+
"content-type": "application/x-ndjson; charset=utf-8",
|
|
312
|
+
"cache-control": "no-store",
|
|
313
|
+
"content-disposition": `attachment; filename="${sessionId}.ndjson"`,
|
|
314
|
+
[SESSION_ID_HEADER]: sessionId,
|
|
315
|
+
},
|
|
316
|
+
});
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const listApprovals: ServerRoute = {
|
|
321
|
+
method: "GET",
|
|
322
|
+
pattern: `${base}/v1/session/:sessionId/approvals`,
|
|
323
|
+
auth,
|
|
324
|
+
handler: async (_request, ctx) => {
|
|
325
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
326
|
+
const record = await engine.sessions.get(sessionId);
|
|
327
|
+
if (record === undefined) {
|
|
328
|
+
return errorResponse(
|
|
329
|
+
404,
|
|
330
|
+
"session_not_found",
|
|
331
|
+
`Unknown session ${sessionId}.`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
335
|
+
relax: relaxSessionReadAuth,
|
|
336
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
337
|
+
requestIp: ctx.requestIp,
|
|
338
|
+
});
|
|
339
|
+
if (ownership !== undefined) {
|
|
340
|
+
return ownership;
|
|
341
|
+
}
|
|
342
|
+
const pending = await engine.listPendingApprovals(sessionId);
|
|
343
|
+
return jsonResponse({ ok: true, sessionId, pending });
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const resolveApproval: ServerRoute = {
|
|
348
|
+
method: "POST",
|
|
349
|
+
pattern: `${base}/v1/session/:sessionId/approvals/:callId`,
|
|
350
|
+
auth,
|
|
351
|
+
handler: async (request, ctx) => {
|
|
352
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
353
|
+
const callId = ctx.params.callId ?? "";
|
|
354
|
+
const record = await engine.sessions.get(sessionId);
|
|
355
|
+
if (record === undefined) {
|
|
356
|
+
return errorResponse(
|
|
357
|
+
404,
|
|
358
|
+
"session_not_found",
|
|
359
|
+
`Unknown session ${sessionId}.`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
const bridgeSlackApproval =
|
|
363
|
+
relaxSessionApprovalAuth === true &&
|
|
364
|
+
record.auth?.authenticator === "slack" &&
|
|
365
|
+
(relaxSessionReadAuthBeyondLoopback === true ||
|
|
366
|
+
(typeof ctx.requestIp === "string" &&
|
|
367
|
+
isLoopbackAddress(ctx.requestIp)));
|
|
368
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
369
|
+
// HTTP sessions stay strict. Slack sessions may use the --dev
|
|
370
|
+
// playground bridge (see relaxSessionApprovalAuth).
|
|
371
|
+
relax: bridgeSlackApproval,
|
|
372
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
373
|
+
requestIp: ctx.requestIp,
|
|
374
|
+
});
|
|
375
|
+
if (ownership !== undefined) {
|
|
376
|
+
return ownership;
|
|
377
|
+
}
|
|
378
|
+
const body = await readJsonObject(request);
|
|
379
|
+
const decision = body?.decision;
|
|
380
|
+
if (decision !== "approve" && decision !== "deny") {
|
|
381
|
+
return errorResponse(
|
|
382
|
+
400,
|
|
383
|
+
"invalid_request",
|
|
384
|
+
'Expected a JSON body with `decision`: "approve" | "deny".'
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
const pending = await engine.resolveApproval(
|
|
389
|
+
sessionId,
|
|
390
|
+
callId,
|
|
391
|
+
decision,
|
|
392
|
+
ctx.auth,
|
|
393
|
+
bridgeSlackApproval ? { asSessionOwner: true } : undefined
|
|
394
|
+
);
|
|
395
|
+
return jsonResponse({
|
|
396
|
+
ok: true,
|
|
397
|
+
sessionId,
|
|
398
|
+
callId,
|
|
399
|
+
decision,
|
|
400
|
+
toolName: pending.toolName,
|
|
401
|
+
});
|
|
402
|
+
} catch (error) {
|
|
403
|
+
if (error instanceof ApprovalNotFoundError) {
|
|
404
|
+
return errorResponse(404, "approval_not_found", error.message);
|
|
405
|
+
}
|
|
406
|
+
if (error instanceof ApprovalInterruptedError) {
|
|
407
|
+
return errorResponse(409, "approval_interrupted", error.message);
|
|
408
|
+
}
|
|
409
|
+
if (error instanceof SessionAuthError) {
|
|
410
|
+
return errorResponse(403, "forbidden", error.message);
|
|
411
|
+
}
|
|
412
|
+
throw error;
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const stop: ServerRoute = {
|
|
418
|
+
method: "POST",
|
|
419
|
+
pattern: `${base}/v1/session/:sessionId/stop`,
|
|
420
|
+
auth,
|
|
421
|
+
handler: async (_request, ctx) => {
|
|
422
|
+
const sessionId = ctx.params.sessionId ?? "";
|
|
423
|
+
const record = await engine.sessions.get(sessionId);
|
|
424
|
+
if (record === undefined) {
|
|
425
|
+
return errorResponse(
|
|
426
|
+
404,
|
|
427
|
+
"session_not_found",
|
|
428
|
+
`Unknown session ${sessionId}.`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
const ownership = requireSessionOwner(record, ctx.auth, {
|
|
432
|
+
relax: relaxSessionReadAuth,
|
|
433
|
+
beyondLoopback: relaxSessionReadAuthBeyondLoopback,
|
|
434
|
+
requestIp: ctx.requestIp,
|
|
435
|
+
});
|
|
436
|
+
if (ownership !== undefined) {
|
|
437
|
+
return ownership;
|
|
438
|
+
}
|
|
439
|
+
const interrupted = await engine.interrupt(sessionId);
|
|
440
|
+
return jsonResponse(
|
|
441
|
+
{ ok: true, interrupted },
|
|
442
|
+
{ headers: { [SESSION_ID_HEADER]: sessionId } }
|
|
443
|
+
);
|
|
444
|
+
},
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
return [
|
|
448
|
+
createSession,
|
|
449
|
+
followUp,
|
|
450
|
+
stop,
|
|
451
|
+
stream,
|
|
452
|
+
events,
|
|
453
|
+
listApprovals,
|
|
454
|
+
resolveApproval,
|
|
455
|
+
];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export function requireSessionOwner(
|
|
459
|
+
record: SessionRecord,
|
|
460
|
+
caller: AuthContext | null,
|
|
461
|
+
options?: {
|
|
462
|
+
relax?: boolean;
|
|
463
|
+
beyondLoopback?: boolean;
|
|
464
|
+
requestIp?: string | null;
|
|
465
|
+
}
|
|
466
|
+
): Response | undefined {
|
|
467
|
+
// Dev playground lists every session (`includeAll`); match that by
|
|
468
|
+
// allowing cross-principal read/follow-up. Loopback-only unless
|
|
469
|
+
// `--allow-anonymous` also opted into beyondLoopback.
|
|
470
|
+
const relaxOwnership =
|
|
471
|
+
options?.relax === true &&
|
|
472
|
+
(options.beyondLoopback === true ||
|
|
473
|
+
(typeof options.requestIp === "string" &&
|
|
474
|
+
isLoopbackAddress(options.requestIp)));
|
|
475
|
+
if (relaxOwnership || samePrincipal(record.auth, caller)) {
|
|
476
|
+
return undefined;
|
|
477
|
+
}
|
|
478
|
+
return errorResponse(
|
|
479
|
+
403,
|
|
480
|
+
"forbidden",
|
|
481
|
+
"This session belongs to a different principal."
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export function jsonResponse(
|
|
486
|
+
data: unknown,
|
|
487
|
+
init: { status?: number; headers?: Record<string, string> } = {}
|
|
488
|
+
): Response {
|
|
489
|
+
return new Response(JSON.stringify(data), {
|
|
490
|
+
status: init.status ?? 200,
|
|
491
|
+
headers: {
|
|
492
|
+
"content-type": "application/json; charset=utf-8",
|
|
493
|
+
...init.headers,
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export function errorResponse(
|
|
499
|
+
status: number,
|
|
500
|
+
code: string,
|
|
501
|
+
message: string
|
|
502
|
+
): Response {
|
|
503
|
+
return jsonResponse({ ok: false, error: code, message }, { status });
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function readWorkspaceFiles(
|
|
507
|
+
value: unknown
|
|
508
|
+
): Record<string, string> | undefined {
|
|
509
|
+
if (value === undefined || value === null || typeof value !== "object") {
|
|
510
|
+
return undefined;
|
|
511
|
+
}
|
|
512
|
+
if (Array.isArray(value)) {
|
|
513
|
+
return undefined;
|
|
514
|
+
}
|
|
515
|
+
const files: Record<string, string> = {};
|
|
516
|
+
for (const [path, contents] of Object.entries(
|
|
517
|
+
value as Record<string, unknown>
|
|
518
|
+
)) {
|
|
519
|
+
if (typeof path !== "string" || path.trim() === "") {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
if (typeof contents !== "string") {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
files[path] = contents;
|
|
526
|
+
}
|
|
527
|
+
return Object.keys(files).length === 0 ? undefined : files;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export async function readJsonObject(
|
|
531
|
+
request: Request
|
|
532
|
+
): Promise<Record<string, unknown> | undefined> {
|
|
533
|
+
try {
|
|
534
|
+
const parsed: unknown = await request.json();
|
|
535
|
+
if (
|
|
536
|
+
typeof parsed === "object" &&
|
|
537
|
+
parsed !== null &&
|
|
538
|
+
!Array.isArray(parsed)
|
|
539
|
+
) {
|
|
540
|
+
return parsed as Record<string, unknown>;
|
|
541
|
+
}
|
|
542
|
+
return undefined;
|
|
543
|
+
} catch {
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
}
|