{"version":3,"file":"index.mjs","names":["Service","layer","defaultLayer","descriptions","make","Destination.DeliveryError","make","Destination.DeliveryError","Destination.notConfigured","layer","Config.Service","Discord.make","Desktop.supported","Desktop.make","Config.defaultLayer","Config.ConfigError","Config.Service","Discord.isWebhookUrl","Desktop.supported","Destination.labels","Destination.names","notificationDescriptions","Destination.names","Registry.Service","Config.defaultLayer","Registry.defaultLayer","Cli.run","pkg.version"],"sources":["../package.json","../src/config.ts","../src/notification.ts","../src/destination/index.ts","../src/destination/desktop.ts","../src/destination/discord.ts","../src/registry.ts","../src/cli/config.ts","../src/notify-request.ts","../src/cli/notify.ts","../src/cli/index.ts","../src/index.ts"],"sourcesContent":["","import {\n\tContext,\n\tEffect,\n\tFileSystem,\n\tLayer,\n\tOption,\n\tPath,\n\tRedacted,\n\tSchema,\n} from 'effect';\nimport type { PlatformError } from 'effect/PlatformError';\n\n// Empty: a Discord incoming webhook URL names the channel and authorises\n// posting to it, so this key is only a presence marker and the URL lives in the\n// owner-only file alone.\nexport const Discord = Schema.Struct({});\n\n// A destination is configured exactly when its key is present, so absence is\n// the single source of truth for \"not set up\".\nexport const File = Schema.Struct({\n\tdesktop: Schema.optional(Schema.Struct({})),\n\tdiscord: Schema.optional(Discord),\n});\n\nexport type File = typeof File.Type;\n\nexport class ConfigError extends Schema.TaggedErrorClass<ConfigError>()(\n\t'ConfigError',\n\t{\n\t\tmessage: Schema.String,\n\t}\n) {}\n\nexport type Error = ConfigError;\n\n// `desktop` is absent because it spawns a local process rather than calling an\n// API, so asking it for a secret is a type error rather than a runtime `none`.\nexport const tokenNames = ['discord'] as const;\n\nexport type TokenName = (typeof tokenNames)[number];\n\nexport interface Interface {\n\treadonly read: () => Effect.Effect<File, ConfigError>;\n\treadonly write: (file: File) => Effect.Effect<void, ConfigError>;\n\t// Prefers `PAGEME_<NAME>_TOKEN` over the stored token, so a secret manager\n\t// can inject it without touching disk.\n\treadonly token: (\n\t\tdestination: TokenName\n\t) => Effect.Effect<Option.Option<Redacted.Redacted<string>>, ConfigError>;\n\treadonly setToken: (\n\t\tdestination: TokenName,\n\t\ttoken: Redacted.Redacted<string>\n\t) => Effect.Effect<void, ConfigError>;\n\treadonly clearToken: (\n\t\tdestination: TokenName\n\t) => Effect.Effect<void, ConfigError>;\n\treadonly path: string;\n}\n\nexport class Service extends Context.Service<Service, Interface>()('Config') {}\n\n// Derived from the destination name rather than listed, so a new destination\n// cannot ship with a config file and no override variable.\nconst variable = (destination: TokenName) =>\n\t`PAGEME_${destination.toUpperCase()}_TOKEN`;\n\n// Owner-only: the directory is 0700 and the token file 0600.\nconst dirMode = 0o700;\nconst fileMode = 0o600;\n\n// A file that is not there is the normal empty state, not a failure.\nconst absent = (error: PlatformError) => error.reason._tag === 'NotFound';\n\nconst fail = (message: string) => (cause: PlatformError) =>\n\tnew ConfigError({ message: `${message}: ${cause.message}` });\n\nexport const layer = (\n\tdir: string\n): Layer.Layer<Service, never, FileSystem.FileSystem | Path.Path> =>\n\tLayer.effect(\n\t\tService,\n\t\tEffect.gen(function* () {\n\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\tconst pathOf = yield* Path.Path;\n\n\t\t\tconst path = pathOf.join(dir, 'config.json');\n\t\t\tconst secret = (destination: TokenName) =>\n\t\t\t\tpathOf.join(dir, `${destination}-token`);\n\t\t\tconst decode = Schema.decodeUnknownEffect(File);\n\n\t\t\t// The directory is not created on write, and 0700 keeps the token\n\t\t\t// unreadable by others even before it is written.\n\t\t\tconst ensure = fs\n\t\t\t\t.makeDirectory(dir, { mode: dirMode, recursive: true })\n\t\t\t\t.pipe(Effect.mapError(fail(`Failed to create ${dir}`)));\n\n\t\t\tconst read = Effect.fn('Config.read')(function* () {\n\t\t\t\t// A missing file means nothing is configured yet, not an error.\n\t\t\t\tconst raw = yield* fs.readFileString(path).pipe(\n\t\t\t\t\tEffect.map((text) => JSON.parse(text) as unknown),\n\t\t\t\t\tEffect.catchIf(absent, () => Effect.succeed({})),\n\t\t\t\t\tEffect.mapError(fail(`Failed to read ${path}`))\n\t\t\t\t);\n\n\t\t\t\treturn yield* decode(raw).pipe(\n\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t(cause) =>\n\t\t\t\t\t\t\tnew ConfigError({\n\t\t\t\t\t\t\t\tmessage: `${path} is not valid pageme config: ${cause.message}`,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tconst write = Effect.fn('Config.write')(function* (file: File) {\n\t\t\t\tyield* ensure;\n\t\t\t\tyield* fs\n\t\t\t\t\t.writeFileString(\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\t`${JSON.stringify(file, null, '\\t')}\\n`\n\t\t\t\t\t)\n\t\t\t\t\t.pipe(Effect.mapError(fail(`Failed to write ${path}`)));\n\t\t\t});\n\n\t\t\tconst token = Effect.fn('Config.token')(function* (\n\t\t\t\tdestination: TokenName\n\t\t\t) {\n\t\t\t\tconst injected = Option.fromNullishOr(\n\t\t\t\t\tprocess.env[variable(destination)]\n\t\t\t\t);\n\t\t\t\tif (Option.isSome(injected))\n\t\t\t\t\treturn Option.some(Redacted.make(injected.value));\n\n\t\t\t\tconst file = secret(destination);\n\t\t\t\tconst stored = yield* fs.readFileString(file).pipe(\n\t\t\t\t\tEffect.map(Option.some),\n\t\t\t\t\tEffect.catchIf(absent, () =>\n\t\t\t\t\t\tEffect.succeed(Option.none<string>())\n\t\t\t\t\t),\n\t\t\t\t\tEffect.mapError(fail(`Failed to read ${file}`))\n\t\t\t\t);\n\n\t\t\t\treturn stored.pipe(\n\t\t\t\t\tOption.map((value) => Redacted.make(value.trim()))\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tconst setToken = Effect.fn('Config.setToken')(function* (\n\t\t\t\tdestination: TokenName,\n\t\t\t\tvalue: Redacted.Redacted<string>\n\t\t\t) {\n\t\t\t\tyield* ensure;\n\t\t\t\tconst file = secret(destination);\n\t\t\t\t// `mode` applies only when the file is created, so remove any\n\t\t\t\t// existing one rather than inherit its permissions.\n\t\t\t\tyield* fs\n\t\t\t\t\t.remove(file, { force: true })\n\t\t\t\t\t.pipe(\n\t\t\t\t\t\tEffect.andThen(\n\t\t\t\t\t\t\tfs.writeFileString(\n\t\t\t\t\t\t\t\tfile,\n\t\t\t\t\t\t\t\t`${Redacted.value(value)}\\n`,\n\t\t\t\t\t\t\t\t{ mode: fileMode }\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t),\n\t\t\t\t\t\tEffect.mapError(fail(`Failed to write ${file}`))\n\t\t\t\t\t);\n\t\t\t});\n\n\t\t\tconst clearToken = Effect.fn('Config.clearToken')(function* (\n\t\t\t\tdestination: TokenName\n\t\t\t) {\n\t\t\t\tconst file = secret(destination);\n\t\t\t\tyield* fs\n\t\t\t\t\t.remove(file, { force: true })\n\t\t\t\t\t.pipe(Effect.mapError(fail(`Failed to delete ${file}`)));\n\t\t\t});\n\n\t\t\treturn { clearToken, path, read, setToken, token, write };\n\t\t})\n\t);\n\nexport const defaultLayer = layer(\n\t`${process.env.XDG_CONFIG_HOME ?? `${process.env.HOME}/.config`}/pageme`\n);\n\n// oxlint-disable-next-line no-barrel-file -- self-reexport gives namespace ergonomics without `namespace`; nothing beyond this module is re-exported\nexport * as Config from './config.ts';\n","import { Schema } from 'effect';\n\nexport const descriptions = {\n\tagent: 'Which agent you are. Shown as the notification title so the user knows who paged them.',\n\tlevel: 'Urgency of the notification.',\n\tmessage: 'Notification body, max 2000 characters.',\n} as const;\n\nexport const Level = Schema.Literals([\n\t'info',\n\t'completed',\n\t'failed',\n\t'action_required',\n]).annotate({ description: descriptions.level });\n\nexport type Level = typeof Level.Type;\n\n// A fixed set rather than free text: left open, \"claude\", \"Claude\" and\n// \"claude-code\" would arrive as different senders for the same agent.\nexport const Agent = Schema.Literals([\n\t'claude',\n\t'codex',\n\t'grok',\n\t'pi',\n]).annotate({ description: descriptions.agent });\n\nexport type Agent = typeof Agent.Type;\n\n// Kept apart from the wire value so the displayed name can be corrected\n// (\"Claude Code\" rather than \"claude\") without changing what callers pass.\nexport const agents: Record<Agent, string> = {\n\tclaude: 'Claude Code',\n\tcodex: 'Codex',\n\tgrok: 'Grok',\n\tpi: 'Pi',\n};\n\nexport const Message = Schema.String.annotate({\n\tdescription: descriptions.message,\n}).check(Schema.isNonEmpty(), Schema.isMaxLength(2000));\n\nexport const Notification = Schema.Struct({\n\tagent: Agent,\n\tlevel: Level,\n\tmessage: Message,\n});\n\nexport type Notification = typeof Notification.Type;\n","import type { Effect } from 'effect';\nimport { Schema } from 'effect';\n\nimport type { Notification } from '../notification.ts';\n\n// The agent picks one by name, so these strings are part of what the CLI accepts.\nexport const Name = Schema.Literals(['discord', 'desktop']);\n\nexport type Name = typeof Name.Type;\n\nexport const names: readonly Name[] = ['discord', 'desktop'];\n\nexport const labels: Record<Name, string> = {\n\tdesktop: 'macOS Notification Center on this machine',\n\tdiscord: 'Discord message to your channel',\n};\n\nconst titles: Record<Name, string> = {\n\tdesktop: 'Desktop notifications',\n\tdiscord: 'Discord',\n};\n\nexport class DeliveryError extends Schema.TaggedErrorClass<DeliveryError>()(\n\t'DeliveryError',\n\t{\n\t\tdestination: Name,\n\t\tmessage: Schema.String,\n\t}\n) {}\n\n// Carries the destinations that *are* available so the agent can retry against\n// one of them rather than guessing.\nexport class NotConfiguredError extends Schema.TaggedErrorClass<NotConfiguredError>()(\n\t'NotConfiguredError',\n\t{\n\t\tavailable: Schema.Array(Name),\n\t\tmessage: Schema.String,\n\t\trequested: Name,\n\t}\n) {}\n\nexport const notConfigured = (\n\trequested: Name,\n\tavailable: readonly Name[]\n): NotConfiguredError =>\n\tnew NotConfiguredError({\n\t\tavailable,\n\t\tmessage:\n\t\t\tavailable.length === 0\n\t\t\t\t? `${titles[requested]} is not configured. Set it up with \\`pageme config add ${requested}\\`, then retry.`\n\t\t\t\t: `${titles[requested]} is not configured. Configured destinations: ${available.join(', ')}. Retry with one of those, or set it up with \\`pageme config add ${requested}\\`.`,\n\t\trequested,\n\t});\n\n// No separate \"nothing is configured\" failure: every request names a\n// destination, so an empty setup is a NotConfiguredError with an empty\n// `available` list.\nexport type Error = DeliveryError | NotConfiguredError;\n\n// Each destination builds its own DeliveryError rather than failing loosely for\n// something here to tag: a shared wrapper would have to accept an `unknown`\n// failure, costing every destination its typed error channel.\nexport interface Interface {\n\treadonly send: (\n\t\tnotification: Notification\n\t) => Effect.Effect<void, DeliveryError>;\n}\n\n// oxlint-disable-next-line no-barrel-file -- self-reexport gives namespace ergonomics without `namespace`; nothing beyond this module is re-exported\nexport * as Destination from './index.ts';\n","import { Effect, Stream } from 'effect';\nimport type { ChildProcessSpawner } from 'effect/unstable/process';\nimport { ChildProcess } from 'effect/unstable/process';\n\nimport { agents } from '../notification.ts';\nimport type { Notification } from '../notification.ts';\nimport { Destination } from './index.ts';\n\n// AppleScript reads the fields from argv, so agent-controlled text never has\n// to be escaped into the script source.\nconst script = [\n\t'on run argv',\n\t'display notification (item 2 of argv) with title (item 1 of argv)',\n\t'end run',\n].join('\\n');\n\nexport const make = (\n\tspawner: ChildProcessSpawner.ChildProcessSpawner['Service']\n): Destination.Interface => ({\n\tsend: Effect.fn('Desktop.send')(function* (notification: Notification) {\n\t\tyield* Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst handle = yield* spawner.spawn(\n\t\t\t\t\tChildProcess.make('osascript', [\n\t\t\t\t\t\t'-e',\n\t\t\t\t\t\tscript,\n\t\t\t\t\t\tagents[notification.agent],\n\t\t\t\t\t\tnotification.message,\n\t\t\t\t\t])\n\t\t\t\t);\n\n\t\t\t\t// Drain first: the streams close when the process exits, and\n\t\t\t\t// osascript explains itself on stderr rather than in its code.\n\t\t\t\tconst output = yield* Stream.mkString(\n\t\t\t\t\tStream.decodeText(handle.all)\n\t\t\t\t);\n\t\t\t\tconst code = yield* handle.exitCode;\n\n\t\t\t\tif (code !== 0) {\n\t\t\t\t\treturn yield* new Destination.DeliveryError({\n\t\t\t\t\t\tdestination: 'desktop',\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\toutput.trim() || `osascript exited with ${code}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t).pipe(\n\t\t\t// Spawning and draining fail in the platform's vocabulary; the\n\t\t\t// exit-code path above already speaks ours.\n\t\t\tEffect.mapError((cause) =>\n\t\t\t\tcause instanceof Destination.DeliveryError\n\t\t\t\t\t? cause\n\t\t\t\t\t: new Destination.DeliveryError({\n\t\t\t\t\t\t\tdestination: 'desktop',\n\t\t\t\t\t\t\tmessage: cause.message,\n\t\t\t\t\t\t})\n\t\t\t)\n\t\t);\n\t}),\n});\n\nexport const supported = process.platform === 'darwin';\n\n// oxlint-disable-next-line no-barrel-file -- self-reexport gives namespace ergonomics without `namespace`; nothing beyond this module is re-exported\nexport * as Desktop from './desktop.ts';\n","import { Effect, Redacted } from 'effect';\nimport { HttpClient, HttpClientRequest } from 'effect/unstable/http';\n\nimport { agents } from '../notification.ts';\nimport type { Level, Notification } from '../notification.ts';\nimport { Destination } from './index.ts';\n\nexport interface Options {\n\t// Both the address and the secret: anyone holding it can post to the channel.\n\treadonly url: Redacted.Redacted<string>;\n}\n\n// `discordapp.com` is the legacy host, still handed out by older clients.\nconst prefixes = [\n\t'https://discord.com/api/webhooks/',\n\t'https://discordapp.com/api/webhooks/',\n] as const;\n\n// Checked at configuration time so a typo is caught while the user is still\n// looking at the prompt, rather than at the moment they need to be paged.\nexport const isWebhookUrl = (value: string): boolean =>\n\tprefixes.some((prefix) => value.startsWith(prefix));\n\n// The embed's left bar carries the level: it reads faster than a heading in a\n// busy channel. Discord's own status colours, so they match what users already\n// read as success and danger elsewhere in the client.\nconst colors: Record<Level, number> = {\n\taction_required: 0xfa_a6_1a,\n\tcompleted: 0x57_f2_87,\n\tfailed: 0xed_42_45,\n\tinfo: 0x58_65_f2,\n};\n\n// Overrides whatever the user happened to call the webhook in Discord.\nconst username = 'PageMe';\n\n// Sent as an embed rather than a message body: Discord renders the level as a\n// coloured bar and the agent as the author line, so neither is spelled out in\n// the text. No title (the colour says the level) and no timestamp (Discord\n// stamps every message it receives).\nexport const payload = (notification: Notification) => ({\n\tembeds: [\n\t\t{\n\t\t\tauthor: { name: agents[notification.agent] },\n\t\t\tcolor: colors[notification.level],\n\t\t\tdescription: notification.message,\n\t\t},\n\t],\n\tusername,\n});\n\n// A webhook rather than a bot: posting is the only thing PageMe does, and a\n// webhook needs no application, invite, or gateway connection — nothing to\n// deploy and nothing to keep running.\nexport const make = (\n\toptions: Options,\n\tclient: HttpClient.HttpClient\n): Destination.Interface => ({\n\tsend: Effect.fn('Discord.send')(function* (notification: Notification) {\n\t\tyield* Effect.gen(function* () {\n\t\t\tconst request = yield* HttpClientRequest.post(\n\t\t\t\tRedacted.value(options.url)\n\t\t\t).pipe(HttpClientRequest.bodyJson(payload(notification)));\n\t\t\tconst response = yield* client.execute(request).pipe(\n\t\t\t\t// Effect records the full URL on HTTP spans, but this URL contains\n\t\t\t\t// the webhook credential and must never enter telemetry.\n\t\t\t\tEffect.provideService(HttpClient.TracerDisabledWhen, () => true)\n\t\t\t);\n\n\t\t\tif (response.status >= 200 && response.status < 300) return;\n\n\t\t\t// Discord explains a rejection in the body — a deleted webhook or\n\t\t\t// a bad payload — and the status alone does not.\n\t\t\tconst detail = yield* response.text.pipe(\n\t\t\t\t// The rejection status is still useful if its body cannot be read.\n\t\t\t\tEffect.catch(() => Effect.succeed(''))\n\t\t\t);\n\t\t\treturn yield* new Destination.DeliveryError({\n\t\t\t\tdestination: 'discord',\n\t\t\t\tmessage: `Discord rejected the notification: ${response.status}${detail ? ` — ${detail}` : ''}`,\n\t\t\t});\n\t\t}).pipe(\n\t\t\t// The URL *is* the credential, and HTTP client errors include it.\n\t\t\t// Scrub it before the failure reaches logs or the agent.\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew Destination.DeliveryError({\n\t\t\t\t\t\tdestination: 'discord',\n\t\t\t\t\t\tmessage: cause.message.replaceAll(\n\t\t\t\t\t\t\tRedacted.value(options.url),\n\t\t\t\t\t\t\t'<redacted webhook url>'\n\t\t\t\t\t\t),\n\t\t\t\t\t})\n\t\t\t)\n\t\t);\n\t}),\n});\n\n// oxlint-disable-next-line no-barrel-file -- self-reexport gives namespace ergonomics without `namespace`; nothing beyond this module is re-exported\nexport * as Discord from './discord.ts';\n","import { Context, Effect, Layer, Option } from 'effect';\nimport { HttpClient } from 'effect/unstable/http';\nimport { ChildProcessSpawner } from 'effect/unstable/process';\n\nimport { Config } from './config.ts';\nimport { Desktop } from './destination/desktop.ts';\nimport { Discord } from './destination/discord.ts';\nimport { Destination } from './destination/index.ts';\nimport type { NotifyRequest } from './notify-request.ts';\n\nexport interface Interface {\n\treadonly available: readonly Destination.Name[];\n\treadonly send: (\n\t\trequest: NotifyRequest\n\t) => Effect.Effect<Destination.Name, Destination.Error>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\n\t'Registry'\n) {}\n\nexport const make = (\n\tentries: readonly (readonly [Destination.Name, Destination.Interface])[]\n): Interface => {\n\tconst destinations = new Map(entries);\n\tconst available = entries.map(([name]) => name);\n\n\tconst send = Effect.fn('Registry.send')(function* (\n\t\trequest: NotifyRequest\n\t): Effect.fn.Return<Destination.Name, Destination.Error> {\n\t\tconst target = destinations.get(request.destination);\n\t\tif (!target) {\n\t\t\treturn yield* Destination.notConfigured(\n\t\t\t\trequest.destination,\n\t\t\t\tavailable\n\t\t\t);\n\t\t}\n\n\t\t// Rebuilt rather than passed through: `destination` has been consumed\n\t\t// by the resolution above, and must not travel below it.\n\t\tyield* target.send({\n\t\t\tagent: request.agent,\n\t\t\tlevel: request.level,\n\t\t\tmessage: request.message,\n\t\t});\n\t\treturn request.destination;\n\t});\n\n\treturn { available, send };\n};\n\nexport const layer = Layer.effect(\n\tService,\n\tEffect.gen(function* () {\n\t\tconst config = yield* Config.Service;\n\t\tconst client = yield* HttpClient.HttpClient;\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n\t\tconst file = yield* config.read();\n\t\tconst discordUrl = yield* config.token('discord');\n\n\t\tconst entries: [Destination.Name, Destination.Interface][] = [];\n\n\t\t// Discord needs both halves: a key in the config file and a stored\n\t\t// webhook URL. Half-configured is not configured.\n\t\tif (file.discord && Option.isSome(discordUrl)) {\n\t\t\tentries.push([\n\t\t\t\t'discord',\n\t\t\t\tDiscord.make({ url: discordUrl.value }, client),\n\t\t\t]);\n\t\t}\n\n\t\tif (file.desktop && Desktop.supported)\n\t\t\tentries.push(['desktop', Desktop.make(spawner)]);\n\n\t\treturn make(entries);\n\t})\n);\n\nexport const defaultLayer = layer.pipe(Layer.provide(Config.defaultLayer));\n\n// oxlint-disable-next-line no-barrel-file -- self-reexport gives namespace ergonomics without `namespace`; nothing beyond this module is re-exported\nexport * as Registry from './registry.ts';\n","import { Console, Effect, Option } from 'effect';\nimport { Argument, Command, Prompt } from 'effect/unstable/cli';\n\nimport { Config } from '../config.ts';\nimport { Desktop } from '../destination/desktop.ts';\nimport { Discord } from '../destination/discord.ts';\nimport { Destination } from '../destination/index.ts';\n\n// The human half of the CLI: interactive, prose written for the user, and\n// changing whenever config storage does. The agent-facing commands live in\n// `./notify.ts`, which shares nothing with this beyond the `Config` service.\n\nconst parse = (name: string) =>\n\tDestination.names.includes(name as Destination.Name)\n\t\t? Effect.succeed(name as Destination.Name)\n\t\t: Effect.fail(\n\t\t\t\tnew Config.ConfigError({\n\t\t\t\t\tmessage: `Unknown destination \"${name}\". Choose one of: ${Destination.names.join(', ')}.`,\n\t\t\t\t})\n\t\t\t);\n\n// One prompt, because a Discord incoming webhook URL is the whole\n// configuration. Prompted as a password: it grants anyone holding it the right\n// to post, so it should not sit in the terminal scrollback.\nconst addDiscord = Effect.gen(function* () {\n\tconst config = yield* Config.Service;\n\n\tconst url = yield* Prompt.run(\n\t\tPrompt.password({\n\t\t\tmessage:\n\t\t\t\t'Discord webhook URL (Channel Settings → Integrations → Webhooks → New Webhook → Copy Webhook URL)',\n\t\t\tvalidate: (value) =>\n\t\t\t\tDiscord.isWebhookUrl(value)\n\t\t\t\t\t? Effect.succeed(value)\n\t\t\t\t\t: Effect.fail(\n\t\t\t\t\t\t\t'That is not a Discord webhook URL. It should start with https://discord.com/api/webhooks/.'\n\t\t\t\t\t\t),\n\t\t})\n\t);\n\n\tyield* config.setToken('discord', url);\n\tconst file = yield* config.read();\n\tyield* config.write({ ...file, discord: {} });\n\tyield* Console.log('✓ Configured discord');\n});\n\nconst addDesktop = Effect.gen(function* () {\n\tif (!Desktop.supported) {\n\t\treturn yield* new Config.ConfigError({\n\t\t\tmessage:\n\t\t\t\t'Desktop notifications need macOS Notification Center, which is not available on this platform.',\n\t\t});\n\t}\n\n\tconst config = yield* Config.Service;\n\tconst file = yield* config.read();\n\tyield* config.write({ ...file, desktop: {} });\n\tyield* Console.log('✓ Configured desktop');\n});\n\nconst add = Command.make(\n\t'add',\n\t{\n\t\tname: Argument.string('destination').pipe(\n\t\t\tArgument.withDescription(\n\t\t\t\t`Destination to configure: ${Destination.names.join(', ')}`\n\t\t\t),\n\t\t\tArgument.optional\n\t\t),\n\t},\n\t({ name }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst chosen = yield* Option.match(name, {\n\t\t\t\tonNone: () =>\n\t\t\t\t\tPrompt.run(\n\t\t\t\t\t\tPrompt.select({\n\t\t\t\t\t\t\tchoices: Destination.names.map((choice) => ({\n\t\t\t\t\t\t\t\tdescription: Destination.labels[choice],\n\t\t\t\t\t\t\t\ttitle: choice,\n\t\t\t\t\t\t\t\tvalue: choice,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\tmessage: 'Which destination?',\n\t\t\t\t\t\t})\n\t\t\t\t\t),\n\t\t\t\tonSome: parse,\n\t\t\t});\n\n\t\t\tconst flows = { desktop: addDesktop, discord: addDiscord };\n\t\t\treturn yield* flows[chosen];\n\t\t})\n).pipe(Command.withDescription('Configure a notification destination'));\n\nconst list = Command.make('list', {}, () =>\n\tEffect.gen(function* () {\n\t\tconst config = yield* Config.Service;\n\t\tconst file = yield* config.read();\n\n\t\tyield* Console.log(`Config: ${config.path}\\n`);\n\n\t\tfor (const name of Destination.names) {\n\t\t\t// A chat destination counts as on only with both halves present,\n\t\t\t// matching what the registry actually builds.\n\t\t\tconst on =\n\t\t\t\tname === 'desktop'\n\t\t\t\t\t? Boolean(file.desktop) && Desktop.supported\n\t\t\t\t\t: Boolean(file[name]) &&\n\t\t\t\t\t\tOption.isSome(yield* config.token(name));\n\t\t\t// No target is printed: Discord's lives inside the webhook URL,\n\t\t\t// which is a secret, and desktop has none.\n\t\t\tyield* Console.log(\n\t\t\t\t`${on ? '✓' : '✗'} ${name} — ${Destination.labels[name]}`\n\t\t\t);\n\t\t}\n\t})\n).pipe(Command.withDescription('Show configured destinations'));\n\nconst rm = Command.make(\n\t'rm',\n\t{\n\t\tname: Argument.string('destination').pipe(\n\t\t\tArgument.withDescription('Destination to remove')\n\t\t),\n\t},\n\t({ name }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst config = yield* Config.Service;\n\t\t\tconst chosen = yield* parse(name);\n\t\t\tconst file = yield* config.read();\n\n\t\t\tif (chosen !== 'desktop') yield* config.clearToken(chosen);\n\n\t\t\tyield* config.write({ ...file, [chosen]: undefined });\n\t\t\tyield* Console.log(`✓ Removed ${chosen}`);\n\t\t})\n).pipe(Command.withDescription('Remove a configured destination'));\n\nexport const config = Command.make('config').pipe(\n\tCommand.withDescription('Manage notification destinations'),\n\tCommand.withSubcommands([add, list, rm])\n);\n","import { Schema } from 'effect';\n\nimport { Destination } from './destination/index.ts';\nimport {\n\tAgent,\n\tdescriptions as notificationDescriptions,\n\tLevel,\n\tMessage,\n} from './notification.ts';\n\nexport const descriptions = {\n\t...notificationDescriptions,\n\tdestination:\n\t\t'Where to deliver. Required: check `destinations` for what is configured, and prefer the one the user named if they named one.',\n} as const;\n\n// `destination` is required rather than defaulted: a silent default is how an\n// agent believes it paged while the message went to a destination the user had\n// stopped watching. The registry consumes it when resolving the target and\n// passes only the notification onwards.\nexport const NotifyRequest = Schema.Struct({\n\tagent: Agent,\n\tdestination: Destination.Name.annotate({\n\t\tdescription: descriptions.destination,\n\t}),\n\tlevel: Level,\n\tmessage: Message,\n});\n\nexport type NotifyRequest = typeof NotifyRequest.Type;\n","import { Console, Effect } from 'effect';\nimport { Command, Flag } from 'effect/unstable/cli';\n\nimport { Destination } from '../destination/index.ts';\nimport { Agent, Level, Message } from '../notification.ts';\nimport { descriptions } from '../notify-request.ts';\nimport { Registry } from '../registry.ts';\n\n// The agent half of the CLI: these two commands are the whole surface an agent\n// touches, and `./config.ts` is the human one. Prose here is written for a\n// model, not for a person.\n\n// Spells `NotifyRequest` as flags and validates them with that struct's own\n// schemas, so what the CLI accepts is defined in one place.\nexport const notify = Command.make(\n\t'notify',\n\t{\n\t\tagent: Flag.choice('agent', Agent.literals).pipe(\n\t\t\tFlag.withDescription(descriptions.agent)\n\t\t),\n\t\tdestination: Flag.choice('destination', Destination.names).pipe(\n\t\t\tFlag.withDescription(descriptions.destination)\n\t\t),\n\t\tlevel: Flag.choice('level', Level.literals).pipe(\n\t\t\tFlag.withDescription(descriptions.level)\n\t\t),\n\t\tmessage: Flag.string('message').pipe(\n\t\t\tFlag.withSchema(Message),\n\t\t\tFlag.withDescription(descriptions.message)\n\t\t),\n\t},\n\t({ agent, destination, level, message }) =>\n\t\tEffect.gen(function* () {\n\t\t\tconst registry = yield* Registry.Service;\n\t\t\tconst sent = yield* registry.send({\n\t\t\t\tagent,\n\t\t\t\tdestination,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t});\n\t\t\t// JSON rather than prose: the reader is an agent, and a\n\t\t\t// machine-readable result is one less thing to parse wrong.\n\t\t\tyield* Console.log(\n\t\t\t\tJSON.stringify({ delivered: true, destination: sent })\n\t\t\t);\n\t\t})\n).pipe(\n\tCommand.withDescription(\n\t\t'Send a notification to the user. Use when you need their input, when an important task fails, or when a long-running task completes. Do not send routine progress updates.'\n\t)\n);\n\n// Written for an agent to parse, not a human: `config list` is the human view\n// of the same state.\nexport const destinations = Command.make('destinations', {}, () =>\n\tEffect.gen(function* () {\n\t\tconst registry = yield* Registry.Service;\n\t\tyield* Console.log(JSON.stringify({ configured: registry.available }));\n\t})\n).pipe(\n\tCommand.withDescription(\n\t\t'Print configured destinations as JSON, for agents to check before promising a destination'\n\t)\n);\n","import { Layer } from 'effect';\nimport { Command } from 'effect/unstable/cli';\n\nimport { Config } from '../config.ts';\nimport { Registry } from '../registry.ts';\nimport { config } from './config.ts';\nimport { destinations, notify } from './notify.ts';\n\nexport const run = Command.make('pageme').pipe(\n\tCommand.withDescription(\n\t\t'Let local coding agents notify you when they need input or finish work.'\n\t),\n\tCommand.withSubcommands([config, destinations, notify])\n);\n\nexport const layer = Layer.mergeAll(Config.defaultLayer, Registry.defaultLayer);\n\n// oxlint-disable-next-line no-barrel-file -- self-reexport gives namespace ergonomics without `namespace`; nothing beyond this module is re-exported\nexport * as Cli from './index.ts';\n","#!/usr/bin/env node\nimport {\n\tNodeHttpClient,\n\tNodeRuntime,\n\tNodeServices,\n} from '@effect/platform-node';\nimport { Effect, Layer } from 'effect';\nimport { Command } from 'effect/unstable/cli';\n\nimport pkg from '../package.json' with { type: 'json' };\nimport { Cli } from './cli/index.ts';\n\n// Every expected failure carries a `message` written for whoever reads it, and\n// becomes stderr plus a non-zero exit — what an agent shelling out observes.\nconst report = (error: { readonly message: string }) =>\n\tEffect.sync(() => {\n\t\tconsole.error(error.message);\n\t\tprocess.exitCode = 1;\n\t});\n\nCommand.run(Cli.run, { version: pkg.version }).pipe(\n\tEffect.catchTags({\n\t\tConfigError: report,\n\t\tDeliveryError: report,\n\t\tNotConfiguredError: report,\n\t}),\n\t// `provideMerge` so the platform services reach both the app's own layers\n\t// and `Command.run`, which needs them for prompts and argument parsing.\n\tEffect.provide(\n\t\tCli.layer.pipe(\n\t\t\tLayer.provideMerge(\n\t\t\t\tLayer.merge(NodeServices.layer, NodeHttpClient.layerUndici)\n\t\t\t)\n\t\t)\n\t),\n\tNodeRuntime.runMain\n);\n"],"mappings":"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"}