← Public packages
@kentcdodds/sentry-triage
Sentry triage wakes Cole (Grok Bot) per issue: one active wake per repo (lease + queue), loop-safe Discord. Cole may spawn Cursor for isolated repo work.
src/adapt.ts
153 lines · 6.5 KB · TypeScriptimport { listingDefaults, listingSecretNames, readTriageSettings } from "./settings.ts"
function needsSwap(listingOwnerCopy, resolved, listingDefault, stored) {
if (listingOwnerCopy) return false
if (!stored) return true
return resolved === listingDefault
}
/**
* After a community fork, call this first.
* Returns every owner-specific setting and the exact swap steps so you can
* point this copy at your Sentry projects, Discord channel, Cole wake / grok-bot,
* and secrets, then publish.
*
* @example
* import adapt from "kody:@you/sentry-triage/adapt"
* const guide = await adapt()
*/
export default async function adapt() {
const settings = await readTriageSettings()
const stored = (name) => settings.sources[name] === "package-storage"
return {
purpose:
"Swap this forked Sentry triage package onto your Sentry org, Discord channel, Cole wake / grok-bot, and secrets, then publish (and optionally community-publish) your copy.",
doNot: [
"Do not edit source just to change Discord channel, Sentry org, models, or project mappings — use ./settings (package storage).",
"Do not disable or delete the minted Sentry webhook on the listing owner copy.",
"Do not rename Kent default secret names on his copy. A fork creates its own secrets (same names, or rename webhook secretName in package.json after fork).",
"Do not put secret values in chat, prompts, or README.",
"Do not keep Kent Discord channel or Sentry project registry after a fork — those would post to his server and wake Cole on his repos.",
],
ownerSettings: {
discordChannelId: {
storageName: "discordChannelId",
resolved: settings.discordChannelId,
source: settings.sources.discordChannelId,
listingDefault: listingDefaults.discordChannelId,
needsSwap: needsSwap(
settings.listingOwnerCopy,
settings.discordChannelId,
listingDefaults.discordChannelId,
stored("discordChannelId"),
),
},
sentryOrgSlug: {
storageName: "sentryOrgSlug",
resolved: settings.sentryOrgSlug,
source: settings.sources.sentryOrgSlug,
listingDefault: listingDefaults.sentryOrgSlug,
needsSwap: needsSwap(
settings.listingOwnerCopy,
settings.sentryOrgSlug,
listingDefaults.sentryOrgSlug,
stored("sentryOrgSlug"),
),
},
agentModelId: {
storageName: "agentModelId",
resolved: settings.agentModelId,
source: settings.sources.agentModelId,
listingDefault: listingDefaults.agentModelId,
needsSwap: needsSwap(
settings.listingOwnerCopy,
settings.agentModelId,
listingDefaults.agentModelId,
stored("agentModelId"),
),
},
shipAgentModelId: {
storageName: "shipAgentModelId",
resolved: settings.shipAgentModelId,
source: settings.sources.shipAgentModelId,
listingDefault: listingDefaults.shipAgentModelId,
needsSwap: false,
},
projects: {
storageName: "triageProjects",
count: settings.projects.length,
source: settings.sources.projects,
listingDefaultCount: listingDefaults.projects.length,
needsSwap:
!settings.listingOwnerCopy &&
settings.sources.projects !== "package-storage",
slugs: settings.projects.map((project) => project.slug),
},
packages: {
selfPackageName: settings.selfPackageName,
sentryPackageName: settings.sentryPackageName,
cursorPackageName: settings.cursorPackageName,
discordPackageName: settings.discordPackageName,
ownerScope: settings.ownerScope,
note: "Agent prompts import kody:@<self>/sentry-triage and kody:@<scope>/sentry. Set these after a fork so Cole calls YOUR copy.",
},
secrets: {
...listingSecretNames,
note: "Kent live copy keeps these names. A fork either creates user secrets with the same names or, after fork, edits package.json kody.webhooks[0].verification.secretName to match a secret you already have. Helper packages resolve their own secret names from the caller account.",
},
webhook: {
name: "sentry",
export: "./handle-sentry-webhook",
secretName: listingSecretNames.sentryWebhookSecret,
mint: "webhook_url_mint for this package, then set that URL on your Sentry internal integration (issue + Seer events).",
},
},
steps: [
{
id: "intent",
title: "Rewrite README ## Intent",
detail: "Community forks must describe the forking user goal, not the listing author. Keep the section short.",
},
{
id: "settings",
title: "Save your org, Discord channel, models, and projects",
detail: "No code edit required. Invoke ./settings with your Discord snowflake, Sentry org slug, owner package names, and a projects array. Empty projects on a fork skip every inbound issue so a fork cannot wake Cole on Kent repos.",
},
{
id: "secrets",
title: "Create secrets (do not paste values in chat)",
detail: "Default names stay on Kent copy: sentryWebhookSecret, sentryAuthToken, discordBotTokenKentPersonalAutomation, grokBotWakeWebhookUrl. A fork creates those same names or remaps webhook secretName in package.json after the fork.",
},
{
id: "webhook",
title: "Mint the Sentry webhook and point your integration at it",
detail: "Keep the package.json webhook named sentry. Call webhook_url_mint for this package and configure that URL on your Sentry internal integration with issue plus Seer events. Do not disable the listing owner minted webhook.",
},
{
id: "helpers",
title: "Connect Sentry, grok-bot, and Discord helpers",
detail: "Static imports of kody:@kentcdodds/sentry, grok-bot, and discord resolve with YOUR user secrets after a fork. Set sentryPackageName / discordPackageName so Cole prompts import your copies if you forked those too. Mint @kentcdodds/grok-bot wake (or your fork) and store it with ./configure-wake-webhook.",
},
{
id: "jobs",
title: "Keep the jobs",
detail: "reconcile-daily and sweep-stale-awaiting stay declared in package.json. They read projects from package storage.",
},
{
id: "smoke",
title: "Smoke-test on your copy",
detail: "Invoke ./handle-sentry-webhook with kodyDryRun true and a fixture issue in one of your project slugs. Then ./adapt again and confirm needsSwap is false.",
},
{
id: "publish",
title: "Publish your package",
detail: "Git lane: push, then package_publish_external_push. Cross-package imports as kody:@kentcdodds/sentry-triage stay valid on Kent copy.",
},
{
id: "community",
title: "Publish the community listing",
detail: "Call community_publish with this package id after account publish succeeds. Share /@username/sentry-triage.",
},
],
}
}