postemi 1.0.1 → 1.1.0
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/PROVIDER_SETTINGS.md +183 -7
- package/README.md +51 -5
- package/SKILL.md +83 -30
- package/dist/index.js +389 -29
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
- package/skills/postemi/SKILL.md +1121 -0
- package/skills/postemi-growth/SKILL.md +221 -0
- package/skills/postemi-growth/reference/30-angles.md +74 -0
- package/skills/postemi-growth/reference/review.md +63 -0
- package/skills/postemi-templates/SKILL.md +107 -0
- package/skills/postemi-templates/reference/engagement.md +155 -0
- package/skills/postemi-templates/reference/everyday.md +132 -0
- package/skills/postemi-templates/reference/hook-contrarian.md +227 -0
- package/skills/postemi-templates/reference/hook-growth.md +210 -0
- package/skills/postemi-templates/reference/hook-how-to.md +266 -0
- package/skills/postemi-templates/reference/hook-learning.md +296 -0
- package/skills/postemi-templates/reference/hook-lists.md +195 -0
- package/skills/postemi-templates/reference/hook-stories.md +282 -0
- package/skills/postemi-templates/reference/hook-talk.md +199 -0
- package/skills/postemi-templates/reference/index.md +251 -0
- package/skills/postemi-templates/reference/launch.md +145 -0
- package/skills/postemi-templates/reference/linkedin.md +449 -0
- package/skills/postemi-templates/reference/x.md +139 -0
- package/skills/postemi-writing/SKILL.md +310 -0
- package/skills/postemi-writing/reference/headline-patterns.md +109 -0
- package/skills/postemi-writing/reference/networks.md +113 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/api.ts","../src/brand.ts","../src/commands/auth.ts","../src/settings.ts","../src/output.ts","../src/dates.ts","../src/config.ts","../src/commands/posts.ts","../src/commands/integrations.ts","../src/commands/analytics.ts","../src/commands/upload.ts","../src/commands/config.ts","../src/commands/workspaces.ts","../src/commands/billing.ts"],"sourcesContent":["import yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { createPost, listPosts, deletePost, deletePostGroup, getMissingContent, connectPost, changePostStatus, findSlot } from './commands/posts';\nimport { listIntegrations, listGroups, getIntegrationSettings, triggerIntegrationTool } from './commands/integrations';\nimport { getAnalytics, getPostAnalytics } from './commands/analytics';\nimport { uploadFile, createUploadLink, listUploadLinkFiles } from './commands/upload';\nimport { authLogin, authLogout, authStatus, authSignup } from './commands/auth';\nimport { configSet, configGet } from './commands/config';\nimport { listWorkspaces, useWorkspace, currentWorkspace } from './commands/workspaces';\nimport { billingPlans, billingSubscribe, billingStatus, billingManage } from './commands/billing';\nimport type { Argv } from 'yargs';\nimport { BRAND, envName, writeEnv } from './brand';\n\nyargs(hideBin(process.argv))\n .scriptName(BRAND.cli)\n .usage('$0 <command> [options]')\n .option('workspace', {\n alias: 'w',\n describe:\n `Workspace id this command acts on (overrides \"${BRAND.cli} workspaces:use\" and ${envName('WORKSPACE')})`,\n type: 'string',\n global: true,\n })\n // One place reads the choice (config.ts), so the flag becomes the env var.\n .middleware((argv: any) => {\n if (argv.workspace) {\n writeEnv('WORKSPACE', String(argv.workspace));\n }\n })\n .command(\n 'posts:create',\n 'Create a new post (schedule, draft, or publish now)',\n (yargs: Argv) => {\n return yargs\n .option('content', {\n alias: 'c',\n describe: 'Post/comment content (repeat for a thread: first is the post, the rest are comments)',\n type: 'string',\n })\n .option('media', {\n alias: 'm',\n describe: `Comma-separated media URLs for the corresponding -c (repeatable; URLs must come from \"${BRAND.cli} upload\")`,\n type: 'string',\n })\n .option('integrations', {\n alias: 'i',\n describe: `Comma-separated list of integration IDs (from \"${BRAND.cli} integrations:list\")`,\n type: 'string',\n })\n .option('date', {\n alias: 's',\n describe:\n `Publish date. ALWAYS give ISO 8601 with an explicit offset (\"2026-12-31T12:00:00Z\" / \"+01:00\"), or a datetime without offset (\"2026-12-31 12:00\") together with a timezone (--timezone / ${envName('TIMEZONE')} / ${BRAND.cli} config:set timezone). A naive date with no timezone configured is an error. Required unless --type now or --json.`,\n type: 'string',\n })\n .option('timezone', {\n describe:\n `IANA timezone name (e.g. ${BRAND.exampleTimezone}) used to interpret --date when it has no explicit offset. Numeric offsets are not accepted here — put those in the date string.`,\n type: 'string',\n })\n .option('type', {\n alias: 't',\n describe: 'Post type: \"schedule\" (default), \"draft\", or \"now\" (publish immediately)',\n type: 'string',\n choices: ['schedule', 'draft', 'now'],\n default: 'schedule',\n })\n .option('delay', {\n alias: 'd',\n describe: 'Delay in MINUTES between comments (default: 0)',\n type: 'number',\n default: 0,\n })\n .option('json', {\n alias: 'j',\n describe: 'Path to JSON file with the full post structure (see examples/)',\n type: 'string',\n })\n .option('shortLink', {\n describe: 'Use short links',\n type: 'boolean',\n default: true,\n })\n .option('settings', {\n describe: `Platform-specific settings as JSON string (schema: \"${BRAND.cli} integrations:settings <id>\")`,\n type: 'string',\n })\n .check((argv) => {\n if (!argv.json && !argv.content) {\n throw new Error('Either --content or --json is required');\n }\n if (!argv.json && !argv.integrations) {\n throw new Error('--integrations is required when not using --json');\n }\n if (!argv.json && !argv.date && argv.type !== 'now') {\n throw new Error('--date is required when not using --json (or use --type now to publish immediately)');\n }\n return true;\n })\n .example(\n '$0 posts:create -c \"Hello World!\" -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n 'Simple scheduled post (explicit UTC)'\n )\n .example(\n `$0 posts:create -c \"Merry Christmas! 🎄\" -s \"2026-12-24 18:00\" --timezone ${BRAND.exampleTimezone} -i \"integration-id\"`,\n 'Local wall-clock time with an explicit IANA timezone'\n )\n .example(\n '$0 posts:create -c \"This goes out right now\" -t now -i \"integration-id\"',\n 'Publish immediately (no --date needed)'\n )\n .example(\n '$0 posts:create -c \"Draft post\" -s \"2026-12-31T12:00:00Z\" -t draft -i \"integration-id\"',\n 'Create draft post'\n )\n .example(\n '$0 posts:create -c \"Main post\" -m \"img1.jpg,img2.jpg\" -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n `Post with multiple images (each URL from \"${BRAND.cli} upload\")`\n )\n .example(\n '$0 posts:create -c \"Main post\" -m \"img1.jpg\" -c \"First comment\" -m \"img2.jpg\" -c \"Second comment\" -m \"img3.jpg,img4.jpg\" -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n 'Post with comments, each having their own media'\n )\n .example(\n '$0 posts:create -c \"Thread 1/3\" -c \"Thread 2/3\" -c \"Thread 3/3\" -d 5 -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n 'X (Twitter) thread with 5 minute delay between comments'\n )\n .example(\n '$0 posts:create --json ./post.json',\n 'Complex post from JSON file'\n )\n .example(\n '$0 posts:create -c \"Tweet content\" -s \"2026-12-31T12:00:00Z\" --settings \\'{\"who_can_reply_post\":\"everyone\"}\\' -i \"integration-id\"',\n 'X (Twitter) post with reply settings'\n )\n .example(\n '$0 posts:create -c \"Video description\" -s \"2026-12-31T12:00:00Z\" --settings \\'{\"title\":\"My Video\",\"type\":\"public\"}\\' -i \"youtube-id\"',\n 'YouTube post with title and visibility'\n );\n },\n createPost as any\n )\n .command(\n 'posts:list',\n 'List posts in a date range',\n (yargs: Argv) => {\n return yargs\n .option('startDate', {\n describe: 'Start date (ISO 8601 with explicit offset, or use --timezone). Default: 30 days ago',\n type: 'string',\n })\n .option('endDate', {\n describe: 'End date (ISO 8601 with explicit offset, or use --timezone). Default: 30 days from now',\n type: 'string',\n })\n .option('timezone', {\n describe:\n `IANA timezone name (e.g. ${BRAND.exampleTimezone}) used to interpret --startDate/--endDate when they have no explicit offset`,\n type: 'string',\n })\n .option('customer', {\n describe: 'Customer (group) ID (optional)',\n type: 'string',\n })\n .example('$0 posts:list', 'List posts (last 30 days to next 30 days)')\n .example(\n '$0 posts:list --startDate \"2026-01-01T00:00:00Z\" --endDate \"2026-12-31T23:59:59Z\"',\n 'List posts for a specific date range'\n )\n .example(\n '$0 posts:list --customer \"customer-id\"',\n 'List posts for a specific customer'\n );\n },\n listPosts as any\n )\n .command(\n 'posts:delete <id>',\n 'Delete one post (one channel). Other channels of the same group stay scheduled',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID to delete (the id field of posts:list)',\n type: 'string',\n })\n .example('$0 posts:delete abc123', 'Delete only post abc123, with its thread or comments')\n .epilogue('To delete a post from every channel it went to, use posts:delete-group <group>.');\n },\n deletePost as any\n )\n .command(\n 'posts:delete-group <group>',\n 'Delete a whole group: the post on every channel it went to',\n (yargs: Argv) => {\n return yargs\n .positional('group', {\n describe: 'Group ID (the group field of posts:list)',\n type: 'string',\n })\n .example('$0 posts:delete-group grp_9f8e7d6c', 'Delete every channel of group grp_9f8e7d6c');\n },\n deletePostGroup as any\n )\n .command(\n 'posts:find-slot <id>',\n 'Find the next free publishing slot for an integration',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .example(\n '$0 posts:find-slot integration-123',\n 'Returns {\"date\": \"...\"} — the next free datetime, usable as posts:create --date'\n );\n },\n findSlot as any\n )\n .command(\n 'posts:missing <id>',\n 'List available content from the provider for a post with missing release ID',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .example(\n '$0 posts:missing post-123',\n 'Get available content to connect to a post'\n );\n },\n getMissingContent as any\n )\n .command(\n 'posts:status <id>',\n 'Change a post status between draft and schedule',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .option('status', {\n alias: 's',\n describe: 'New status: \"draft\" or \"schedule\"',\n type: 'string',\n choices: ['draft', 'schedule'],\n demandOption: true,\n })\n .example(\n '$0 posts:status post-123 --status draft',\n 'Move a scheduled post back to draft (stops the running workflow)'\n )\n .example(\n '$0 posts:status post-123 --status schedule',\n 'Schedule a draft post so it is queued for publishing'\n );\n },\n changePostStatus as any\n )\n .command(\n 'posts:connect <id>',\n 'Connect a post to its published content by updating the release ID',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .option('release-id', {\n describe: 'The platform-specific content ID to connect',\n type: 'string',\n demandOption: true,\n })\n .example(\n '$0 posts:connect post-123 --release-id \"7321456789012345678\"',\n 'Connect a post to its published content'\n );\n },\n connectPost as any\n )\n .command(\n 'integrations:list',\n 'List all connected integrations',\n (yargs: Argv) => {\n return yargs\n .option('group', {\n describe: 'Filter integrations by group (customer) ID',\n type: 'string',\n })\n .example('$0 integrations:list', 'List all connected integrations')\n .example(\n '$0 integrations:list --group \"customer-id\"',\n 'List integrations for a specific group'\n );\n },\n listIntegrations as any\n )\n .command(\n 'integrations:groups',\n 'List all groups (customers)',\n {},\n listGroups as any\n )\n .command(\n 'integrations:settings <id>',\n 'Get settings schema, rules, max length and tools for an integration',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .example(\n '$0 integrations:settings youtube-456',\n 'Get settings schema for a YouTube integration'\n )\n .example(\n '$0 integrations:settings instagram-123',\n 'Get settings schema and tools for an Instagram integration'\n );\n },\n getIntegrationSettings as any\n )\n .command(\n 'integrations:trigger <id> <method>',\n 'Trigger an integration tool to fetch additional data',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .positional('method', {\n describe: 'Method name from the \"tools\" array of integrations:settings',\n type: 'string',\n })\n .option('data', {\n alias: 'd',\n describe: 'Data to pass to the tool as JSON string',\n type: 'string',\n })\n .example(\n '$0 integrations:trigger instagram-123 audioSearch -d \\'{\"q\":\"lofi\",\"type\":\"music\"}\\'',\n 'Search Instagram audio for a Reel (the only tool on a supported channel)'\n );\n },\n triggerIntegrationTool as any\n )\n .command(\n 'analytics:platform <id>',\n 'Get analytics for a specific integration/channel',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .option('days', {\n alias: ['d', 'date'],\n describe: 'Number of days to look back (default: 7)',\n type: 'string',\n default: '7',\n })\n .example(\n '$0 analytics:platform integration-123',\n 'Get last 7 days of analytics'\n )\n .example(\n '$0 analytics:platform integration-123 -d 30',\n 'Get last 30 days of analytics'\n );\n },\n getAnalytics as any\n )\n .command(\n 'analytics:post <id>',\n 'Get analytics for a specific post',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .option('days', {\n alias: ['d', 'date'],\n describe: 'Number of days to look back (default: 7)',\n type: 'string',\n default: '7',\n })\n .example(\n '$0 analytics:post post-123',\n 'Get last 7 days of post analytics'\n )\n .example(\n '$0 analytics:post post-123 -d 30',\n 'Get last 30 days of post analytics'\n );\n },\n getPostAnalytics as any\n )\n .command(\n 'upload <file>',\n 'Upload a media file; returns the URL to pass to posts:create -m',\n (yargs: Argv) => {\n return yargs\n .positional('file', {\n describe: 'File path to upload (jpeg/png/gif/webp/avif/bmp/tiff up to 10 MB, mp4 up to 1 GB)',\n type: 'string',\n })\n .example('$0 upload ./image.png', 'Upload an image; use the returned .path in posts:create -m');\n },\n uploadFile as any\n )\n .command(\n 'upload:link',\n 'Get a browser upload link for a file that is not on this machine (e.g. on a phone)',\n (yargs: Argv) => {\n return yargs.example(\n '$0 upload:link',\n 'Returns {id, url, expiresAt}. Show the url to the person; they drop files on it, signed out. Then run upload:files <id>'\n );\n },\n createUploadLink as any\n )\n .command(\n 'upload:files <id>',\n 'List the files that arrived through an upload link; each .path goes to posts:create -m',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: `The id returned by \"${BRAND.cli} upload:link\"`,\n type: 'string',\n })\n .example(\n '$0 upload:files kR3mQ7xP2nLa',\n 'Returns {status, count, files:[{id,name,path,type}]}; status \"empty\" means nothing has arrived yet'\n );\n },\n listUploadLinkFiles as any\n )\n .command(\n 'workspaces:list',\n 'List the workspaces this credential can act on (\"current\" marks the active one)',\n {},\n listWorkspaces as any\n )\n .command(\n 'workspaces:use <id>',\n 'Make every following command act on this workspace',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: `Workspace id, from \"${BRAND.cli} workspaces:list\"`,\n type: 'string',\n })\n .example('$0 workspaces:use 3f2a…', 'Switch the CLI to that workspace');\n },\n useWorkspace as any\n )\n .command(\n 'workspaces:current',\n 'Show the workspace commands act on now',\n {},\n currentWorkspace as any\n )\n .command(\n 'billing:plans',\n 'Show the Postemi plans: prices, limits, the trial rule and the current tier',\n {},\n billingPlans as any\n )\n .command(\n 'billing:subscribe',\n 'Get a Stripe Checkout link for a plan. Nothing is charged; the subscriber opens the link and pays with their own wallet or card',\n (yargs: Argv) => {\n return yargs\n .option('tier', {\n describe: `The plan: ${BRAND.tierList} (see \"${BRAND.cli} billing:plans\")`,\n type: 'string',\n demandOption: true,\n })\n .option('period', {\n describe: 'How often the plan renews',\n type: 'string',\n choices: ['monthly', 'yearly'],\n demandOption: true,\n })\n .option('open', {\n describe: 'Also open the link in this machine\\'s browser',\n type: 'boolean',\n default: false,\n })\n .example(\n '$0 billing:subscribe --tier pro --period yearly',\n 'Print the checkout link as JSON'\n )\n .example(\n '$0 billing:subscribe --tier pro --period yearly --open',\n 'Print it and open it in the browser'\n );\n },\n billingSubscribe as any\n )\n .command(\n 'billing:status',\n 'Show the subscription state (none, trialing, active, past_due, read_only, cancelled) and any unpaid checkout',\n {},\n billingStatus as any\n )\n .command(\n 'billing:manage',\n 'Get a link to the Stripe billing portal (plan change, cancel, invoices, card)',\n (yargs: Argv) => {\n return yargs.option('open', {\n describe: 'Also open the link in this machine\\'s browser',\n type: 'boolean',\n default: false,\n });\n },\n billingManage as any\n )\n .command(\n 'config:set <key> <value>',\n `Save a CLI setting to ~/${BRAND.configDirName}/config.json`,\n (yargs: Argv) => {\n return yargs\n .positional('key', {\n describe: `Setting name. Known: \"timezone\" (an IANA name), \"workspace\" (an id; prefer \"${BRAND.cli} workspaces:use\")`,\n type: 'string',\n })\n .positional('value', {\n describe: 'Setting value',\n type: 'string',\n })\n .example(\n `$0 config:set timezone ${BRAND.exampleTimezone}`,\n `Interpret dates written without an explicit offset in ${BRAND.exampleTimezoneCity} time`\n );\n },\n configSet as any\n )\n .command(\n 'config:get [key]',\n 'Show saved CLI settings (all, or one key)',\n (yargs: Argv) => {\n return yargs\n .positional('key', {\n describe: 'Setting name. Known: \"timezone\"',\n type: 'string',\n })\n .example('$0 config:get', 'Show all saved settings as JSON')\n .example('$0 config:get timezone', 'Show the saved timezone');\n },\n configGet as any\n )\n .command(\n 'auth:login',\n 'Authenticate using the OAuth2 device flow (opens a browser)',\n (yargs: Argv) => {\n return yargs\n .option('auth-server', {\n describe: `Auth server URL (default: ${BRAND.defaultApiUrl})`,\n type: 'string',\n })\n .example(\n '$0 auth:login',\n 'Login via OAuth2 device flow'\n );\n },\n authLogin as any\n )\n .command(\n 'auth:signup',\n `Create a NEW ${BRAND.name} account with a code sent to the e-mail address, and store its key. No free trial: the next step is billing:subscribe`,\n (yargs: Argv) => {\n return yargs\n .option('email', {\n describe: 'E-mail address of the new account; the code is sent there',\n type: 'string',\n demandOption: true,\n })\n .option('code', {\n describe: 'The six-digit code from the e-mail (asked for when omitted on a terminal)',\n type: 'string',\n })\n .option('accept-terms', {\n describe: `The person has read ${BRAND.termsUrl} and ${BRAND.privacyUrl} and agrees`,\n type: 'boolean',\n default: false,\n })\n /*\n NOT --workspace: that is the global flag and takes a workspace ID\n (the middleware above turns it into POSTEMI_WORKSPACE). A name here\n under the same flag would be read as an id by every other command.\n */\n .option('workspace-name', {\n describe: 'Name of the new workspace (default: the part of the address before the @)',\n type: 'string',\n })\n .option('timezone', {\n describe: `The person's IANA timezone for the account, e.g. ${BRAND.exampleTimezone} (default: the one saved by config:set, else the system time zone)`,\n type: 'string',\n })\n .option('language', {\n describe: 'Language of the e-mail and the account',\n type: 'string',\n choices: ['hu', 'en', 'de', 'cs'],\n })\n .option('api-url', {\n describe: `API base URL (default: ${envName('API_URL')}, then ${BRAND.defaultApiUrl})`,\n type: 'string',\n })\n .example(\n '$0 auth:signup --email anna@example.com',\n 'Send the code, then ask for it and for the terms on the terminal'\n )\n .example(\n `$0 auth:signup --email anna@example.com --code 123456 --accept-terms --workspace-name \"Anna's Cafe\"`,\n 'Finish in one run (an agent, after the person read the code and agreed)'\n );\n },\n authSignup as any\n )\n .command(\n 'auth:logout',\n 'Remove stored OAuth2 credentials',\n {},\n authLogout as any\n )\n .command(\n 'auth:status',\n 'Show current authentication status and verify the credentials',\n {},\n authStatus as any\n )\n .demandCommand(1, `Specify a command. Run \"${BRAND.cli} --help\" for the list.`)\n .strict()\n .help()\n .alias('h', 'help')\n .version()\n .alias('v', 'version')\n .wrap(Math.min(110, process.stdout.columns || 110))\n .epilogue(\n `Output contract: results are JSON on stdout; status and errors go to stderr. Every failure exits 1.\\n\\nAuthentication:\\n Device login: ${BRAND.cli} auth:login\\n API Key: export ${envName('API_KEY')}=your_api_key\\n\\nWorkspaces: a credential may reach several. \"${BRAND.cli} workspaces:list\" shows them, \"${BRAND.cli} workspaces:use <id>\" picks the one commands act on (or pass --workspace <id> / ${envName('WORKSPACE')}).\\n\\nDates: ALWAYS pass an explicit offset (\"2026-12-31T12:00:00Z\" / \"+01:00\"), or pass --timezone with an IANA name (e.g. ${BRAND.exampleTimezone}). A date without either is resolved via ${envName('TIMEZONE')}, then the timezone saved by \"${BRAND.cli} config:set timezone\" — and is an ERROR when none of those is set. Numeric offsets are never accepted as timezone values.\\n\\nFor more information, visit: ${BRAND.homepage}`\n )\n .parse();\n","import { randomUUID } from 'crypto';\nimport { BRAND, networkError } from './brand';\n\nexport interface PostemiConfig {\n apiKey: string;\n apiUrl?: string;\n /**\n * The workspace every request is about, sent as the `showorg` header.\n * Required by the API when the key spans several workspaces; harmless when\n * it spans one. See `postemi workspaces:list` / `postemi workspaces:use`.\n */\n workspaceId?: string;\n}\n\n/** `GET /public/v1/workspaces`: what the credential can act on. */\nexport interface Workspace {\n id: string;\n name: string;\n role: string;\n /** True for the workspace this request acted on. */\n current: boolean;\n}\n\n/**\n * The sentence a person should read out of an error body.\n *\n * The API answers with JSON such as `{\"statusCode\":402,\"message\":\"The monthly\n * limit is ...\",\"url\":\"...\"}`, and printing that whole object buried the one\n * line that says what happened and what to do. This takes `message` (joined\n * when Nest sends a list of validation messages), then `msg`, then `detail`,\n * and falls back to the raw body when it is not JSON or has none of them.\n * The raw body stays on `ApiError.body` for anything that needs it.\n */\nexport function serverSentence(body: string): string {\n const raw = (body ?? '').trim();\n let json: any = null;\n try {\n json = JSON.parse(raw);\n } catch {\n return raw;\n }\n const pick = (value: unknown): string | null => {\n if (typeof value === 'string' && value.trim()) return value.trim();\n if (Array.isArray(value)) {\n const parts = value.filter((part) => typeof part === 'string' && part.trim());\n return parts.length ? parts.join('; ') : null;\n }\n return null;\n };\n return pick(json?.message) ?? pick(json?.msg) ?? pick(json?.detail) ?? raw;\n}\n\n/**\n * Thrown for any non-2xx answer from the API. `status` survives so command\n * handlers can say something more useful than the raw body. Only a 401 means\n * the credential was rejected and points at `postemi auth:login`; a 403 is a\n * valid credential that may not do this, and logging in again changes nothing.\n */\nexport class ApiError extends Error {\n constructor(public status: number, public body: string) {\n super(`API Error (${status}): ${serverSentence(body)}`);\n this.name = 'ApiError';\n }\n\n /** The credential itself was rejected (missing, unknown, expired). 401 only. */\n get isAuthError() {\n return this.status === 401;\n }\n\n /**\n * A valid credential that is not allowed to do this: a scoped key on a\n * route that needs a full-workspace one, a role below the payer, a closed\n * registration. The body says which; the fix is never `auth:login`.\n */\n get isForbidden() {\n return this.status === 403;\n }\n\n /** The body as JSON when it is JSON, else null. */\n private get json(): any {\n try {\n return JSON.parse(this.body);\n } catch {\n return null;\n }\n }\n\n /**\n * The 403 of the scope guard: the credential is VALID and lacks a\n * permission. Logging in again changes nothing; a key with the scope\n * (or a higher role for its owner) does. Null for any other answer.\n */\n get missingScope(): { missing: string[]; granted: string[]; role?: string } | null {\n if (this.status !== 403) return null;\n const body = this.json;\n const msg = String(body?.msg ?? body?.message ?? this.body);\n if (!/missing the required permission/i.test(msg)) return null;\n const required: string[] = Array.isArray(body?.required) ? body.required : [];\n const granted: string[] = Array.isArray(body?.granted) ? body.granted : [];\n const fromText = (msg.split(':')[1] || '')\n .split(',')\n .map((scope) => scope.trim())\n .filter(Boolean);\n const missing = required.length\n ? required.filter((scope) => !granted.includes(scope))\n : fromText;\n return { missing, granted, role: body?.role };\n }\n\n /**\n * The 401 of the plan gate: the credential is valid, the workspace has no\n * plan with API access. The billing commands still work.\n */\n get isPlanMissing() {\n return (\n this.status === 401 &&\n /no subscription found|does not include api access|no plan with api access/i.test(\n this.body\n )\n );\n }\n\n get isRateLimit() {\n return this.status === 429;\n }\n\n /**\n * The 403 a multi-workspace key gets when no workspace was named. Not an\n * auth failure: the key is fine, the request is missing a choice, and the\n * fix is `workspaces:use`, not `auth:login`.\n */\n get isWorkspaceChoice() {\n return (\n this.status === 403 && this.body.includes('spans several workspaces')\n );\n }\n}\n\n/** `POST /public/v1/upload-link`: the page to show the person, and its id. */\nexport interface UploadLink {\n id: string;\n url: string;\n expiresAt: string;\n}\n\n/** `GET /public/v1/upload-link/:id`: what arrived through the link so far. */\nexport interface UploadLinkFiles {\n id: string;\n status: 'empty' | 'ready';\n count: number;\n files: Array<{ id: string; name: string; path: string; type: string }>;\n}\n\n/** `GET /public/v1/plans`: the four plans and the workspace's current tier. */\nexport interface Plans {\n currency: string;\n trial: string;\n trialDays: number;\n trialAvailableHere: boolean;\n current: { tier: string; plan: string; slug: string | null };\n plans: Array<{\n tier: string;\n plan: string;\n slug: string;\n monthly: { amount: number; formatted: string };\n yearly: { amount: number; formatted: string; savesPerYear: number };\n limits: Record<string, number | boolean | null>;\n }>;\n}\n\n/** `POST /public/v1/subscriptions/checkout`: the link the PERSON opens. */\nexport interface SubscriptionCheckout {\n status: 'requires_payment';\n checkoutUrl: string;\n checkoutId: string;\n tier: string;\n plan: string;\n period: 'MONTHLY' | 'YEARLY';\n amount: number;\n currency: string;\n trial: boolean;\n trialDays: number;\n expiresAt: string;\n /** False for a plan without API or MCP access (Basic): tell the person before they pay. */\n apiAndMcpAccess?: boolean;\n /** Set when the plan has no API access; the sentence to pass on. */\n note?: string | null;\n}\n\n/** `GET /public/v1/subscription`: where the workspace stands. */\nexport interface SubscriptionState {\n state: 'none' | 'trialing' | 'active' | 'past_due' | 'read_only' | 'cancelled';\n tier: string | null;\n plan: string | null;\n period: 'MONTHLY' | 'YEARLY' | null;\n currentPeriodEnd: string | null;\n cancelAt: string | null;\n payerIsCaller: boolean;\n noPayerYet: boolean;\n pendingCheckout: {\n checkoutId: string;\n checkoutUrl: string;\n plan: string;\n period: string | null;\n startedAt: string;\n expiresAt: string;\n } | null;\n apiAndMcpAccess: boolean;\n}\n\nexport class PostemiAPI {\n private apiKey: string;\n private apiUrl: string;\n private workspaceId?: string;\n\n constructor(config: PostemiConfig) {\n this.apiKey = config.apiKey;\n this.workspaceId = config.workspaceId;\n // `postemi auth:login` stores the base in credentials.json; a key set by\n // hand uses POSTEMI_API_URL (config.ts) or this default.\n this.apiUrl = config.apiUrl || BRAND.defaultApiUrl;\n }\n\n private async request(endpoint: string, options: any = {}) {\n const url = `${this.apiUrl}${endpoint}`;\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: this.apiKey,\n ...this.workspaceHeader(),\n ...options.headers,\n };\n\n let response: Response;\n try {\n response = await fetch(url, {\n ...options,\n headers,\n });\n } catch (error: any) {\n throw new Error(networkError(`Could not reach ${this.apiUrl}`, error));\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new ApiError(response.status, error);\n }\n\n return await response.json();\n }\n\n /**\n * ONE IDEMPOTENCY KEY PER INVOCATION, REUSED ON ITS OWN RETRY.\n *\n * A timeout cannot tell a lost request from a lost answer, and resending a\n * post blindly can publish it twice on a real account. So the post carries\n * an `Idempotency-Key` (a fresh UUID for this command), and the one retry\n * below, after a network failure or a 5xx, sends the SAME key: the server\n * then hands back the post it already created instead of making another.\n */\n async createPost(data: any, idempotencyKey: string = randomUUID()) {\n const send = () =>\n this.request('/public/v1/posts', {\n method: 'POST',\n body: JSON.stringify(data),\n headers: { 'Idempotency-Key': idempotencyKey },\n });\n\n try {\n return await send();\n } catch (error: any) {\n const retryable =\n !(error instanceof ApiError) ||\n [500, 502, 503, 504].includes(error.status);\n if (!retryable) throw error;\n await new Promise((resolve) => setTimeout(resolve, 1500));\n return send();\n }\n }\n\n async listPosts(filters: any = {}) {\n const queryString = new URLSearchParams(\n Object.entries(filters).reduce((acc, [key, value]) => {\n if (value !== undefined && value !== null) {\n acc[key] = String(value);\n }\n return acc;\n }, {} as Record<string, string>)\n ).toString();\n\n const endpoint = queryString\n ? `/public/v1/posts?${queryString}`\n : '/public/v1/posts';\n\n return this.request(endpoint, {\n method: 'GET',\n });\n }\n\n /** One post (one channel) with its thread or comments. Other channels of its group stay. */\n async deletePost(id: string) {\n return this.request(`/public/v1/posts/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n });\n }\n\n /** The whole group: every channel of one multi-channel post. */\n async deletePostGroup(group: string) {\n return this.request(`/public/v1/posts/group/${encodeURIComponent(group)}`, {\n method: 'DELETE',\n });\n }\n\n async findSlot(integrationId: string) {\n return this.request(\n `/public/v1/find-slot/${encodeURIComponent(integrationId)}`,\n {\n method: 'GET',\n }\n );\n }\n\n async upload(file: Buffer, filename: string) {\n const formData = new FormData();\n const extension = filename.split('.').pop()?.toLowerCase() || '';\n\n // The server sniffs magic bytes and accepts exactly eight types; this map\n // only sets the declared Content-Type for the multipart part.\n const mimeTypes: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n avif: 'image/avif',\n bmp: 'image/bmp',\n tif: 'image/tiff',\n tiff: 'image/tiff',\n mp4: 'video/mp4',\n };\n\n const type = mimeTypes[extension] || 'application/octet-stream';\n\n const blob = new Blob([new Uint8Array(file)], { type });\n formData.append('file', blob, filename);\n\n const url = `${this.apiUrl}/public/v1/upload`;\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: this.apiKey,\n ...this.workspaceHeader(),\n },\n });\n } catch (error: any) {\n throw new Error(networkError(`Could not reach ${this.apiUrl}`, error));\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new ApiError(response.status, error);\n }\n\n return await response.json();\n }\n\n private workspaceHeader(): Record<string, string> {\n return this.workspaceId ? { showorg: this.workspaceId } : {};\n }\n\n async listWorkspaces(): Promise<Workspace[]> {\n return (await this.request('/public/v1/workspaces', {\n method: 'GET',\n })) as Workspace[];\n }\n\n async getMissingContent(postId: string) {\n return this.request(`/public/v1/posts/${postId}/missing`, {\n method: 'GET',\n });\n }\n\n async updateReleaseId(postId: string, releaseId: string) {\n return this.request(`/public/v1/posts/${postId}/release-id`, {\n method: 'PUT',\n body: JSON.stringify({ releaseId }),\n });\n }\n\n async changePostStatus(postId: string, status: 'draft' | 'schedule') {\n return this.request(`/public/v1/posts/${postId}/status`, {\n method: 'PUT',\n body: JSON.stringify({ status }),\n });\n }\n\n async getAnalytics(integrationId: string, date: string) {\n return this.request(`/public/v1/analytics/${integrationId}?date=${encodeURIComponent(date)}`, {\n method: 'GET',\n });\n }\n\n async getPostAnalytics(postId: string, date: string) {\n return this.request(`/public/v1/analytics/post/${postId}?date=${encodeURIComponent(date)}`, {\n method: 'GET',\n });\n }\n\n async listIntegrations(group?: string) {\n const query = group ? `?group=${encodeURIComponent(group)}` : '';\n return this.request(`/public/v1/integrations${query}`, {\n method: 'GET',\n });\n }\n\n async listGroups() {\n return this.request('/public/v1/groups', {\n method: 'GET',\n });\n }\n\n async getIntegrationSettings(integrationId: string) {\n return this.request(`/public/v1/integration-settings/${integrationId}`, {\n method: 'GET',\n });\n }\n\n async triggerIntegrationTool(\n integrationId: string,\n methodName: string,\n data: Record<string, string>\n ) {\n return this.request(`/public/v1/integration-trigger/${integrationId}`, {\n method: 'POST',\n body: JSON.stringify({ methodName, data }),\n });\n }\n\n /**\n * A browser upload link for a file this process does not hold. `upload`\n * covers the file on disk; this covers the one on the person's phone.\n */\n async createUploadLink(): Promise<UploadLink> {\n return (await this.request('/public/v1/upload-link', {\n method: 'POST',\n body: JSON.stringify({}),\n })) as UploadLink;\n }\n\n async getUploadLinkFiles(id: string): Promise<UploadLinkFiles> {\n return (await this.request(\n `/public/v1/upload-link/${encodeURIComponent(id)}`,\n { method: 'GET' }\n )) as UploadLinkFiles;\n }\n\n /*\n BILLING. These four answer without the plan gate on the server, so they\n work for a workspace that has no subscription yet: they are how it gets\n one. The checkout and the portal need an OAuth token or a full-workspace\n key (the \"whole workspace\" box on the `auth:login` approval page);\n a scoped key is refused with a sentence that says so.\n */\n\n async getPlans(): Promise<Plans> {\n return (await this.request('/public/v1/plans', { method: 'GET' })) as Plans;\n }\n\n async getSubscription(): Promise<SubscriptionState> {\n return (await this.request('/public/v1/subscription', {\n method: 'GET',\n })) as SubscriptionState;\n }\n\n /** Nothing is charged by this call; the person pays on the returned link. */\n async createSubscriptionCheckout(\n tier: string,\n period: string\n ): Promise<SubscriptionCheckout> {\n return (await this.request('/public/v1/subscriptions/checkout', {\n method: 'POST',\n body: JSON.stringify({ tier, period }),\n })) as SubscriptionCheckout;\n }\n\n async getSubscriptionPortal(): Promise<{ portalUrl: string; note: string }> {\n return (await this.request('/public/v1/subscription/portal', {\n method: 'GET',\n })) as { portalUrl: string; note: string };\n }\n}\n","/**\n * The Postemi values the CLI uses in more than one place: the name a person\n * reads, the command they type, the environment variables, the config\n * folder, the default API host and the links.\n */\n\ninterface Brand {\n /** The product name in a sentence. */\n name: string;\n /** The command a person types. */\n cli: string;\n /** Prefix of the environment variables (`POSTEMI_API_KEY`). */\n envPrefix: string;\n /** Folder under the home directory for credentials.json and config.json. */\n configDirName: string;\n /** API base when nothing else says otherwise. */\n defaultApiUrl: string;\n /** Where `auth:login` starts the device flow. */\n defaultAuthServer: string;\n /** Shown on the approval page. */\n clientName: string;\n homepage: string;\n termsUrl: string;\n privacyUrl: string;\n /** Where a person creates an account in the browser. */\n signupUrl: string;\n /** The IANA zone used in examples. */\n exampleTimezone: string;\n /** \"in London time\" in the config:set example. */\n exampleTimezoneCity: string;\n /** The plan slugs as the help text names them. */\n tierList: string;\n /** The plan without API access, by name. */\n basicPlanName: string;\n}\n\nexport const BRAND: Brand = {\n name: 'Postemi',\n cli: 'postemi',\n envPrefix: 'POSTEMI',\n configDirName: '.postemi',\n // api.postemi.com serves the API at the root (its proxy adds /api).\n defaultApiUrl: 'https://api.postemi.com',\n defaultAuthServer: 'https://api.postemi.com',\n clientName: 'Postemi CLI',\n homepage: 'https://postemi.com',\n termsUrl: 'https://postemi.com/terms',\n privacyUrl: 'https://postemi.com/privacy',\n signupUrl: 'https://postemi.com/app/signup',\n exampleTimezone: 'Europe/London',\n exampleTimezoneCity: 'London',\n tierList: 'basic, pro, creator or team',\n basicPlanName: 'Basic',\n};\n\n/** `API_KEY` -> `POSTEMI_API_KEY`. */\nexport const envName = (name: string): string => `${BRAND.envPrefix}_${name}`;\n\n/** Read `POSTEMI_<name>` from the environment. */\nexport function readEnv(name: string): string | undefined {\n return process.env[envName(name)];\n}\n\n/** Write `POSTEMI_<name>` (the `--workspace` middleware uses it). */\nexport function writeEnv(name: string, value: string): void {\n process.env[envName(name)] = value;\n}\n\n/*\n PLAN NAMES. The CLI shows the plans as Basic, Pro, Creator and Team. The\n API knows `pro` and `creator` by those names but the other two by older\n slugs, so `basic` and `team` are translated before the request. Only these\n display names are mapped.\n*/\nconst TIER_ALIASES: Record<string, string> = {\n basic: 'alap',\n team: 'csapat',\n};\n\nexport function tierForApi(tier: string): string {\n return TIER_ALIASES[tier.trim().toLowerCase()] ?? tier;\n}\n\n/*\n A failed fetch() says only \"fetch failed\"; the reason is in `error.cause`.\n This names it (a host that does not resolve, a refused connection, a\n timeout).\n*/\nconst NETWORK_REASONS: Record<string, string> = {\n ENOTFOUND: 'the host name does not resolve',\n EAI_AGAIN: 'the host name could not be looked up',\n ECONNREFUSED: 'the connection was refused',\n ECONNRESET: 'the connection was reset',\n ETIMEDOUT: 'the connection timed out',\n UND_ERR_CONNECT_TIMEOUT: 'the connection timed out',\n CERT_HAS_EXPIRED: 'the TLS certificate has expired',\n DEPTH_ZERO_SELF_SIGNED_CERT: 'the TLS certificate is self-signed',\n};\n\nexport function networkError(prefix: string, error: any, variable = 'API_URL'): string {\n const plain = `${prefix}: ${error?.message}`;\n const code: string | undefined = error?.cause?.code ?? error?.code;\n const reason = code ? NETWORK_REASONS[code] ?? code : null;\n return reason\n ? `${prefix}: ${reason} (${code}). Check the connection, or point ${envName(variable)} at another server.`\n : plain;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { createInterface } from 'readline';\nimport { getSetting, saveSetting } from '../settings';\nimport { result, status } from '../output';\nimport { assertIanaTimezone } from '../dates';\nimport { ApiError, PostemiAPI, serverSentence, SubscriptionState, Workspace } from '../api';\nimport { getWorkspaceId } from '../config';\nimport { BRAND, envName, networkError, readEnv } from '../brand';\n\nconst CREDENTIALS_DIR = join(homedir(), BRAND.configDirName);\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\n\n/**\n * Where the device flow lives: `POST /device/code`, `POST /device/token`, and\n * an approval page on the web app where the person picks which workspace and\n * channels the key may reach. Override with `POSTEMI_AUTH_SERVER`.\n */\nconst DEFAULT_AUTH_SERVER = BRAND.defaultAuthServer;\n\n/** Used when neither the credentials file nor POSTEMI_API_URL names one. */\nconst DEFAULT_API_URL = BRAND.defaultApiUrl;\n\ninterface StoredCredentials {\n accessToken: string;\n apiUrl: string;\n organizationId?: string;\n}\n\nexport function loadCredentials(): StoredCredentials | null {\n try {\n if (!existsSync(CREDENTIALS_FILE)) return null;\n const data = JSON.parse(readFileSync(CREDENTIALS_FILE, 'utf-8'));\n if (!data.accessToken) return null;\n return data;\n } catch {\n return null;\n }\n}\n\nexport function saveCredentials(credentials: StoredCredentials): void {\n if (!existsSync(CREDENTIALS_DIR)) {\n mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });\n }\n writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { encoding: 'utf-8', mode: 0o600 });\n // Ensure permissions even if file already existed\n chmodSync(CREDENTIALS_FILE, 0o600);\n}\n\nfunction deleteCredentials(): void {\n if (existsSync(CREDENTIALS_FILE)) {\n unlinkSync(CREDENTIALS_FILE);\n }\n}\n\n/*\n SPAWNED WITH THE URL AS AN ARGUMENT, NEVER INTERPOLATED INTO A SHELL STRING.\n\n Never build `open \"${url}\"` for exec(), which runs it through a shell. The\n url is not ours -- it comes from whatever\n POSTEMI_AUTH_SERVER points at -- so a hostile or intercepted auth server could\n close the quote and append a command that runs on the machine of whoever\n typed `postemi auth:login`. Better quoting is not the fix; the shell is.\n\n spawn() with an argv array involves no shell, so the url stays one argument\n whatever it contains. Windows is the exception: `start` is a cmd builtin\n rather than a program, so it needs cmd -- and there the url is passed AS AN\n ARGUMENT to cmd rather than pasted into the command string.\n*/\nexport function openBrowser(url: string): void {\n const { spawn } = require('child_process');\n const opts = { stdio: 'ignore' as const, detached: true };\n\n const child =\n process.platform === 'darwin'\n ? spawn('open', [url], opts)\n : process.platform === 'win32'\n ? spawn('cmd', ['/c', 'start', '', url], opts)\n : spawn('xdg-open', [url], opts);\n\n // A machine with no browser (a server, a container) must not take the login\n // down with it. The url is printed for the user either way.\n child.on('error', () => {});\n child.unref();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction ask(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) =>\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n })\n );\n}\n\n/**\n * One-time scheduling-timezone setup, run after a successful login.\n *\n * Dates written without an explicit offset are refused unless a timezone is\n * configured (see dates.ts), so a fresh login on a TTY is the moment to set\n * one: detect the machine's zone, ask the human to confirm it, save it to\n * `~/.postemi/config.json`. Skipped when a timezone is already saved, and\n * skipped entirely off-TTY — scripts and agents must use `--timezone`,\n * `POSTEMI_TIMEZONE` or `postemi config:set timezone`.\n */\nasync function maybeConfigureTimezone(): Promise<void> {\n if (getSetting('timezone')) return;\n if (!process.stdin.isTTY || !process.stderr.isTTY) return;\n\n const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n const answer = (await ask(`\\nScheduling timezone: ${detected} — OK? [Y/n] `))\n .trim()\n .toLowerCase();\n\n let timezone = detected;\n if (answer === 'n' || answer === 'no') {\n const typed = (\n await ask(`Enter an IANA timezone name (e.g. ${BRAND.exampleTimezone}), or leave empty to skip: `)\n ).trim();\n if (!typed) {\n console.error(\n `Skipped. Dates without an explicit offset will be refused until you run: ${BRAND.cli} config:set timezone <IANA name>`\n );\n return;\n }\n try {\n timezone = assertIanaTimezone(typed, 'auth:login');\n } catch (error: any) {\n console.error(error.message);\n console.error(\n `Skipped. Set it later with: ${BRAND.cli} config:set timezone <IANA name>`\n );\n return;\n }\n } else if (answer && answer !== 'y' && answer !== 'yes') {\n console.error(\n `Skipped. Set it later with: ${BRAND.cli} config:set timezone <IANA name>`\n );\n return;\n }\n\n saveSetting('timezone', timezone);\n console.error(\n `✅ Scheduling timezone saved: ${timezone} (change it with \"${BRAND.cli} config:set timezone <IANA name>\")`\n );\n}\n\n/**\n * Which workspace the new key acts on, decided right after login.\n *\n * The approval page can grant one workspace or all of them. With one there\n * is nothing to ask and the id is stored so `auth:status` can name it. With\n * several the API refuses every request that does not name one, so the\n * choice is made here, on a TTY, and stored; off-TTY the hint says how.\n * Never fatal: a login that worked stays worked.\n */\nasync function chooseWorkspace(creds: StoredCredentials): Promise<void> {\n let workspaces: Workspace[];\n try {\n workspaces = await new PostemiAPI({\n apiKey: creds.accessToken,\n apiUrl: creds.apiUrl,\n }).listWorkspaces();\n } catch {\n return;\n }\n\n if (workspaces.length === 1) {\n saveCredentials({ ...creds, organizationId: workspaces[0].id });\n console.error(`🏢 Workspace: ${workspaces[0].name}`);\n return;\n }\n if (workspaces.length < 2) return;\n\n console.error('\\nThis key reaches several workspaces:');\n workspaces.forEach((w, i) => console.error(` ${i + 1}. ${w.name} (${w.id})`));\n\n if (!process.stdin.isTTY || !process.stderr.isTTY) {\n console.error(\n `Pick one with: ${BRAND.cli} workspaces:use <id> (or pass --workspace <id> on each command)`\n );\n return;\n }\n\n const answer = (await ask(`Work in which one? [1-${workspaces.length}] `)).trim();\n const index = Number(answer) - 1;\n const chosen = workspaces[index];\n if (!chosen) {\n console.error(`Skipped. Pick one later with: ${BRAND.cli} workspaces:use <id>`);\n return;\n }\n saveCredentials({ ...creds, organizationId: chosen.id });\n console.error(`✅ Workspace: ${chosen.name} (change it with \"${BRAND.cli} workspaces:use <id>\")`);\n}\n\nexport async function authLogin(argv: any) {\n const authServer = argv.authServer || readEnv('AUTH_SERVER') || DEFAULT_AUTH_SERVER;\n\n console.log('🔐 Starting device authorization flow...\\n');\n\n // Step 1: Request a device code from the auth server\n let deviceCode: string;\n let userCode: string;\n let verificationUri: string;\n let expiresIn: number;\n let interval: number;\n\n try {\n const response = await fetch(`${authServer}/device/code`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n // Shown on the approval page, so somebody can tell the login they just\n // started from one they did not.\n body: JSON.stringify({\n client_name: readEnv('CLIENT_NAME') || BRAND.clientName,\n // Asks for Postemi's approval page (postemi.com/app/device).\n brand: 'postemi',\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n console.error(`❌ Failed to start authorization (${response.status}): ${error}`);\n process.exit(1);\n }\n\n const data = (await response.json()) as any;\n deviceCode = data.device_code;\n userCode = data.user_code;\n verificationUri = data.verification_uri;\n expiresIn = data.expires_in;\n interval = data.interval || 5;\n } catch (error: any) {\n console.error(`❌ ${networkError(`Could not reach auth server at ${authServer}`, error, 'AUTH_SERVER')}`);\n process.exit(1);\n }\n\n // Step 2: Show the user code and open browser\n console.log(' Your authorization code:\\n');\n console.log(` ┌─────────────────┐`);\n console.log(` │ ${userCode} │`);\n console.log(` └─────────────────┘\\n`);\n console.log(` Open this URL and enter the code above:`);\n console.log(` ${verificationUri}\\n`);\n\n openBrowser(`${verificationUri}?code=${encodeURIComponent(userCode)}`);\n\n console.log(' Waiting for authorization...\\n');\n\n // Step 3: Poll for the token\n const deadline = Date.now() + expiresIn * 1000;\n\n while (Date.now() < deadline) {\n await sleep(interval * 1000);\n\n try {\n const response = await fetch(`${authServer}/device/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ device_code: deviceCode }),\n });\n\n const data = (await response.json()) as any;\n\n if (response.ok && data.access_token) {\n const creds: StoredCredentials = {\n accessToken: data.access_token,\n /*\n The host the login ran on (api.postemi.com), not the `api_url` in\n the token response: the Postemi host is what makes the API answer\n as Postemi.\n */\n apiUrl: String(authServer).replace(/\\/+$/, ''),\n organizationId: data.organization_id,\n };\n saveCredentials(creds);\n\n console.log('✅ Successfully authenticated!');\n console.log(`📁 Credentials saved to ${CREDENTIALS_FILE}`);\n await chooseWorkspace(creds);\n await maybeConfigureTimezone();\n return;\n }\n\n if (data.error === 'authorization_pending') {\n continue;\n }\n\n if (data.error === 'expired_token') {\n console.error('❌ Authorization expired. Please try again.');\n process.exit(1);\n }\n\n // Unknown error\n console.error(`❌ Authorization failed: ${data.error}`);\n process.exit(1);\n } catch {\n // Network error during poll — keep trying\n continue;\n }\n }\n\n console.error('❌ Authorization timed out. Please try again.');\n process.exit(1);\n}\n\nconst TERMS_URL = BRAND.termsUrl;\nconst PRIVACY_URL = BRAND.privacyUrl;\n\n/** POST a JSON body to the unauthenticated sign-up routes. */\nasync function signupRequest(\n apiUrl: string,\n path: string,\n body: Record<string, unknown>\n): Promise<{ status: number; data: any }> {\n const response = await fetch(`${apiUrl}/public/v1${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n const text = await response.text();\n let data: any = text;\n try {\n data = JSON.parse(text);\n } catch {\n // not JSON; keep the text for the error message\n }\n return { status: response.status, data };\n}\n\n/** One shell word: quoted only when it has to be, so the command stays readable. */\nfunction shellWord(value: string): string {\n return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value)\n ? value\n : `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * The person's timezone for the new account: `--timezone`, then the one\n * saved by `config:set`, then this machine's own zone. An agent usually runs\n * on the person's machine, and a workspace without a zone schedules in UTC.\n */\nfunction signupTimezone(argv: any): string | undefined {\n const chosen = argv.timezone || getSetting('timezone');\n if (chosen) return String(chosen);\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The server's refusal as one sentence, whatever shape it came in. */\nfunction refusal(data: any): string {\n if (typeof data === 'string') return data;\n const message = data?.msg ?? data?.message;\n return Array.isArray(message) ? message.join('; ') : String(message ?? JSON.stringify(data));\n}\n\n/**\n * `postemi auth:signup --email <address> [--workspace-name <name>] [--code <code>] [--accept-terms]`\n *\n * CREATES A NEW POSTEMI ACCOUNT for the person at that address, with a code\n * from their mailbox, and stores its key exactly like `auth:login` does\n * (~/.postemi/credentials.json, 0600). The key is never printed.\n *\n * NO FREE TRIAL. An account made this way has no trial and no plan: the key\n * opens only the billing commands until the person pays, so the next step is\n * `postemi billing:plans` and `postemi billing:subscribe`.\n *\n * Two shapes, so both a person at a terminal and an agent without one can\n * drive it:\n * - interactive: one run sends the code, asks for it, asks whether the\n * person agrees to the terms, and finishes;\n * - an agent: the first run (no --code, no TTY) sends the code and prints\n * what to run next; the second run passes --code and --accept-terms,\n * which the agent sends only after the person has read the terms and the\n * privacy notice and agreed.\n */\nexport async function authSignup(argv: any) {\n const email = String(argv.email || '').trim();\n const apiUrl = String(\n argv.apiUrl || readEnv('API_URL') || DEFAULT_API_URL\n ).replace(/\\/+$/, '');\n const language = argv.language ? String(argv.language) : undefined;\n const timezone = signupTimezone(argv);\n const interactive = !!process.stdin.isTTY && !!process.stderr.isTTY;\n\n if (!email.includes('@')) {\n console.error('❌ Give the e-mail address of the new account with --email.');\n process.exit(1);\n }\n\n let code = argv.code ? String(argv.code).trim() : '';\n\n try {\n if (!code) {\n const started = await signupRequest(apiUrl, '/signup/start', {\n email,\n ...(language ? { language } : {}),\n });\n if (started.status !== 202 && started.status !== 200) {\n console.error(\n `❌ Could not send the code (HTTP ${started.status}): ${refusal(started.data)}`\n );\n process.exit(1);\n }\n\n status(`📧 A six-digit code was sent to ${email}. It is valid for 10 minutes.`);\n status(' Accounts created this way have no free trial; a plan is chosen and paid for next.');\n\n if (!interactive) {\n /*\n An agent: the person reads the code back, then the second run.\n EVERY option of this run rides along in the printed command. The\n first version printed only --email, so the second run lost the\n API URL (and hit the wrong server), the language, the workspace\n name and the timezone.\n */\n const nextCommand = [\n `${BRAND.cli} auth:signup`,\n `--email ${shellWord(email)}`,\n '--code <code>',\n '--accept-terms',\n ...(argv.apiUrl ? [`--api-url ${shellWord(apiUrl)}`] : []),\n ...(language ? [`--language ${language}`] : []),\n ...(argv.workspaceName\n ? [`--workspace-name ${shellWord(String(argv.workspaceName))}`]\n : []),\n ...(timezone ? [`--timezone ${shellWord(timezone)}`] : []),\n ].join(' ');\n result({\n codeSent: true,\n email,\n trial: false,\n terms: TERMS_URL,\n privacy: PRIVACY_URL,\n timezone: timezone ?? null,\n language: language ?? null,\n next: `Ask the person for the code, show them ${TERMS_URL} and ${PRIVACY_URL}, and when they agree run: ${nextCommand}`,\n });\n return;\n }\n\n code = (await ask('Code from the e-mail: ')).trim();\n if (!code) {\n console.error('❌ No code given. Run the command again with --code <code>.');\n process.exit(1);\n }\n }\n\n if (!/^[0-9]{6}$/.test(code)) {\n console.error('❌ The code is the six digits from the e-mail.');\n process.exit(1);\n }\n\n status('');\n status('To create the account the person must agree to:');\n status(` Terms of service: ${TERMS_URL}`);\n status(` Privacy notice: ${PRIVACY_URL}`);\n\n let accepted = !!argv.acceptTerms;\n if (!accepted && interactive) {\n const answer = (await ask('Do you agree to both? [y/N] ')).trim().toLowerCase();\n accepted = answer === 'y' || answer === 'yes' || answer === 'i' || answer === 'igen';\n }\n if (!accepted) {\n console.error(\n '❌ No account was created: the terms were not accepted. Show the person the two links above; if they agree, run the command again with --accept-terms.'\n );\n process.exit(1);\n }\n\n const completed = await signupRequest(apiUrl, '/signup/complete', {\n email,\n code,\n acceptTerms: true,\n ...(argv.workspaceName ? { workspaceName: String(argv.workspaceName) } : {}),\n ...(timezone ? { timezone: String(timezone) } : {}),\n ...(language ? { language } : {}),\n });\n\n if (completed.status === 409) {\n console.error(`❌ ${refusal(completed.data)}`);\n console.error(` Sign in instead: ${BRAND.cli} auth:login`);\n process.exit(1);\n }\n if (completed.status !== 201 && completed.status !== 200) {\n console.error(\n `❌ The account was not created (HTTP ${completed.status}): ${refusal(completed.data)}`\n );\n process.exit(1);\n }\n\n const data = completed.data || {};\n if (!data.apiKey) {\n console.error(`❌ The server answered without a key. Sign in with: ${BRAND.cli} auth:login`);\n process.exit(1);\n }\n\n if (loadCredentials()) {\n status('ℹ️ The credentials stored before are replaced by the new account\\'s key.');\n }\n saveCredentials({\n accessToken: data.apiKey,\n apiUrl,\n organizationId: data.workspaceId,\n });\n\n status(`✅ Account created. Workspace: ${data.workspaceName}`);\n status(`📁 Key saved to ${CREDENTIALS_FILE}`);\n status('');\n status('No free trial on this account. Next:');\n status(` ${BRAND.cli} billing:plans`);\n status(` ${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>`);\n status(`The person opens the checkout link and pays. This key then works for every command only on a plan with API access (apiAndMcpAccess: true in billing:plans); ${BRAND.basicPlanName} has none, so say so before the person picks it.`);\n\n result({\n created: true,\n workspaceId: data.workspaceId,\n workspaceName: data.workspaceName,\n trial: false,\n credentials: CREDENTIALS_FILE,\n next: [\n `${BRAND.cli} billing:plans`,\n `${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>`,\n `${BRAND.cli} billing:status`,\n ],\n note: `This key keeps working after the payment only on a plan with apiAndMcpAccess: true in billing:plans. ${BRAND.basicPlanName} has no API access: tell the person before they pay for it.`,\n });\n } catch (error: any) {\n console.error(`❌ ${networkError(`Could not reach the ${BRAND.name} API at ${apiUrl}`, error)}`);\n process.exit(1);\n }\n}\n\nexport async function authLogout() {\n const creds = loadCredentials();\n if (!creds) {\n console.log('ℹ️ No stored credentials found.');\n return;\n }\n\n deleteCredentials();\n console.log('✅ Credentials removed.');\n}\n\n/**\n * Report who we are authenticated as, and whether those credentials still work.\n *\n * OBEYS THE OUTPUT CONTRACT, which it used to break in both directions: it\n * printed its human report to STDOUT and returned 0 even when the credentials\n * were invalid. SKILL.md tells an agent to run this first and pipe it to `jq`,\n * so the emoji went straight into the parser, and a caller that checked the\n * exit code was told \"fine\" about an expired token.\n *\n * Now the prose goes to stderr, a machine-readable verdict goes to stdout, and\n * anything short of working credentials exits 1.\n *\n * ONLY THE KEY PREFIX IS EVER SHOWN. `psty_mcp_` keys are eight characters of\n * literal prefix, so the old `substring(0, 8)` revealed nothing — but for a\n * `pos_` OAuth token those same eight characters were four real secret ones.\n * The prefix is enough to tell two keys apart, which is all this is for.\n */\nexport async function authStatus() {\n const envKey = readEnv('API_KEY');\n const creds = loadCredentials();\n\n /** Enough to identify a key, never enough to use one. */\n const hint = (token: string) => `${token.split('_')[0]}_…`;\n\n /*\n THE METHOD IS THE CREDENTIAL, NOT THE FILE IT CAME FROM. Both\n `auth:login` and `auth:signup` store an API key (`psty_…`) in\n credentials.json; only a `pos_` token is OAuth. This used to say\n \"OAuth2\" for anything in the file.\n */\n const methodOf = (token: string): 'oauth2' | 'api-key' =>\n token.startsWith('pos_') ? 'oauth2' : 'api-key';\n const label = (m: 'oauth2' | 'api-key') =>\n m === 'oauth2' ? 'OAuth token' : 'API key';\n\n let apiKey: string | undefined;\n let apiUrl: string;\n let method: 'oauth2' | 'api-key';\n let source: 'credentials-file' | 'environment';\n\n if (creds) {\n method = methodOf(creds.accessToken);\n source = 'credentials-file';\n apiKey = creds.accessToken;\n apiUrl = creds.apiUrl;\n status(`🔐 Authentication method: ${label(method)} (stored by auth:login or auth:signup)`);\n status(`📡 API URL: ${creds.apiUrl}`);\n status(`🔑 Credential: ${hint(creds.accessToken)}`);\n if (creds.organizationId) {\n status(`🏢 Workspace: ${creds.organizationId}`);\n }\n status(`📁 Credentials file: ${CREDENTIALS_FILE}`);\n } else if (envKey) {\n method = methodOf(envKey);\n source = 'environment';\n apiKey = envKey;\n apiUrl = readEnv('API_URL') || DEFAULT_API_URL;\n status(`🔑 Authentication method: ${label(method)} (${envName('API_KEY')})`);\n status(`🔑 Credential: ${hint(envKey)}`);\n } else {\n status('❌ Not authenticated.');\n status('');\n status('Options:');\n status(` 1. Device login: ${BRAND.cli} auth:login`);\n status(` 2. New account: ${BRAND.cli} auth:signup --email <address>`);\n status(` 3. API Key: export ${envName('API_KEY')}=your_api_key`);\n result({ authenticated: false, reason: 'no-credentials' });\n process.exit(1);\n }\n\n status('');\n status('🔄 Verifying credentials...');\n\n const workspaceId = getWorkspaceId();\n const base = { method, source, apiUrl, workspace: workspaceId ?? null };\n\n /*\n THE PROBE IS `GET /subscription`, which answers for ANY valid credential,\n including one whose workspace has no plan with API access yet. The old\n probe (`GET /integrations`) is plan-gated, so a fresh `auth:signup` key\n was reported as \"expired or invalid\" while it was fine and only waiting\n for the payment.\n */\n let subscription: SubscriptionState;\n try {\n subscription = await new PostemiAPI({\n apiKey,\n apiUrl,\n workspaceId,\n }).getSubscription();\n } catch (error: any) {\n if (error instanceof ApiError && error.isWorkspaceChoice) {\n status('✅ Credentials are valid, but this key spans several workspaces and none is selected.');\n status(` Run: ${BRAND.cli} workspaces:list, then ${BRAND.cli} workspaces:use <id>`);\n result({ authenticated: true, ...base, reason: 'choose-workspace' });\n process.exit(1);\n }\n if (error instanceof ApiError && error.status === 401) {\n status('❌ Credentials are expired or invalid. Please re-authenticate.');\n status(\n creds\n ? ` Run: ${BRAND.cli} auth:login`\n : ` Update your ${envName('API_KEY')} environment variable.`\n );\n result({ authenticated: false, ...base, reason: 'rejected' });\n process.exit(1);\n }\n if (error instanceof ApiError) {\n /*\n UNKNOWN, NOT INVALID. A 500 or a proxy error says nothing about the\n credentials, so this reports that it could not check rather than\n claiming they are bad, but it still exits 1, because a caller that\n asked \"are these good?\" did not get a yes.\n */\n status(`⚠️ Could not verify credentials (HTTP ${error.status}): ${serverSentence(error.body)}`);\n result({ authenticated: null, ...base, reason: `http-${error.status}` });\n process.exit(1);\n }\n status(`⚠️ Could not reach API to verify credentials: ${error.message}`);\n result({ authenticated: null, ...base, reason: 'unreachable' });\n process.exit(1);\n }\n\n /*\n VALID, BUT NO PLAN YET: said as its own answer. The credential works (exit\n 0), and every command except billing:* will be refused until the workspace\n is on a plan with API access.\n */\n if (!subscription.apiAndMcpAccess) {\n const noPlan =\n subscription.state === 'none' ||\n subscription.state === 'cancelled' ||\n subscription.state === 'read_only';\n status(\n noPlan\n ? '✅ Credentials are valid. This workspace has no plan yet, so only the billing commands work.'\n : `✅ Credentials are valid. The current plan (${subscription.plan}) has no API access, so only the billing commands work.`\n );\n status(` Next: ${BRAND.cli} billing:plans, then ${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>`);\n if (subscription.pendingCheckout) {\n status(` An unpaid checkout is waiting: ${subscription.pendingCheckout.checkoutUrl}`);\n }\n result({\n authenticated: true,\n ...base,\n apiAccess: false,\n plan: subscription.plan,\n subscriptionState: subscription.state,\n reason: noPlan ? 'no-plan' : 'plan-without-api-access',\n });\n return;\n }\n\n // A full answer: how many channels, when the key may read them.\n let integrations: number | null = null;\n try {\n const list = (await new PostemiAPI({\n apiKey,\n apiUrl,\n workspaceId,\n }).listIntegrations()) as any[];\n integrations = Array.isArray(list) ? list.length : null;\n } catch {\n // A scoped key without channels:read; the credential is still valid.\n }\n\n status(\n `✅ Credentials are valid. Plan: ${subscription.plan ?? 'none'}${\n integrations === null ? '' : `, ${integrations} channel(s) connected`\n }.`\n );\n result({\n authenticated: true,\n ...base,\n apiAccess: true,\n plan: subscription.plan,\n subscriptionState: subscription.state,\n integrations,\n });\n}\n","/**\n * Persistent CLI settings — `~/.postemi/config.json`.\n *\n * Deliberately separate from `credentials.json`: settings survive\n * `postemi auth:logout`, and the credentials file keeps holding secrets only.\n *\n * One known key today: `timezone` (an IANA name, used to interpret dates\n * written without an explicit offset — see dates.ts for the full ladder).\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { BRAND } from './brand';\n\nconst SETTINGS_DIR = join(homedir(), BRAND.configDirName);\nconst SETTINGS_FILE = join(SETTINGS_DIR, 'config.json');\n\n/*\n `workspace` is the fallback home of the chosen workspace for a key that came\n from POSTEMI_API_KEY rather than from `postemi auth:login`; a device login stores\n it next to its token in credentials.json instead (see `workspaces:use`).\n*/\nexport const KNOWN_SETTINGS = ['timezone', 'workspace'] as const;\nexport type SettingKey = (typeof KNOWN_SETTINGS)[number];\n\nexport function settingsFilePath(): string {\n return SETTINGS_FILE;\n}\n\nexport function loadSettings(): Record<string, string> {\n try {\n if (!existsSync(SETTINGS_FILE)) return {};\n const data = JSON.parse(readFileSync(SETTINGS_FILE, 'utf-8'));\n return data && typeof data === 'object' ? data : {};\n } catch {\n return {};\n }\n}\n\nexport function getSetting(key: SettingKey): string | undefined {\n const value = loadSettings()[key];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nexport function saveSetting(key: SettingKey, value: string): void {\n if (!existsSync(SETTINGS_DIR)) {\n mkdirSync(SETTINGS_DIR, { recursive: true, mode: 0o700 });\n }\n const settings = loadSettings();\n settings[key] = value;\n writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + '\\n', {\n encoding: 'utf-8',\n });\n}\n","import { ApiError } from './api';\nimport { BRAND, envName } from './brand';\n\n/**\n * Output contract, kept strict because the primary consumers are scripts and\n * AI agents piping into `jq`:\n *\n * stdout — the JSON result of the command, and NOTHING else.\n * stderr — human-readable status, warnings and errors.\n *\n * Every failure exits 1.\n */\n\n/** The command's result. The only thing that ever goes to stdout. */\nexport function result(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n}\n\n/** Human-readable progress/status — stderr, so stdout stays parseable. */\nexport function status(message: string): void {\n console.error(message);\n}\n\n/** Print a failure (with an auth hint when it is one) and exit 1. */\nexport function fail(context: string, error: any): never {\n console.error(`❌ ${context}: ${error?.message || error}`);\n\n if (error instanceof ApiError && error.isWorkspaceChoice) {\n console.error(\n `This key spans several workspaces and none is selected. Run \"${BRAND.cli} workspaces:list\", then \"${BRAND.cli} workspaces:use <id>\" (or pass --workspace <id>).`\n );\n } else if (error instanceof ApiError && error.missingScope) {\n /*\n A VALID credential without the permission. \"Run auth:login\" was the\n wrong advice here: the key is fine, logging in again changes nothing.\n */\n const { missing, role } = error.missingScope;\n console.error(\n `This key is valid but lacks the permission ${missing.join(', ') || 'this command needs'}${\n role ? ` (the key owner's role: ${role})` : ''\n }. Create a key that includes it in ${BRAND.name} (Settings, Developers), or ask a workspace owner.`\n );\n } else if (error instanceof ApiError && error.isPlanMissing) {\n console.error(\n `The credential is valid, but this workspace has no plan with API access yet. Run \"${BRAND.cli} billing:plans\", then \"${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>\".`\n );\n } else if (error instanceof ApiError && error.isForbidden) {\n /*\n A 403 the scope guard did not phrase: the credential is valid, this\n action is not open to it (a scoped key on billing:manage, a colleague\n who is not the payer). The server's message above says why; \"your\n credentials were rejected\" would send the person to log in for nothing.\n */\n console.error(\n 'The credential is valid but not allowed to do this. The message above says why.'\n );\n } else if (error instanceof ApiError && error.isAuthError) {\n console.error(\n `Your credentials were rejected. Run \"${BRAND.cli} auth:login\" to re-authenticate, or check ${envName('API_KEY')}.`\n );\n }\n if (error instanceof ApiError && error.isRateLimit) {\n console.error(\n 'Rate limit hit (per key, per route, per hour). Back off — do not retry in a loop.'\n );\n }\n\n process.exit(1);\n}\n","/**\n * Date input handling.\n *\n * The API stores publish dates as UTC instants, and the backend interprets a\n * datetime WITHOUT a timezone designator in the server's own clock (UTC in\n * production) — which silently shifts a local \"12:00\" by the zone's offset.\n *\n * The CLI therefore refuses to guess. A date is either explicit or explicitly\n * configured, resolved in this priority order:\n *\n * (a) an explicit designator in the string itself (`Z`, `+01:00`) — used\n * as written;\n * (b) `--timezone <IANA name>` on the command;\n * (c) the `POSTEMI_TIMEZONE` environment variable;\n * (d) the `timezone` saved in `~/.postemi/config.json`\n * (`postemi config:set timezone <IANA>`, or confirmed during\n * `postemi auth:login` on a TTY);\n * (e) none of the above and the date is naive → hard error.\n *\n * Timezones must be IANA names (`Europe/London`). Numeric offsets are\n * REJECTED as timezone values on purpose: an offset hand-picked by a human or\n * an LLM is exactly the DST mistake this design exists to prevent. Offsets\n * belong inside the date string, where they are explicit per-instant.\n *\n * Whenever a timezone is applied (b–d), the resolved UTC instant is echoed on\n * stderr so nothing is silent.\n */\n\nimport { getSetting } from './settings';\nimport { BRAND, envName, readEnv } from './brand';\n\nexport type TimezoneSource =\n | '--timezone'\n | 'POSTEMI_TIMEZONE'\n | 'config (postemi config:set timezone)';\n\nexport interface ResolvedTimezone {\n name: string;\n source: TimezoneSource;\n}\n\nconst HAS_DESIGNATOR = /(Z|[+-]\\d{2}:?\\d{2})$/i;\nconst NAIVE_SHAPE =\n /^(\\d{4})-(\\d{2})-(\\d{2})([T ](\\d{2}):(\\d{2})(:(\\d{2}))?)?$/;\n\n/** Offset-shaped \"timezones\" we refuse: +02:00, -0500, UTC+2, GMT-5, Etc/GMT+2 … */\nconst OFFSET_SHAPED = /^(Etc\\/)?(UTC|GMT)?\\s*[+-]?\\d/i;\n\n/**\n * Validate an IANA timezone name. Throws with a corrective message on\n * anything else — including numeric offsets, which are valid concepts but\n * banned as timezone VALUES (see module comment).\n */\nexport function assertIanaTimezone(name: string, origin: string): string {\n const value = name.trim();\n\n if (!value || OFFSET_SHAPED.test(value)) {\n throw new Error(\n `Invalid timezone \"${name}\" (from ${origin}): numeric offsets are not accepted as timezones — DST would be your problem to compute. ` +\n `Use an IANA name like \"${BRAND.exampleTimezone}\" (or put the offset inside the date string itself, e.g. \"2026-12-31T12:00:00+01:00\").`\n );\n }\n\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: value });\n } catch {\n throw new Error(\n `Unknown timezone \"${name}\" (from ${origin}). Use an IANA name like \"${BRAND.exampleTimezone}\" or \"UTC\".`\n );\n }\n\n return value;\n}\n\n/**\n * Walk the ladder (b) → (d). Returns null when nothing is configured — the\n * caller then errors only if it actually meets a naive date. An invalid value\n * at any rung is an error, not a fall-through: silently skipping a typoed\n * POSTEMI_TIMEZONE would reintroduce the guessing this design removes.\n */\nexport function resolveTimezone(flagValue?: string): ResolvedTimezone | null {\n if (flagValue !== undefined) {\n return {\n name: assertIanaTimezone(flagValue, '--timezone'),\n source: '--timezone',\n };\n }\n\n const env = readEnv('TIMEZONE');\n if (env) {\n return {\n name: assertIanaTimezone(env, envName('TIMEZONE')),\n source: 'POSTEMI_TIMEZONE',\n };\n }\n\n const stored = getSetting('timezone');\n if (stored) {\n return {\n name: assertIanaTimezone(stored, `~/${BRAND.configDirName}/config.json`),\n source: 'config (postemi config:set timezone)',\n };\n }\n\n return null;\n}\n\n/** Offset of `timeZone` from UTC at the given instant, in minutes. */\nfunction tzOffsetMinutes(instant: Date, timeZone: string): number {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n }).formatToParts(instant);\n\n const get = (type: string) =>\n Number(parts.find((p) => p.type === type)?.value);\n\n const asUtc = Date.UTC(\n get('year'),\n get('month') - 1,\n get('day'),\n get('hour') % 24,\n get('minute'),\n get('second')\n );\n\n return Math.round((asUtc - instant.getTime()) / 60000);\n}\n\n/** Interpret naive wall-clock components in `timeZone`; return the instant. */\nfunction zonedToUtc(\n y: number,\n mo: number,\n d: number,\n h: number,\n mi: number,\n s: number,\n timeZone: string\n): Date {\n // First guess: treat the wall clock as UTC, then correct by the zone's\n // offset at that instant. One refinement pass handles DST boundaries.\n const guess = Date.UTC(y, mo - 1, d, h, mi, s);\n let offset = tzOffsetMinutes(new Date(guess), timeZone);\n let instant = guess - offset * 60000;\n const refined = tzOffsetMinutes(new Date(instant), timeZone);\n if (refined !== offset) {\n instant = guess - refined * 60000;\n }\n return new Date(instant);\n}\n\nexport interface ResolvedDate {\n /** UTC ISO 8601, always with `Z` — what goes on the wire. */\n iso: string;\n /** Set when the input carried no designator and a timezone was applied. */\n appliedTimezone: ResolvedTimezone | null;\n}\n\nfunction naiveDateError(input: string, flagName: string): Error {\n return new Error(\n `Date \"${input}\" has no timezone, and no timezone is configured. ` +\n `The server would read it as UTC, silently shifting your post. Fix one of:\\n` +\n ` 1. Explicit offset in the date: ${flagName} \"2026-12-31T12:00:00+01:00\" (or ...T12:00:00Z for UTC)\\n` +\n ` 2. Timezone flag: --timezone ${BRAND.exampleTimezone}\\n` +\n ` 3. Environment variable: export ${envName('TIMEZONE')}=${BRAND.exampleTimezone}\\n` +\n ` 4. Save it once: ${BRAND.cli} config:set timezone ${BRAND.exampleTimezone}`\n );\n}\n\n/**\n * Normalize a user-supplied date to UTC ISO 8601, or throw with a message\n * that says exactly how to fix it. `timezone` comes from `resolveTimezone`.\n */\nexport function resolveDateInput(\n input: string,\n timezone: ResolvedTimezone | null,\n flagName = '--date'\n): ResolvedDate {\n const value = input.trim();\n\n if (HAS_DESIGNATOR.test(value)) {\n const parsed = new Date(value);\n if (isNaN(parsed.getTime())) {\n throw new Error(\n `Invalid date \"${input}\". Use ISO 8601, e.g. \"2026-12-31T12:00:00Z\" or \"2026-12-31T12:00:00+01:00\".`\n );\n }\n return { iso: parsed.toISOString(), appliedTimezone: null };\n }\n\n const m = NAIVE_SHAPE.exec(value);\n if (!m) {\n throw new Error(\n `Invalid date \"${input}\". Use ISO 8601 with an explicit offset (\"2026-12-31T12:00:00Z\"), or \"YYYY-MM-DD HH:mm\" together with a timezone (--timezone ${BRAND.exampleTimezone}).`\n );\n }\n\n if (!timezone) {\n throw naiveDateError(input, flagName);\n }\n\n const instant = zonedToUtc(\n Number(m[1]),\n Number(m[2]),\n Number(m[3]),\n Number(m[5] ?? 0),\n Number(m[6] ?? 0),\n Number(m[8] ?? 0),\n timezone.name\n );\n\n if (isNaN(instant.getTime())) {\n throw new Error(`Invalid date \"${input}\".`);\n }\n\n return { iso: instant.toISOString(), appliedTimezone: timezone };\n}\n","import { PostemiConfig } from './api';\nimport { loadCredentials } from './commands/auth';\nimport { getSetting } from './settings';\nimport { BRAND, envName, readEnv } from './brand';\n\n/**\n * Which workspace requests are about, in order of precedence: `--workspace`\n * on the command (the yargs middleware copies it into POSTEMI_WORKSPACE), the\n * environment, the choice saved by `postemi workspaces:use` (in credentials.json\n * for a device login, in config.json for an env key). Undefined is fine for a\n * one-workspace key; the API refuses to guess for a key that spans several.\n */\nexport function getWorkspaceId(): string | undefined {\n const fromEnv = readEnv('WORKSPACE');\n if (fromEnv) return fromEnv;\n const creds = loadCredentials();\n if (creds?.organizationId) return creds.organizationId;\n return getSetting('workspace');\n}\n\nexport function getConfig(): PostemiConfig {\n const workspaceId = getWorkspaceId();\n\n // Check for stored OAuth credentials first\n const creds = loadCredentials();\n if (creds) {\n return {\n apiKey: creds.accessToken,\n apiUrl: creds.apiUrl,\n workspaceId,\n };\n }\n\n // Fall back to environment variable\n const apiKey = readEnv('API_KEY');\n const apiUrl = readEnv('API_URL');\n\n if (!apiKey) {\n console.error('❌ Error: No authentication found.');\n console.error('Options:');\n console.error(` 1. Device login: ${BRAND.cli} auth:login`);\n console.error(` 2. API Key: export ${envName('API_KEY')}=your_api_key`);\n process.exit(1);\n }\n\n return {\n apiKey,\n apiUrl,\n workspaceId,\n };\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport {\n ResolvedDate,\n ResolvedTimezone,\n resolveDateInput,\n resolveTimezone,\n} from '../dates';\nimport { result, status, fail } from '../output';\nimport { readFileSync, existsSync } from 'fs';\nimport { BRAND } from '../brand';\n\n/**\n * Read `--content`/`--media` off the raw argv, keeping the order they were\n * written in, so each `-m` belongs to the `-c` it follows.\n *\n * Exported for the tests, and separate from the handler because it is pure:\n * argv in, pairs out, no process state.\n *\n * Accepts `-c X`, `--content X` and `--content=X`. Repeating `-m` under one\n * `-c` appends, matching the comma syntax a single `-m` already supports.\n */\nexport const pairContentsWithMedia = (\n argv: string[]\n): { content: string; media?: string }[] => {\n const read = (\n token: string,\n next: string | undefined,\n long: string,\n short: string\n ): { value: string; consumed: number } | null => {\n if (token === `--${long}` || token === `-${short}`) {\n return next === undefined ? null : { value: next, consumed: 2 };\n }\n if (token.startsWith(`--${long}=`)) {\n return { value: token.slice(long.length + 3), consumed: 1 };\n }\n return null;\n };\n\n const pairs: { content: string; media?: string }[] = [];\n\n for (let i = 0; i < argv.length; ) {\n const content = read(argv[i], argv[i + 1], 'content', 'c');\n if (content) {\n pairs.push({ content: content.value });\n i += content.consumed;\n continue;\n }\n\n const media = read(argv[i], argv[i + 1], 'media', 'm');\n if (media) {\n /*\n An -m before any -c has nothing to attach to. Guessing (first\n content? all of them?) is how the old bug behaved, so refuse instead.\n */\n if (!pairs.length) {\n console.error('❌ --media/-m must come after the --content/-c it belongs to');\n process.exit(1);\n }\n const last = pairs[pairs.length - 1];\n last.media = last.media ? `${last.media},${media.value}` : media.value;\n i += media.consumed;\n continue;\n }\n\n i += 1;\n }\n\n return pairs;\n};\n\n/** Walk the timezone ladder for this invocation, or exit 1 with the reason. */\nfunction timezoneForArgs(args: any): ResolvedTimezone | null {\n try {\n return resolveTimezone(args.timezone);\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n}\n\nfunction echoInterpretation(input: string, resolved: ResolvedDate) {\n if (resolved.appliedTimezone) {\n status(\n `ℹ️ Interpreted \"${input}\" as ${resolved.appliedTimezone.name} (via ${resolved.appliedTimezone.source}) → ${resolved.iso}`\n );\n }\n}\n\nexport async function getMissingContent(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getMissingContent(args.id);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get missing content', error);\n }\n}\n\nexport async function connectPost(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.updateReleaseId(args.id, args.releaseId);\n status(`✅ Post ${args.id} connected to release ${args.releaseId}`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to connect post', error);\n }\n}\n\nexport async function findSlot(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.findSlot(args.id);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to find a free slot', error);\n }\n}\n\nexport async function createPost(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n // Support both simple and complex post creation\n let postData: any;\n\n if (args.json) {\n // Load from JSON file for complex posts with comments and media\n try {\n const jsonPath = args.json;\n if (!existsSync(jsonPath)) {\n console.error(`❌ JSON file not found: ${jsonPath}`);\n process.exit(1);\n }\n const jsonContent = readFileSync(jsonPath, 'utf-8');\n postData = JSON.parse(jsonContent);\n } catch (error: any) {\n console.error(`❌ Failed to parse JSON file: ${error.message}`);\n process.exit(1);\n }\n } else {\n const integrations = args.integrations\n ? args.integrations.split(',').map((id: string) => id.trim())\n : [];\n\n if (integrations.length === 0) {\n console.error('❌ At least one integration ID is required');\n console.error('Use -i or --integrations to specify integration IDs');\n console.error(`Run \"${BRAND.cli} integrations:list\" to see available integrations`);\n process.exit(1);\n }\n\n const contents = Array.isArray(args.content) ? args.content : [args.content];\n\n if (!contents[0]) {\n console.error('❌ At least one -c/--content is required');\n process.exit(1);\n }\n\n /*\n PAIRED BY POSITION ON THE COMMAND LINE, NOT BY ARRAY INDEX.\n\n yargs collects every -c into one array and every -m into another, and\n this used to pair them by index. The two arrays only line up when every\n -c has an -m, so\n\n -c \"A\" -m one.jpg -c \"B\" -c \"C\" -m three.jpg\n\n produced medias [\"one\",\"three\"] and attached three.jpg to comment B.\n Silently, and to a live social account. Reading the real argv is the\n only way to know which -c an -m was written under.\n */\n const pairs = pairContentsWithMedia(process.argv);\n\n if (pairs.length && pairs.length !== contents.length) {\n console.error(\n `❌ Could not match --media to --content reliably (parsed ${pairs.length} content flags, yargs saw ${contents.length}).`\n );\n console.error('Pass the post structure with --json instead.');\n process.exit(1);\n }\n\n const values = (pairs.length ? pairs : contents.map((content: string) => ({ content, media: undefined })))\n .map(({ content, media }: { content: string; media?: string }) => ({\n content,\n image: media\n ? media.split(',').filter((img: string) => img.trim()).map((img: string) => ({\n id: Math.random().toString(36).substring(7),\n path: img.trim(),\n }))\n : [],\n delay: args?.delay || 0,\n }));\n\n // Parse provider-specific settings if provided\n // Note: __type is automatically added by the backend based on integration ID\n let settings: any = undefined;\n\n if (args.settings) {\n try {\n settings = typeof args.settings === 'string'\n ? JSON.parse(args.settings)\n : args.settings;\n } catch (error: any) {\n console.error(`❌ Failed to parse settings JSON: ${error.message}`);\n process.exit(1);\n }\n }\n\n const type = args.type || 'schedule';\n\n // `now` publishes immediately; the server replaces the date, but the API\n // still requires the field, so send the current instant when it is omitted.\n let dateIso: string;\n if (!args.date && type === 'now') {\n dateIso = new Date().toISOString();\n } else {\n const timezone = timezoneForArgs(args);\n try {\n const resolved = resolveDateInput(args.date, timezone, '--date');\n dateIso = resolved.iso;\n echoInterpretation(args.date, resolved);\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n }\n\n // Build the proper post structure\n postData = {\n type,\n creationMethod: 'CLI',\n date: dateIso,\n shortLink: args.shortLink !== false,\n tags: [],\n posts: integrations.map((integrationId: string) => ({\n integration: { id: integrationId },\n value: values,\n settings: settings,\n })),\n };\n }\n\n try {\n const res = await api.createPost(postData);\n status('✅ Post created successfully!');\n if (postData?.type && postData.type !== 'draft') {\n status(\n 'Note: a key without posts:publish creates a DRAFT even when you asked to schedule — check the type in the response.'\n );\n }\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to create post', error);\n }\n}\n\nexport async function listPosts(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n // Set default date range: last 30 days to 30 days in the future\n const defaultStartDate = new Date();\n defaultStartDate.setDate(defaultStartDate.getDate() - 30);\n\n const defaultEndDate = new Date();\n defaultEndDate.setDate(defaultEndDate.getDate() + 30);\n\n // Only walk the ladder when a date was actually supplied — the defaults are\n // computed instants and must not fail on, say, a typoed POSTEMI_TIMEZONE.\n const timezone =\n args.startDate || args.endDate ? timezoneForArgs(args) : null;\n\n const resolve = (label: string, value: string | undefined, fallback: Date) => {\n if (!value) return fallback.toISOString();\n try {\n const resolved = resolveDateInput(value, timezone, label);\n echoInterpretation(value, resolved);\n return resolved.iso;\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n };\n\n // Only send fields that are in GetPostsDto\n const filters: any = {\n startDate: resolve('--startDate', args.startDate, defaultStartDate),\n endDate: resolve('--endDate', args.endDate, defaultEndDate),\n };\n\n // customer is optional in the DTO\n if (args.customer) {\n filters.customer = args.customer;\n }\n\n try {\n const res = await api.listPosts(filters);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list posts', error);\n }\n}\n\nexport async function changePostStatus(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.changePostStatus(args.id, args.status);\n status(`✅ Post ${args.id} status changed to ${args.status}`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to change post status', error);\n }\n}\n\nexport async function deletePost(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.deletePost(args.id);\n status(`✅ Post ${args.id} deleted successfully!`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to delete post', error);\n }\n}\n\nexport async function deletePostGroup(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.deletePostGroup(args.group);\n status(`✅ Post group ${args.group} deleted from every channel`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to delete post group', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { result, fail } from '../output';\n\nexport async function listIntegrations(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.listIntegrations(args?.group);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list integrations', error);\n }\n}\n\nexport async function listGroups() {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.listGroups();\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list groups', error);\n }\n}\n\nexport async function getIntegrationSettings(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getIntegrationSettings(args.id);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get integration settings', error);\n }\n}\n\nexport async function triggerIntegrationTool(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n // Parse data from JSON string or use empty object\n let data: Record<string, string> = {};\n if (args.data) {\n try {\n data = JSON.parse(args.data);\n } catch (error: any) {\n console.error(`❌ Failed to parse data JSON: ${error.message}`);\n process.exit(1);\n }\n }\n\n try {\n const res = await api.triggerIntegrationTool(args.id, args.method, data);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to trigger tool', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { result, fail } from '../output';\n\nfunction daysArg(args: any): string {\n const days = String(args.days ?? '7');\n if (!/^\\d+$/.test(days) || Number(days) < 1) {\n console.error('❌ --days must be a positive whole number of days, e.g. --days 30');\n process.exit(1);\n }\n return days;\n}\n\nexport async function getAnalytics(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getAnalytics(args.id, daysArg(args));\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get analytics', error);\n }\n}\n\nexport async function getPostAnalytics(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getPostAnalytics(args.id, daysArg(args));\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get post analytics', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { result, status, fail } from '../output';\nimport { readFileSync, existsSync } from 'fs';\nimport { basename } from 'path';\nimport { BRAND } from '../brand';\n\nexport async function uploadFile(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n if (!existsSync(args.file)) {\n console.error(`❌ File not found: ${args.file}`);\n process.exit(1);\n }\n\n try {\n const fileBuffer = readFileSync(args.file);\n const filename = basename(args.file) || 'file';\n\n const res = await api.upload(fileBuffer, filename);\n status('✅ File uploaded successfully!');\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to upload file', error);\n }\n}\n\n/**\n * `postemi upload:link` — for a file that is NOT on this machine.\n *\n * `postemi upload` needs the file on disk. When the person has it on their\n * phone, or the agent running this CLI cannot see their filesystem, mint a\n * link instead: they open it in any browser, drop the files, and\n * `postemi upload:files <id>` returns what arrived.\n */\nexport async function createUploadLink() {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.createUploadLink();\n status(\n `🔗 Upload link created. Open it in a browser, drop the files, then run: ${BRAND.cli} upload:files ${res.id}`\n );\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to create an upload link', error);\n }\n}\n\nexport async function listUploadLinkFiles(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getUploadLinkFiles(args.id);\n if (res.status === 'empty') {\n status('⏳ Nothing has arrived through this link yet. Ask the person to check the page says \"uploaded\", then run this again.');\n } else {\n status(`✅ ${res.count} file(s) arrived. Use each .path in posts:create -m`);\n }\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to read the upload link', error);\n }\n}\n","import {\n KNOWN_SETTINGS,\n SettingKey,\n loadSettings,\n saveSetting,\n settingsFilePath,\n} from '../settings';\nimport { assertIanaTimezone } from '../dates';\nimport { result, status } from '../output';\n\nfunction assertKnownKey(key: string): SettingKey {\n if (!(KNOWN_SETTINGS as readonly string[]).includes(key)) {\n console.error(\n `❌ Unknown setting \"${key}\". Known settings: ${KNOWN_SETTINGS.join(', ')}`\n );\n process.exit(1);\n }\n return key as SettingKey;\n}\n\nexport async function configSet(args: any) {\n const key = assertKnownKey(args.key);\n let value = String(args.value);\n\n if (key === 'timezone') {\n try {\n value = assertIanaTimezone(value, 'config:set');\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n }\n\n saveSetting(key, value);\n status(`✅ ${key} = ${value} saved to ${settingsFilePath()}`);\n result({ [key]: value });\n}\n\nexport async function configGet(args: any) {\n const settings = loadSettings();\n\n if (args.key) {\n const key = assertKnownKey(args.key);\n result({ [key]: settings[key] ?? null });\n return;\n }\n\n result(settings);\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig, getWorkspaceId } from '../config';\nimport { loadCredentials, saveCredentials } from './auth';\nimport { saveSetting, settingsFilePath } from '../settings';\nimport { result, status, fail } from '../output';\nimport { BRAND } from '../brand';\n\n/**\n * `postemi workspaces:list` — every workspace the credential can act on, with\n * `current` marking the one requests go to. A key from `postemi auth:login`\n * spans one workspace unless \"all my workspaces\" was ticked on the approval\n * page; a key made in Settings can span any number.\n */\nexport async function listWorkspaces() {\n const api = new PostemiAPI(getConfig());\n try {\n const res = await api.listWorkspaces();\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list workspaces', error);\n }\n}\n\n/**\n * `postemi workspaces:use <id>` — make every following command act on that\n * workspace. Checked against the API first, so a typo is refused here and\n * not on the next post. Stored next to the token for a device login, in\n * config.json for a key that comes from the environment.\n */\nexport async function useWorkspace(args: any) {\n const id = String(args.id || '').trim();\n if (!id) {\n fail('Failed to select workspace', new Error(`Give the workspace id, from \"${BRAND.cli} workspaces:list\"`));\n }\n\n // Listed WITHOUT naming a workspace: the list route is the one route that\n // answers for a multi-workspace key either way, and asking with the header\n // would trip the target's subscription gate before the choice is even saved.\n const api = new PostemiAPI({ ...getConfig(), workspaceId: undefined });\n\n let workspaces;\n try {\n workspaces = await api.listWorkspaces();\n } catch (error: any) {\n fail('Failed to select workspace', error);\n }\n\n const chosen = workspaces.find((w) => w.id === id);\n if (!chosen) {\n fail(\n 'Failed to select workspace',\n new Error(\n `This credential cannot act on workspace ${id}. Available: ${workspaces\n .map((w) => `${w.name} (${w.id})`)\n .join(', ') || 'none'}`\n )\n );\n }\n\n const creds = loadCredentials();\n if (creds) {\n saveCredentials({ ...creds, organizationId: chosen.id });\n status(`✅ Workspace set to ${chosen.name} (saved with your login)`);\n } else {\n saveSetting('workspace', chosen.id);\n status(`✅ Workspace set to ${chosen.name} (saved to ${settingsFilePath()})`);\n }\n result({ id: chosen.id, name: chosen.name, role: chosen.role });\n}\n\n/** `postemi workspaces:current` — the one requests go to, or null. */\nexport async function currentWorkspace() {\n const id = getWorkspaceId();\n const api = new PostemiAPI(getConfig());\n try {\n const workspaces = await api.listWorkspaces();\n const current = workspaces.find((w) => w.current) || null;\n if (!current && workspaces.length > 1) {\n status(\n `No workspace selected and this key spans several. Run: ${BRAND.cli} workspaces:use <id>`\n );\n }\n result(current ?? (id ? { id, name: null } : null));\n } catch (error: any) {\n fail('Failed to read the current workspace', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { openBrowser } from './auth';\nimport { result, status, fail } from '../output';\nimport { BRAND, tierForApi } from '../brand';\n\n/*\n SUBSCRIBING FROM A SHELL, WITH THE ONE STEP THAT STAYS HUMAN.\n\n An agent driving this CLI can show the plans, ask for a checkout link and\n confirm afterwards that the plan is live. It cannot pay, and it must not\n try: the link is Stripe's Managed Payments Checkout, the person opens it\n and pays with their own Link wallet or card. A one-time or agent-issued\n card would fail at the first renewal and end the plan, so `billing:subscribe`\n says so on stderr every time it prints a link.\n*/\n\n/** `postemi billing:plans` — the four plans, their prices, and the current tier. */\nexport async function billingPlans() {\n const api = new PostemiAPI(getConfig());\n try {\n result(await api.getPlans());\n } catch (error: any) {\n fail('Failed to read the plans', error);\n }\n}\n\n/**\n * `postemi billing:subscribe --tier pro --period yearly [--open]` — a Stripe\n * Checkout link for the plan. Printed as JSON on stdout; `--open` also opens\n * it in the browser of the machine the CLI runs on, which is only useful when\n * that machine is the person's own.\n */\nexport async function billingSubscribe(args: any) {\n const tier = String(args.tier || '').trim();\n const period = String(args.period || '').trim().toLowerCase();\n\n if (!tier) {\n fail(\n 'Failed to start the subscription',\n new Error(`Give the plan with --tier (${BRAND.tierList}; see \"${BRAND.cli} billing:plans\")`)\n );\n }\n if (period !== 'monthly' && period !== 'yearly') {\n fail(\n 'Failed to start the subscription',\n new Error('Give the period with --period monthly or --period yearly')\n );\n }\n\n const api = new PostemiAPI(getConfig());\n try {\n const checkout = await api.createSubscriptionCheckout(tierForApi(tier), period);\n status(\n `Checkout link for ${checkout.plan} (${checkout.period.toLowerCase()}, ${checkout.amount} ${checkout.currency}${\n checkout.trial ? `, ${checkout.trialDays}-day free trial` : ''\n }). The link expires at ${checkout.expiresAt}.`\n );\n status(\n `The subscriber opens this link and pays in Stripe Checkout with their own Link wallet or card. Do not pay with a one-time or agent-issued card: the subscription renews and a one-time card fails at the first renewal. After paying, run \"${BRAND.cli} billing:status\" to confirm.`\n );\n /*\n The note goes to stderr ONCE, in the CLI's own words: the server's text\n is shared with the MCP tools, and the JSON on stdout carries\n `apiAndMcpAccess: false` for a script to act on. Printing `note` in both\n streams showed the person the same warning twice.\n */\n const { note: _note, ...json } = checkout;\n if (checkout.apiAndMcpAccess === false) {\n status(\n `The ${checkout.plan} plan has no API or MCP access: after the payment this key still reaches only the billing commands, and the person uses ${BRAND.name} in the web app. Tell the person before they pay; a plan with apiAndMcpAccess: true in \"${BRAND.cli} billing:plans\" keeps the CLI working.`\n );\n }\n if (args.open) {\n openBrowser(checkout.checkoutUrl);\n status('Opened the checkout in the browser.');\n }\n result(json);\n } catch (error: any) {\n fail('Failed to start the subscription', error);\n }\n}\n\n/** `postemi billing:status` — the subscription state and any unpaid checkout. */\nexport async function billingStatus() {\n const api = new PostemiAPI(getConfig());\n try {\n const subscription = await api.getSubscription();\n if (subscription.pendingCheckout) {\n const pending = subscription.pendingCheckout;\n const when = (iso: string) =>\n iso ? new Date(iso).toLocaleString() : 'an unknown time';\n status(\n `A checkout for ${pending.plan}${\n pending.period ? ` (${pending.period.toLowerCase()})` : ''\n } started at ${when(pending.startedAt)} has not been paid yet. The link is in pendingCheckout.checkoutUrl and expires at ${when(pending.expiresAt)}.`\n );\n }\n result(subscription);\n } catch (error: any) {\n fail('Failed to read the subscription', error);\n }\n}\n\n/** `postemi billing:manage [--open]` — a link to the Stripe billing portal. */\nexport async function billingManage(args: any) {\n const api = new PostemiAPI(getConfig());\n try {\n const portal = await api.getSubscriptionPortal();\n // Once, on stderr; the JSON keeps only what a script acts on.\n const { note, ...json } = portal;\n status(note);\n if (args.open) {\n openBrowser(portal.portalUrl);\n status('Opened the billing portal in the browser.');\n }\n result(json);\n } catch (error: any) {\n fail('Failed to open the billing portal', error);\n }\n}\n"],"mappings":"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","names":["status","import_fs","import_path","import_os","import_fs","import_fs","import_path","yargs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/api.ts","../src/brand.ts","../src/commands/auth.ts","../src/settings.ts","../src/output.ts","../src/dates.ts","../src/commands/skills.ts","../src/skills.ts","../src/config.ts","../src/commands/posts.ts","../src/commands/integrations.ts","../src/commands/analytics.ts","../src/commands/upload.ts","../src/commands/config.ts","../src/commands/workspaces.ts","../src/commands/billing.ts"],"sourcesContent":["import yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { createPost, listPosts, deletePost, deletePostGroup, getMissingContent, connectPost, changePostStatus, findSlot } from './commands/posts';\nimport { listIntegrations, listGroups, getIntegrationSettings, triggerIntegrationTool } from './commands/integrations';\nimport { getAnalytics, getPostAnalytics } from './commands/analytics';\nimport { uploadFile, createUploadLink, listUploadLinkFiles } from './commands/upload';\nimport { authLogin, authLogout, authStatus, authSignup } from './commands/auth';\nimport { configSet, configGet } from './commands/config';\nimport { listWorkspaces, useWorkspace, currentWorkspace } from './commands/workspaces';\nimport { skillsList, skillsAdd, skillsRemove } from './commands/skills';\nimport { billingPlans, billingSubscribe, billingStatus, billingManage } from './commands/billing';\nimport type { Argv } from 'yargs';\nimport { BRAND, envName, writeEnv } from './brand';\n\nyargs(hideBin(process.argv))\n .scriptName(BRAND.cli)\n .usage('$0 <command> [options]')\n .option('workspace', {\n alias: 'w',\n describe:\n `Workspace id this command acts on (overrides \"${BRAND.cli} workspaces:use\" and ${envName('WORKSPACE')})`,\n type: 'string',\n global: true,\n })\n // One place reads the choice (config.ts), so the flag becomes the env var.\n .middleware((argv: any) => {\n if (argv.workspace) {\n writeEnv('WORKSPACE', String(argv.workspace));\n }\n })\n .command(\n 'posts:create',\n 'Create a new post (schedule, draft, or publish now)',\n (yargs: Argv) => {\n return yargs\n .option('content', {\n alias: 'c',\n describe: 'Post/comment content (repeat for a thread: first is the post, the rest are comments)',\n type: 'string',\n })\n .option('media', {\n alias: 'm',\n describe: `Comma-separated media URLs for the corresponding -c (repeatable; URLs must come from \"${BRAND.cli} upload\")`,\n type: 'string',\n })\n .option('integrations', {\n alias: 'i',\n describe: `Comma-separated list of integration IDs (from \"${BRAND.cli} integrations:list\")`,\n type: 'string',\n })\n .option('date', {\n alias: 's',\n describe:\n `Publish date. ALWAYS give ISO 8601 with an explicit offset (\"2026-12-31T12:00:00Z\" / \"+01:00\"), or a datetime without offset (\"2026-12-31 12:00\") together with a timezone (--timezone / ${envName('TIMEZONE')} / ${BRAND.cli} config:set timezone). A naive date with no timezone configured is an error. Required unless --type now or --json.`,\n type: 'string',\n })\n .option('timezone', {\n describe:\n `IANA timezone name (e.g. ${BRAND.exampleTimezone}) used to interpret --date when it has no explicit offset. Numeric offsets are not accepted here — put those in the date string.`,\n type: 'string',\n })\n .option('type', {\n alias: 't',\n describe: 'Post type: \"schedule\" (default), \"draft\", or \"now\" (publish immediately)',\n type: 'string',\n choices: ['schedule', 'draft', 'now'],\n default: 'schedule',\n })\n .option('delay', {\n alias: 'd',\n describe: 'Delay in MINUTES between comments (default: 0)',\n type: 'number',\n default: 0,\n })\n .option('json', {\n alias: 'j',\n describe: 'Path to JSON file with the full post structure (see examples/)',\n type: 'string',\n })\n .option('shortLink', {\n describe: 'Use short links',\n type: 'boolean',\n default: true,\n })\n .option('settings', {\n describe: `Platform-specific settings as JSON string (schema: \"${BRAND.cli} integrations:settings <id>\")`,\n type: 'string',\n })\n .check((argv) => {\n if (!argv.json && !argv.content) {\n throw new Error('Either --content or --json is required');\n }\n if (!argv.json && !argv.integrations) {\n throw new Error('--integrations is required when not using --json');\n }\n if (!argv.json && !argv.date && argv.type !== 'now') {\n throw new Error('--date is required when not using --json (or use --type now to publish immediately)');\n }\n return true;\n })\n .example(\n '$0 posts:create -c \"Hello World!\" -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n 'Simple scheduled post (explicit UTC)'\n )\n .example(\n `$0 posts:create -c \"Merry Christmas! 🎄\" -s \"2026-12-24 18:00\" --timezone ${BRAND.exampleTimezone} -i \"integration-id\"`,\n 'Local wall-clock time with an explicit IANA timezone'\n )\n .example(\n '$0 posts:create -c \"This goes out right now\" -t now -i \"integration-id\"',\n 'Publish immediately (no --date needed)'\n )\n .example(\n '$0 posts:create -c \"Draft post\" -s \"2026-12-31T12:00:00Z\" -t draft -i \"integration-id\"',\n 'Create draft post'\n )\n .example(\n '$0 posts:create -c \"Main post\" -m \"img1.jpg,img2.jpg\" -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n `Post with multiple images (each URL from \"${BRAND.cli} upload\")`\n )\n .example(\n '$0 posts:create -c \"Main post\" -m \"img1.jpg\" -c \"First comment\" -m \"img2.jpg\" -c \"Second comment\" -m \"img3.jpg,img4.jpg\" -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n 'Post with comments, each having their own media'\n )\n .example(\n '$0 posts:create -c \"Thread 1/3\" -c \"Thread 2/3\" -c \"Thread 3/3\" -d 5 -s \"2026-12-31T12:00:00Z\" -i \"integration-id\"',\n 'X (Twitter) thread with 5 minute delay between comments'\n )\n .example(\n '$0 posts:create --json ./post.json',\n 'Complex post from JSON file'\n )\n .example(\n '$0 posts:create -c \"Tweet content\" -s \"2026-12-31T12:00:00Z\" --settings \\'{\"who_can_reply_post\":\"everyone\"}\\' -i \"integration-id\"',\n 'X (Twitter) post with reply settings'\n )\n .example(\n '$0 posts:create -c \"Video description\" -s \"2026-12-31T12:00:00Z\" --settings \\'{\"title\":\"My Video\",\"type\":\"public\"}\\' -i \"youtube-id\"',\n 'YouTube post with title and visibility'\n );\n },\n createPost as any\n )\n .command(\n 'posts:list',\n 'List posts in a date range',\n (yargs: Argv) => {\n return yargs\n .option('startDate', {\n describe: 'Start date (ISO 8601 with explicit offset, or use --timezone). Default: 30 days ago',\n type: 'string',\n })\n .option('endDate', {\n describe: 'End date (ISO 8601 with explicit offset, or use --timezone). Default: 30 days from now',\n type: 'string',\n })\n .option('timezone', {\n describe:\n `IANA timezone name (e.g. ${BRAND.exampleTimezone}) used to interpret --startDate/--endDate when they have no explicit offset`,\n type: 'string',\n })\n .option('customer', {\n describe: 'Customer (group) ID (optional)',\n type: 'string',\n })\n .example('$0 posts:list', 'List posts (last 30 days to next 30 days)')\n .example(\n '$0 posts:list --startDate \"2026-01-01T00:00:00Z\" --endDate \"2026-12-31T23:59:59Z\"',\n 'List posts for a specific date range'\n )\n .example(\n '$0 posts:list --customer \"customer-id\"',\n 'List posts for a specific customer'\n );\n },\n listPosts as any\n )\n .command(\n 'posts:delete <id>',\n 'Delete one post (one channel). Other channels of the same group stay scheduled',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID to delete (the id field of posts:list)',\n type: 'string',\n })\n .example('$0 posts:delete abc123', 'Delete only post abc123, with its thread or comments')\n .epilogue('To delete a post from every channel it went to, use posts:delete-group <group>.');\n },\n deletePost as any\n )\n .command(\n 'posts:delete-group <group>',\n 'Delete a whole group: the post on every channel it went to',\n (yargs: Argv) => {\n return yargs\n .positional('group', {\n describe: 'Group ID (the group field of posts:list)',\n type: 'string',\n })\n .example('$0 posts:delete-group grp_9f8e7d6c', 'Delete every channel of group grp_9f8e7d6c');\n },\n deletePostGroup as any\n )\n .command(\n 'posts:find-slot <id>',\n 'Find the next free publishing slot for an integration',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .example(\n '$0 posts:find-slot integration-123',\n 'Returns {\"date\": \"...\"} — the next free datetime, usable as posts:create --date'\n );\n },\n findSlot as any\n )\n .command(\n 'posts:missing <id>',\n 'List available content from the provider for a post with missing release ID',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .example(\n '$0 posts:missing post-123',\n 'Get available content to connect to a post'\n );\n },\n getMissingContent as any\n )\n .command(\n 'posts:status <id>',\n 'Change a post status between draft and schedule',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .option('status', {\n alias: 's',\n describe: 'New status: \"draft\" or \"schedule\"',\n type: 'string',\n choices: ['draft', 'schedule'],\n demandOption: true,\n })\n .example(\n '$0 posts:status post-123 --status draft',\n 'Move a scheduled post back to draft (stops the running workflow)'\n )\n .example(\n '$0 posts:status post-123 --status schedule',\n 'Schedule a draft post so it is queued for publishing'\n );\n },\n changePostStatus as any\n )\n .command(\n 'posts:connect <id>',\n 'Connect a post to its published content by updating the release ID',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .option('release-id', {\n describe: 'The platform-specific content ID to connect',\n type: 'string',\n demandOption: true,\n })\n .example(\n '$0 posts:connect post-123 --release-id \"7321456789012345678\"',\n 'Connect a post to its published content'\n );\n },\n connectPost as any\n )\n .command(\n 'integrations:list',\n 'List all connected integrations',\n (yargs: Argv) => {\n return yargs\n .option('group', {\n describe: 'Filter integrations by group (customer) ID',\n type: 'string',\n })\n .example('$0 integrations:list', 'List all connected integrations')\n .example(\n '$0 integrations:list --group \"customer-id\"',\n 'List integrations for a specific group'\n );\n },\n listIntegrations as any\n )\n .command(\n 'integrations:groups',\n 'List all groups (customers)',\n {},\n listGroups as any\n )\n .command(\n 'integrations:settings <id>',\n 'Get settings schema, rules, max length and tools for an integration',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .example(\n '$0 integrations:settings youtube-456',\n 'Get settings schema for a YouTube integration'\n )\n .example(\n '$0 integrations:settings instagram-123',\n 'Get settings schema and tools for an Instagram integration'\n );\n },\n getIntegrationSettings as any\n )\n .command(\n 'integrations:trigger <id> <method>',\n 'Trigger an integration tool to fetch additional data',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .positional('method', {\n describe: 'Method name from the \"tools\" array of integrations:settings',\n type: 'string',\n })\n .option('data', {\n alias: 'd',\n describe: 'Data to pass to the tool as JSON string',\n type: 'string',\n })\n .example(\n '$0 integrations:trigger instagram-123 audioSearch -d \\'{\"q\":\"lofi\",\"type\":\"music\"}\\'',\n 'Search Instagram audio for a Reel (the only tool on a supported channel)'\n );\n },\n triggerIntegrationTool as any\n )\n .command(\n 'analytics:platform <id>',\n 'Get analytics for a specific integration/channel',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Integration ID',\n type: 'string',\n })\n .option('days', {\n alias: ['d', 'date'],\n describe: 'Number of days to look back (default: 7)',\n type: 'string',\n default: '7',\n })\n .example(\n '$0 analytics:platform integration-123',\n 'Get last 7 days of analytics'\n )\n .example(\n '$0 analytics:platform integration-123 -d 30',\n 'Get last 30 days of analytics'\n );\n },\n getAnalytics as any\n )\n .command(\n 'analytics:post <id>',\n 'Get analytics for a specific post',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: 'Post ID',\n type: 'string',\n })\n .option('days', {\n alias: ['d', 'date'],\n describe: 'Number of days to look back (default: 7)',\n type: 'string',\n default: '7',\n })\n .example(\n '$0 analytics:post post-123',\n 'Get last 7 days of post analytics'\n )\n .example(\n '$0 analytics:post post-123 -d 30',\n 'Get last 30 days of post analytics'\n );\n },\n getPostAnalytics as any\n )\n .command(\n 'upload <file>',\n 'Upload a media file; returns the URL to pass to posts:create -m',\n (yargs: Argv) => {\n return yargs\n .positional('file', {\n describe: 'File path to upload (jpeg/png/gif/webp/avif/bmp/tiff up to 10 MB, mp4 up to 1 GB)',\n type: 'string',\n })\n .example('$0 upload ./image.png', 'Upload an image; use the returned .path in posts:create -m');\n },\n uploadFile as any\n )\n .command(\n 'upload:link',\n 'Get a browser upload link for a file that is not on this machine (e.g. on a phone)',\n (yargs: Argv) => {\n return yargs.example(\n '$0 upload:link',\n 'Returns {id, url, expiresAt}. Show the url to the person; they drop files on it, signed out. Then run upload:files <id>'\n );\n },\n createUploadLink as any\n )\n .command(\n 'upload:files <id>',\n 'List the files that arrived through an upload link; each .path goes to posts:create -m',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: `The id returned by \"${BRAND.cli} upload:link\"`,\n type: 'string',\n })\n .example(\n '$0 upload:files kR3mQ7xP2nLa',\n 'Returns {status, count, files:[{id,name,path,type}]}; status \"empty\" means nothing has arrived yet'\n );\n },\n listUploadLinkFiles as any\n )\n .command(\n 'workspaces:list',\n 'List the workspaces this credential can act on (\"current\" marks the active one)',\n {},\n listWorkspaces as any\n )\n .command(\n 'workspaces:use <id>',\n 'Make every following command act on this workspace',\n (yargs: Argv) => {\n return yargs\n .positional('id', {\n describe: `Workspace id, from \"${BRAND.cli} workspaces:list\"`,\n type: 'string',\n })\n .example('$0 workspaces:use 3f2a…', 'Switch the CLI to that workspace');\n },\n useWorkspace as any\n )\n .command(\n 'workspaces:current',\n 'Show the workspace commands act on now',\n {},\n currentWorkspace as any\n )\n .command(\n 'billing:plans',\n 'Show the Postemi plans: prices, limits, the trial rule and the current tier',\n {},\n billingPlans as any\n )\n .command(\n 'billing:subscribe',\n 'Get a Stripe Checkout link for a plan. Nothing is charged; the subscriber opens the link and pays with their own wallet or card',\n (yargs: Argv) => {\n return yargs\n .option('tier', {\n describe: `The plan: ${BRAND.tierList} (see \"${BRAND.cli} billing:plans\")`,\n type: 'string',\n demandOption: true,\n })\n .option('period', {\n describe: 'How often the plan renews',\n type: 'string',\n choices: ['monthly', 'yearly'],\n demandOption: true,\n })\n .option('open', {\n describe: 'Also open the link in this machine\\'s browser',\n type: 'boolean',\n default: false,\n })\n .example(\n '$0 billing:subscribe --tier pro --period yearly',\n 'Print the checkout link as JSON'\n )\n .example(\n '$0 billing:subscribe --tier pro --period yearly --open',\n 'Print it and open it in the browser'\n );\n },\n billingSubscribe as any\n )\n .command(\n 'billing:status',\n 'Show the subscription state (none, trialing, active, past_due, read_only, cancelled) and any unpaid checkout',\n {},\n billingStatus as any\n )\n .command(\n 'billing:manage',\n 'Get a link to the Stripe billing portal (plan change, cancel, invoices, card)',\n (yargs: Argv) => {\n return yargs.option('open', {\n describe: 'Also open the link in this machine\\'s browser',\n type: 'boolean',\n default: false,\n });\n },\n billingManage as any\n )\n .command(\n 'skills <command>',\n `Optional agent skills: install them into Claude Code, Codex, Cursor or Grok Build`,\n (yargs: Argv) => {\n const target = (y: Argv) =>\n y\n .positional('skills', {\n describe: 'writing (with templates), growth, all, or core',\n type: 'string',\n array: true,\n })\n .option('agent', {\n describe: 'Only these agents: claude, codex, cursor, grok, or all (skips the question)',\n type: 'string',\n array: true,\n })\n .option('yes', { alias: 'y', describe: 'Ask nothing; use every agent found', type: 'boolean', default: false })\n .option('json', { describe: 'Run as an agent or script: never ask', type: 'boolean', default: false });\n return yargs\n .command('list', 'Show the core and optional skills, and where each is installed', {}, skillsList as any)\n .command(\n 'add [skills..]',\n 'Install skills (writing, growth, all); asks which when you name none',\n (y: Argv) =>\n target(y)\n .example('$0 skills add writing', 'Writing and template skills, plus the core skill')\n .example('$0 skills add all --agent claude --yes', 'Both optional skills, Claude Code only, no questions'),\n skillsAdd as any\n )\n .command('remove [skills..]', 'Remove installed skills (writing, growth, all, core)', target, skillsRemove as any)\n .demandCommand(1, `Use: ${BRAND.cli} skills list | add | remove`);\n },\n () => {}\n )\n .command(\n 'config:set <key> <value>',\n `Save a CLI setting to ~/${BRAND.configDirName}/config.json`,\n (yargs: Argv) => {\n return yargs\n .positional('key', {\n describe: `Setting name. Known: \"timezone\" (an IANA name), \"workspace\" (an id; prefer \"${BRAND.cli} workspaces:use\")`,\n type: 'string',\n })\n .positional('value', {\n describe: 'Setting value',\n type: 'string',\n })\n .example(\n `$0 config:set timezone ${BRAND.exampleTimezone}`,\n `Interpret dates written without an explicit offset in ${BRAND.exampleTimezoneCity} time`\n );\n },\n configSet as any\n )\n .command(\n 'config:get [key]',\n 'Show saved CLI settings (all, or one key)',\n (yargs: Argv) => {\n return yargs\n .positional('key', {\n describe: 'Setting name. Known: \"timezone\"',\n type: 'string',\n })\n .example('$0 config:get', 'Show all saved settings as JSON')\n .example('$0 config:get timezone', 'Show the saved timezone');\n },\n configGet as any\n )\n .command(\n 'auth:login',\n 'Authenticate using the OAuth2 device flow (opens a browser)',\n (yargs: Argv) => {\n return yargs\n .option('auth-server', {\n describe: `Auth server URL (default: ${BRAND.defaultApiUrl})`,\n type: 'string',\n })\n .option('json', {\n describe: 'Run as an agent or script: ask no setup questions after the login',\n type: 'boolean',\n default: false,\n })\n .example(\n '$0 auth:login',\n 'Login via OAuth2 device flow'\n );\n },\n authLogin as any\n )\n .command(\n 'auth:signup',\n `Create a NEW ${BRAND.name} account with a code sent to the e-mail address, and store its key. No free trial: the next step is billing:subscribe`,\n (yargs: Argv) => {\n return yargs\n .option('email', {\n describe: 'E-mail address of the new account; the code is sent there',\n type: 'string',\n demandOption: true,\n })\n .option('code', {\n describe: 'The six-digit code from the e-mail (asked for when omitted on a terminal)',\n type: 'string',\n })\n .option('accept-terms', {\n describe: `The person has read ${BRAND.termsUrl} and ${BRAND.privacyUrl} and agrees`,\n type: 'boolean',\n default: false,\n })\n /*\n NOT --workspace: that is the global flag and takes a workspace ID\n (the middleware above turns it into POSTEMI_WORKSPACE). A name here\n under the same flag would be read as an id by every other command.\n */\n .option('workspace-name', {\n describe: 'Name of the new workspace (default: the part of the address before the @)',\n type: 'string',\n })\n .option('timezone', {\n describe: `The person's IANA timezone for the account, e.g. ${BRAND.exampleTimezone} (default: the one saved by config:set, else the system time zone)`,\n type: 'string',\n })\n .option('language', {\n describe: 'Language of the e-mail and the account',\n type: 'string',\n choices: ['hu', 'en', 'de', 'cs'],\n })\n .option('api-url', {\n describe: `API base URL (default: ${envName('API_URL')}, then ${BRAND.defaultApiUrl})`,\n type: 'string',\n })\n .example(\n '$0 auth:signup --email anna@example.com',\n 'Send the code, then ask for it and for the terms on the terminal'\n )\n .example(\n `$0 auth:signup --email anna@example.com --code 123456 --accept-terms --workspace-name \"Anna's Cafe\"`,\n 'Finish in one run (an agent, after the person read the code and agreed)'\n );\n },\n authSignup as any\n )\n .command(\n 'auth:logout',\n 'Remove stored OAuth2 credentials',\n {},\n authLogout as any\n )\n .command(\n 'auth:status',\n 'Show current authentication status and verify the credentials',\n {},\n authStatus as any\n )\n .demandCommand(1, `Specify a command. Run \"${BRAND.cli} --help\" for the list.`)\n .strict()\n .help()\n .alias('h', 'help')\n .version()\n .alias('v', 'version')\n .wrap(Math.min(110, process.stdout.columns || 110))\n .epilogue(\n `Output contract: results are JSON on stdout; status and errors go to stderr. Every failure exits 1.\\n\\nAuthentication:\\n Device login: ${BRAND.cli} auth:login\\n API Key: export ${envName('API_KEY')}=your_api_key\\n\\nWorkspaces: a credential may reach several. \"${BRAND.cli} workspaces:list\" shows them, \"${BRAND.cli} workspaces:use <id>\" picks the one commands act on (or pass --workspace <id> / ${envName('WORKSPACE')}).\\n\\nDates: ALWAYS pass an explicit offset (\"2026-12-31T12:00:00Z\" / \"+01:00\"), or pass --timezone with an IANA name (e.g. ${BRAND.exampleTimezone}). A date without either is resolved via ${envName('TIMEZONE')}, then the timezone saved by \"${BRAND.cli} config:set timezone\" — and is an ERROR when none of those is set. Numeric offsets are never accepted as timezone values.\\n\\nFor more information, visit: ${BRAND.homepage}`\n )\n .parse();\n","import { randomUUID } from 'crypto';\nimport { BRAND, networkError } from './brand';\n\nexport interface PostemiConfig {\n apiKey: string;\n apiUrl?: string;\n /**\n * The workspace every request is about, sent as the `showorg` header.\n * Required by the API when the key spans several workspaces; harmless when\n * it spans one. See `postemi workspaces:list` / `postemi workspaces:use`.\n */\n workspaceId?: string;\n}\n\n/** `GET /public/v1/workspaces`: what the credential can act on. */\nexport interface Workspace {\n id: string;\n name: string;\n role: string;\n /** True for the workspace this request acted on. */\n current: boolean;\n}\n\n/**\n * The sentence a person should read out of an error body.\n *\n * The API answers with JSON such as `{\"statusCode\":402,\"message\":\"The monthly\n * limit is ...\",\"url\":\"...\"}`, and printing that whole object buried the one\n * line that says what happened and what to do. This takes `message` (joined\n * when Nest sends a list of validation messages), then `msg`, then `detail`,\n * and falls back to the raw body when it is not JSON or has none of them.\n * The raw body stays on `ApiError.body` for anything that needs it.\n */\nexport function serverSentence(body: string): string {\n const raw = (body ?? '').trim();\n let json: any = null;\n try {\n json = JSON.parse(raw);\n } catch {\n return raw;\n }\n const pick = (value: unknown): string | null => {\n if (typeof value === 'string' && value.trim()) return value.trim();\n if (Array.isArray(value)) {\n const parts = value.filter((part) => typeof part === 'string' && part.trim());\n return parts.length ? parts.join('; ') : null;\n }\n return null;\n };\n return pick(json?.message) ?? pick(json?.msg) ?? pick(json?.detail) ?? raw;\n}\n\n/**\n * Thrown for any non-2xx answer from the API. `status` survives so command\n * handlers can say something more useful than the raw body. Only a 401 means\n * the credential was rejected and points at `postemi auth:login`; a 403 is a\n * valid credential that may not do this, and logging in again changes nothing.\n */\nexport class ApiError extends Error {\n constructor(public status: number, public body: string) {\n super(`API Error (${status}): ${serverSentence(body)}`);\n this.name = 'ApiError';\n }\n\n /** The credential itself was rejected (missing, unknown, expired). 401 only. */\n get isAuthError() {\n return this.status === 401;\n }\n\n /**\n * A valid credential that is not allowed to do this: a scoped key on a\n * route that needs a full-workspace one, a role below the payer, a closed\n * registration. The body says which; the fix is never `auth:login`.\n */\n get isForbidden() {\n return this.status === 403;\n }\n\n /** The body as JSON when it is JSON, else null. */\n private get json(): any {\n try {\n return JSON.parse(this.body);\n } catch {\n return null;\n }\n }\n\n /**\n * The 403 of the scope guard: the credential is VALID and lacks a\n * permission. Logging in again changes nothing; a key with the scope\n * (or a higher role for its owner) does. Null for any other answer.\n */\n get missingScope(): { missing: string[]; granted: string[]; role?: string } | null {\n if (this.status !== 403) return null;\n const body = this.json;\n const msg = String(body?.msg ?? body?.message ?? this.body);\n if (!/missing the required permission/i.test(msg)) return null;\n const required: string[] = Array.isArray(body?.required) ? body.required : [];\n const granted: string[] = Array.isArray(body?.granted) ? body.granted : [];\n const fromText = (msg.split(':')[1] || '')\n .split(',')\n .map((scope) => scope.trim())\n .filter(Boolean);\n const missing = required.length\n ? required.filter((scope) => !granted.includes(scope))\n : fromText;\n return { missing, granted, role: body?.role };\n }\n\n /**\n * The 401 of the plan gate: the credential is valid, the workspace has no\n * plan with API access. The billing commands still work.\n */\n get isPlanMissing() {\n return (\n this.status === 401 &&\n /no subscription found|does not include api access|no plan with api access/i.test(\n this.body\n )\n );\n }\n\n get isRateLimit() {\n return this.status === 429;\n }\n\n /**\n * The 403 a multi-workspace key gets when no workspace was named. Not an\n * auth failure: the key is fine, the request is missing a choice, and the\n * fix is `workspaces:use`, not `auth:login`.\n */\n get isWorkspaceChoice() {\n return (\n this.status === 403 && this.body.includes('spans several workspaces')\n );\n }\n}\n\n/** `POST /public/v1/upload-link`: the page to show the person, and its id. */\nexport interface UploadLink {\n id: string;\n url: string;\n expiresAt: string;\n}\n\n/** `GET /public/v1/upload-link/:id`: what arrived through the link so far. */\nexport interface UploadLinkFiles {\n id: string;\n status: 'empty' | 'ready';\n count: number;\n files: Array<{ id: string; name: string; path: string; type: string }>;\n}\n\n/** `GET /public/v1/plans`: the four plans and the workspace's current tier. */\nexport interface Plans {\n currency: string;\n trial: string;\n trialDays: number;\n trialAvailableHere: boolean;\n current: { tier: string; plan: string; slug: string | null };\n plans: Array<{\n tier: string;\n plan: string;\n slug: string;\n monthly: { amount: number; formatted: string };\n yearly: { amount: number; formatted: string; savesPerYear: number };\n limits: Record<string, number | boolean | null>;\n }>;\n}\n\n/** `POST /public/v1/subscriptions/checkout`: the link the PERSON opens. */\nexport interface SubscriptionCheckout {\n status: 'requires_payment';\n checkoutUrl: string;\n checkoutId: string;\n tier: string;\n plan: string;\n period: 'MONTHLY' | 'YEARLY';\n amount: number;\n currency: string;\n trial: boolean;\n trialDays: number;\n expiresAt: string;\n /** False for a plan without API or MCP access (Basic): tell the person before they pay. */\n apiAndMcpAccess?: boolean;\n /** Set when the plan has no API access; the sentence to pass on. */\n note?: string | null;\n}\n\n/** `GET /public/v1/subscription`: where the workspace stands. */\nexport interface SubscriptionState {\n state: 'none' | 'trialing' | 'active' | 'past_due' | 'read_only' | 'cancelled';\n tier: string | null;\n plan: string | null;\n period: 'MONTHLY' | 'YEARLY' | null;\n currentPeriodEnd: string | null;\n cancelAt: string | null;\n payerIsCaller: boolean;\n noPayerYet: boolean;\n pendingCheckout: {\n checkoutId: string;\n checkoutUrl: string;\n plan: string;\n period: string | null;\n startedAt: string;\n expiresAt: string;\n } | null;\n apiAndMcpAccess: boolean;\n}\n\nexport class PostemiAPI {\n private apiKey: string;\n private apiUrl: string;\n private workspaceId?: string;\n\n constructor(config: PostemiConfig) {\n this.apiKey = config.apiKey;\n this.workspaceId = config.workspaceId;\n // `postemi auth:login` stores the base in credentials.json; a key set by\n // hand uses POSTEMI_API_URL (config.ts) or this default.\n this.apiUrl = config.apiUrl || BRAND.defaultApiUrl;\n }\n\n private async request(endpoint: string, options: any = {}) {\n const url = `${this.apiUrl}${endpoint}`;\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: this.apiKey,\n ...this.workspaceHeader(),\n ...options.headers,\n };\n\n let response: Response;\n try {\n response = await fetch(url, {\n ...options,\n headers,\n });\n } catch (error: any) {\n throw new Error(networkError(`Could not reach ${this.apiUrl}`, error));\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new ApiError(response.status, error);\n }\n\n return await response.json();\n }\n\n /**\n * ONE IDEMPOTENCY KEY PER INVOCATION, REUSED ON ITS OWN RETRY.\n *\n * A timeout cannot tell a lost request from a lost answer, and resending a\n * post blindly can publish it twice on a real account. So the post carries\n * an `Idempotency-Key` (a fresh UUID for this command), and the one retry\n * below, after a network failure or a 5xx, sends the SAME key: the server\n * then hands back the post it already created instead of making another.\n */\n async createPost(data: any, idempotencyKey: string = randomUUID()) {\n const send = () =>\n this.request('/public/v1/posts', {\n method: 'POST',\n body: JSON.stringify(data),\n headers: { 'Idempotency-Key': idempotencyKey },\n });\n\n try {\n return await send();\n } catch (error: any) {\n const retryable =\n !(error instanceof ApiError) ||\n [500, 502, 503, 504].includes(error.status);\n if (!retryable) throw error;\n await new Promise((resolve) => setTimeout(resolve, 1500));\n return send();\n }\n }\n\n async listPosts(filters: any = {}) {\n const queryString = new URLSearchParams(\n Object.entries(filters).reduce((acc, [key, value]) => {\n if (value !== undefined && value !== null) {\n acc[key] = String(value);\n }\n return acc;\n }, {} as Record<string, string>)\n ).toString();\n\n const endpoint = queryString\n ? `/public/v1/posts?${queryString}`\n : '/public/v1/posts';\n\n return this.request(endpoint, {\n method: 'GET',\n });\n }\n\n /** One post (one channel) with its thread or comments. Other channels of its group stay. */\n async deletePost(id: string) {\n return this.request(`/public/v1/posts/${encodeURIComponent(id)}`, {\n method: 'DELETE',\n });\n }\n\n /** The whole group: every channel of one multi-channel post. */\n async deletePostGroup(group: string) {\n return this.request(`/public/v1/posts/group/${encodeURIComponent(group)}`, {\n method: 'DELETE',\n });\n }\n\n async findSlot(integrationId: string) {\n return this.request(\n `/public/v1/find-slot/${encodeURIComponent(integrationId)}`,\n {\n method: 'GET',\n }\n );\n }\n\n async upload(file: Buffer, filename: string) {\n const formData = new FormData();\n const extension = filename.split('.').pop()?.toLowerCase() || '';\n\n // The server sniffs magic bytes and accepts exactly eight types; this map\n // only sets the declared Content-Type for the multipart part.\n const mimeTypes: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n avif: 'image/avif',\n bmp: 'image/bmp',\n tif: 'image/tiff',\n tiff: 'image/tiff',\n mp4: 'video/mp4',\n };\n\n const type = mimeTypes[extension] || 'application/octet-stream';\n\n const blob = new Blob([new Uint8Array(file)], { type });\n formData.append('file', blob, filename);\n\n const url = `${this.apiUrl}/public/v1/upload`;\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n body: formData,\n headers: {\n Authorization: this.apiKey,\n ...this.workspaceHeader(),\n },\n });\n } catch (error: any) {\n throw new Error(networkError(`Could not reach ${this.apiUrl}`, error));\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new ApiError(response.status, error);\n }\n\n return await response.json();\n }\n\n private workspaceHeader(): Record<string, string> {\n return this.workspaceId ? { showorg: this.workspaceId } : {};\n }\n\n async listWorkspaces(): Promise<Workspace[]> {\n return (await this.request('/public/v1/workspaces', {\n method: 'GET',\n })) as Workspace[];\n }\n\n async getMissingContent(postId: string) {\n return this.request(`/public/v1/posts/${postId}/missing`, {\n method: 'GET',\n });\n }\n\n async updateReleaseId(postId: string, releaseId: string) {\n return this.request(`/public/v1/posts/${postId}/release-id`, {\n method: 'PUT',\n body: JSON.stringify({ releaseId }),\n });\n }\n\n async changePostStatus(postId: string, status: 'draft' | 'schedule') {\n return this.request(`/public/v1/posts/${postId}/status`, {\n method: 'PUT',\n body: JSON.stringify({ status }),\n });\n }\n\n async getAnalytics(integrationId: string, date: string) {\n return this.request(`/public/v1/analytics/${integrationId}?date=${encodeURIComponent(date)}`, {\n method: 'GET',\n });\n }\n\n async getPostAnalytics(postId: string, date: string) {\n return this.request(`/public/v1/analytics/post/${postId}?date=${encodeURIComponent(date)}`, {\n method: 'GET',\n });\n }\n\n async listIntegrations(group?: string) {\n const query = group ? `?group=${encodeURIComponent(group)}` : '';\n return this.request(`/public/v1/integrations${query}`, {\n method: 'GET',\n });\n }\n\n async listGroups() {\n return this.request('/public/v1/groups', {\n method: 'GET',\n });\n }\n\n async getIntegrationSettings(integrationId: string) {\n return this.request(`/public/v1/integration-settings/${integrationId}`, {\n method: 'GET',\n });\n }\n\n async triggerIntegrationTool(\n integrationId: string,\n methodName: string,\n data: Record<string, string>\n ) {\n return this.request(`/public/v1/integration-trigger/${integrationId}`, {\n method: 'POST',\n body: JSON.stringify({ methodName, data }),\n });\n }\n\n /**\n * A browser upload link for a file this process does not hold. `upload`\n * covers the file on disk; this covers the one on the person's phone.\n */\n async createUploadLink(): Promise<UploadLink> {\n return (await this.request('/public/v1/upload-link', {\n method: 'POST',\n body: JSON.stringify({}),\n })) as UploadLink;\n }\n\n async getUploadLinkFiles(id: string): Promise<UploadLinkFiles> {\n return (await this.request(\n `/public/v1/upload-link/${encodeURIComponent(id)}`,\n { method: 'GET' }\n )) as UploadLinkFiles;\n }\n\n /*\n BILLING. These four answer without the plan gate on the server, so they\n work for a workspace that has no subscription yet: they are how it gets\n one. The checkout and the portal need an OAuth token or a full-workspace\n key (the \"whole workspace\" box on the `auth:login` approval page);\n a scoped key is refused with a sentence that says so.\n */\n\n async getPlans(): Promise<Plans> {\n return (await this.request('/public/v1/plans', { method: 'GET' })) as Plans;\n }\n\n async getSubscription(): Promise<SubscriptionState> {\n return (await this.request('/public/v1/subscription', {\n method: 'GET',\n })) as SubscriptionState;\n }\n\n /** Nothing is charged by this call; the person pays on the returned link. */\n async createSubscriptionCheckout(\n tier: string,\n period: string\n ): Promise<SubscriptionCheckout> {\n return (await this.request('/public/v1/subscriptions/checkout', {\n method: 'POST',\n body: JSON.stringify({ tier, period }),\n })) as SubscriptionCheckout;\n }\n\n async getSubscriptionPortal(): Promise<{ portalUrl: string; note: string }> {\n return (await this.request('/public/v1/subscription/portal', {\n method: 'GET',\n })) as { portalUrl: string; note: string };\n }\n}\n","/**\n * The Postemi values the CLI uses in more than one place: the name a person\n * reads, the command they type, the environment variables, the config\n * folder, the default API host and the links.\n */\n\ninterface Brand {\n /** The product name in a sentence. */\n name: string;\n /** The command a person types. */\n cli: string;\n /** Prefix of the environment variables (`POSTEMI_API_KEY`). */\n envPrefix: string;\n /** Folder under the home directory for credentials.json and config.json. */\n configDirName: string;\n /** API base when nothing else says otherwise. */\n defaultApiUrl: string;\n /** Where `auth:login` starts the device flow. */\n defaultAuthServer: string;\n /** Shown on the approval page. */\n clientName: string;\n homepage: string;\n termsUrl: string;\n privacyUrl: string;\n /** Where a person creates an account in the browser. */\n signupUrl: string;\n /** The IANA zone used in examples. */\n exampleTimezone: string;\n /** \"in London time\" in the config:set example. */\n exampleTimezoneCity: string;\n /** The plan slugs as the help text names them. */\n tierList: string;\n /** The plan without API access, by name. */\n basicPlanName: string;\n}\n\nexport const BRAND: Brand = {\n name: 'Postemi',\n cli: 'postemi',\n envPrefix: 'POSTEMI',\n configDirName: '.postemi',\n // api.postemi.com serves the API at the root (its proxy adds /api).\n defaultApiUrl: 'https://api.postemi.com',\n defaultAuthServer: 'https://api.postemi.com',\n clientName: 'Postemi CLI',\n homepage: 'https://postemi.com',\n termsUrl: 'https://postemi.com/terms',\n privacyUrl: 'https://postemi.com/privacy',\n signupUrl: 'https://postemi.com/app/signup',\n exampleTimezone: 'Europe/London',\n exampleTimezoneCity: 'London',\n tierList: 'basic, pro, creator or team',\n basicPlanName: 'Basic',\n};\n\n/** `API_KEY` -> `POSTEMI_API_KEY`. */\nexport const envName = (name: string): string => `${BRAND.envPrefix}_${name}`;\n\n/** Read `POSTEMI_<name>` from the environment. */\nexport function readEnv(name: string): string | undefined {\n return process.env[envName(name)];\n}\n\n/** Write `POSTEMI_<name>` (the `--workspace` middleware uses it). */\nexport function writeEnv(name: string, value: string): void {\n process.env[envName(name)] = value;\n}\n\n/*\n PLAN NAMES. The CLI shows the plans as Basic, Pro, Creator and Team. The\n API knows `pro` and `creator` by those names but the other two by older\n slugs, so `basic` and `team` are translated before the request. Only these\n display names are mapped.\n*/\nconst TIER_ALIASES: Record<string, string> = {\n basic: 'alap',\n team: 'csapat',\n};\n\nexport function tierForApi(tier: string): string {\n return TIER_ALIASES[tier.trim().toLowerCase()] ?? tier;\n}\n\n/*\n A failed fetch() says only \"fetch failed\"; the reason is in `error.cause`.\n This names it (a host that does not resolve, a refused connection, a\n timeout).\n*/\nconst NETWORK_REASONS: Record<string, string> = {\n ENOTFOUND: 'the host name does not resolve',\n EAI_AGAIN: 'the host name could not be looked up',\n ECONNREFUSED: 'the connection was refused',\n ECONNRESET: 'the connection was reset',\n ETIMEDOUT: 'the connection timed out',\n UND_ERR_CONNECT_TIMEOUT: 'the connection timed out',\n CERT_HAS_EXPIRED: 'the TLS certificate has expired',\n DEPTH_ZERO_SELF_SIGNED_CERT: 'the TLS certificate is self-signed',\n};\n\nexport function networkError(prefix: string, error: any, variable = 'API_URL'): string {\n const plain = `${prefix}: ${error?.message}`;\n const code: string | undefined = error?.cause?.code ?? error?.code;\n const reason = code ? NETWORK_REASONS[code] ?? code : null;\n return reason\n ? `${prefix}: ${reason} (${code}). Check the connection, or point ${envName(variable)} at another server.`\n : plain;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { createInterface } from 'readline';\nimport { getSetting, saveSetting } from '../settings';\nimport { result, status } from '../output';\nimport { assertIanaTimezone } from '../dates';\nimport { ApiError, PostemiAPI, serverSentence, SubscriptionState, Workspace } from '../api';\nimport { getWorkspaceId } from '../config';\nimport { BRAND, envName, networkError, readEnv } from '../brand';\nimport { offerSkillsAfterLogin } from './skills';\n\nconst CREDENTIALS_DIR = join(homedir(), BRAND.configDirName);\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json');\n\n/**\n * Where the device flow lives: `POST /device/code`, `POST /device/token`, and\n * an approval page on the web app where the person picks which workspace and\n * channels the key may reach. Override with `POSTEMI_AUTH_SERVER`.\n */\nconst DEFAULT_AUTH_SERVER = BRAND.defaultAuthServer;\n\n/** Used when neither the credentials file nor POSTEMI_API_URL names one. */\nconst DEFAULT_API_URL = BRAND.defaultApiUrl;\n\ninterface StoredCredentials {\n accessToken: string;\n apiUrl: string;\n organizationId?: string;\n}\n\nexport function loadCredentials(): StoredCredentials | null {\n try {\n if (!existsSync(CREDENTIALS_FILE)) return null;\n const data = JSON.parse(readFileSync(CREDENTIALS_FILE, 'utf-8'));\n if (!data.accessToken) return null;\n return data;\n } catch {\n return null;\n }\n}\n\nexport function saveCredentials(credentials: StoredCredentials): void {\n if (!existsSync(CREDENTIALS_DIR)) {\n mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });\n }\n writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { encoding: 'utf-8', mode: 0o600 });\n // Ensure permissions even if file already existed\n chmodSync(CREDENTIALS_FILE, 0o600);\n}\n\nfunction deleteCredentials(): void {\n if (existsSync(CREDENTIALS_FILE)) {\n unlinkSync(CREDENTIALS_FILE);\n }\n}\n\n/*\n SPAWNED WITH THE URL AS AN ARGUMENT, NEVER INTERPOLATED INTO A SHELL STRING.\n\n Never build `open \"${url}\"` for exec(), which runs it through a shell. The\n url is not ours -- it comes from whatever\n POSTEMI_AUTH_SERVER points at -- so a hostile or intercepted auth server could\n close the quote and append a command that runs on the machine of whoever\n typed `postemi auth:login`. Better quoting is not the fix; the shell is.\n\n spawn() with an argv array involves no shell, so the url stays one argument\n whatever it contains. Windows is the exception: `start` is a cmd builtin\n rather than a program, so it needs cmd -- and there the url is passed AS AN\n ARGUMENT to cmd rather than pasted into the command string.\n*/\nexport function openBrowser(url: string): void {\n const { spawn } = require('child_process');\n const opts = { stdio: 'ignore' as const, detached: true };\n\n const child =\n process.platform === 'darwin'\n ? spawn('open', [url], opts)\n : process.platform === 'win32'\n ? spawn('cmd', ['/c', 'start', '', url], opts)\n : spawn('xdg-open', [url], opts);\n\n // A machine with no browser (a server, a container) must not take the login\n // down with it. The url is printed for the user either way.\n child.on('error', () => {});\n child.unref();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction ask(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) =>\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n })\n );\n}\n\n/**\n * One-time scheduling-timezone setup, run after a successful login.\n *\n * Dates written without an explicit offset are refused unless a timezone is\n * configured (see dates.ts), so a fresh login on a TTY is the moment to set\n * one: detect the machine's zone, ask the human to confirm it, save it to\n * `~/.postemi/config.json`. Skipped when a timezone is already saved, and\n * skipped entirely off-TTY — scripts and agents must use `--timezone`,\n * `POSTEMI_TIMEZONE` or `postemi config:set timezone`.\n */\nasync function maybeConfigureTimezone(): Promise<void> {\n if (getSetting('timezone')) return;\n if (!process.stdin.isTTY || !process.stderr.isTTY) return;\n\n const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n const answer = (await ask(`\\nScheduling timezone: ${detected} — OK? [Y/n] `))\n .trim()\n .toLowerCase();\n\n let timezone = detected;\n if (answer === 'n' || answer === 'no') {\n const typed = (\n await ask(`Enter an IANA timezone name (e.g. ${BRAND.exampleTimezone}), or leave empty to skip: `)\n ).trim();\n if (!typed) {\n console.error(\n `Skipped. Dates without an explicit offset will be refused until you run: ${BRAND.cli} config:set timezone <IANA name>`\n );\n return;\n }\n try {\n timezone = assertIanaTimezone(typed, 'auth:login');\n } catch (error: any) {\n console.error(error.message);\n console.error(\n `Skipped. Set it later with: ${BRAND.cli} config:set timezone <IANA name>`\n );\n return;\n }\n } else if (answer && answer !== 'y' && answer !== 'yes') {\n console.error(\n `Skipped. Set it later with: ${BRAND.cli} config:set timezone <IANA name>`\n );\n return;\n }\n\n saveSetting('timezone', timezone);\n console.error(\n `✅ Scheduling timezone saved: ${timezone} (change it with \"${BRAND.cli} config:set timezone <IANA name>\")`\n );\n}\n\n/**\n * Which workspace the new key acts on, decided right after login.\n *\n * The approval page can grant one workspace or all of them. With one there\n * is nothing to ask and the id is stored so `auth:status` can name it. With\n * several the API refuses every request that does not name one, so the\n * choice is made here, on a TTY, and stored; off-TTY the hint says how.\n * Never fatal: a login that worked stays worked.\n */\nasync function chooseWorkspace(creds: StoredCredentials): Promise<void> {\n let workspaces: Workspace[];\n try {\n workspaces = await new PostemiAPI({\n apiKey: creds.accessToken,\n apiUrl: creds.apiUrl,\n }).listWorkspaces();\n } catch {\n return;\n }\n\n if (workspaces.length === 1) {\n saveCredentials({ ...creds, organizationId: workspaces[0].id });\n console.error(`🏢 Workspace: ${workspaces[0].name}`);\n return;\n }\n if (workspaces.length < 2) return;\n\n console.error('\\nThis key reaches several workspaces:');\n workspaces.forEach((w, i) => console.error(` ${i + 1}. ${w.name} (${w.id})`));\n\n if (!process.stdin.isTTY || !process.stderr.isTTY) {\n console.error(\n `Pick one with: ${BRAND.cli} workspaces:use <id> (or pass --workspace <id> on each command)`\n );\n return;\n }\n\n const answer = (await ask(`Work in which one? [1-${workspaces.length}] `)).trim();\n const index = Number(answer) - 1;\n const chosen = workspaces[index];\n if (!chosen) {\n console.error(`Skipped. Pick one later with: ${BRAND.cli} workspaces:use <id>`);\n return;\n }\n saveCredentials({ ...creds, organizationId: chosen.id });\n console.error(`✅ Workspace: ${chosen.name} (change it with \"${BRAND.cli} workspaces:use <id>\")`);\n}\n\nexport async function authLogin(argv: any) {\n const authServer = argv.authServer || readEnv('AUTH_SERVER') || DEFAULT_AUTH_SERVER;\n\n console.log('🔐 Starting device authorization flow...\\n');\n\n // Step 1: Request a device code from the auth server\n let deviceCode: string;\n let userCode: string;\n let verificationUri: string;\n let expiresIn: number;\n let interval: number;\n\n try {\n const response = await fetch(`${authServer}/device/code`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n // Shown on the approval page, so somebody can tell the login they just\n // started from one they did not.\n body: JSON.stringify({\n client_name: readEnv('CLIENT_NAME') || BRAND.clientName,\n // Asks for Postemi's approval page (postemi.com/app/device).\n brand: 'postemi',\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n console.error(`❌ Failed to start authorization (${response.status}): ${error}`);\n process.exit(1);\n }\n\n const data = (await response.json()) as any;\n deviceCode = data.device_code;\n userCode = data.user_code;\n verificationUri = data.verification_uri;\n expiresIn = data.expires_in;\n interval = data.interval || 5;\n } catch (error: any) {\n console.error(`❌ ${networkError(`Could not reach auth server at ${authServer}`, error, 'AUTH_SERVER')}`);\n process.exit(1);\n }\n\n // Step 2: Show the user code and open browser\n console.log(' Your authorization code:\\n');\n console.log(` ┌─────────────────┐`);\n console.log(` │ ${userCode} │`);\n console.log(` └─────────────────┘\\n`);\n console.log(` Open this URL and enter the code above:`);\n console.log(` ${verificationUri}\\n`);\n\n openBrowser(`${verificationUri}?code=${encodeURIComponent(userCode)}`);\n\n console.log(' Waiting for authorization...\\n');\n\n // Step 3: Poll for the token\n const deadline = Date.now() + expiresIn * 1000;\n\n while (Date.now() < deadline) {\n await sleep(interval * 1000);\n\n try {\n const response = await fetch(`${authServer}/device/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ device_code: deviceCode }),\n });\n\n const data = (await response.json()) as any;\n\n if (response.ok && data.access_token) {\n const creds: StoredCredentials = {\n accessToken: data.access_token,\n /*\n The host the login ran on (api.postemi.com), not the `api_url` in\n the token response: the Postemi host is what makes the API answer\n as Postemi.\n */\n apiUrl: String(authServer).replace(/\\/+$/, ''),\n organizationId: data.organization_id,\n };\n saveCredentials(creds);\n\n console.log('✅ Successfully authenticated!');\n console.log(`📁 Credentials saved to ${CREDENTIALS_FILE}`);\n await chooseWorkspace(creds);\n await maybeConfigureTimezone();\n await offerSkillsAfterLogin(argv);\n return;\n }\n\n if (data.error === 'authorization_pending') {\n continue;\n }\n\n if (data.error === 'expired_token') {\n console.error('❌ Authorization expired. Please try again.');\n process.exit(1);\n }\n\n // Unknown error\n console.error(`❌ Authorization failed: ${data.error}`);\n process.exit(1);\n } catch {\n // Network error during poll — keep trying\n continue;\n }\n }\n\n console.error('❌ Authorization timed out. Please try again.');\n process.exit(1);\n}\n\nconst TERMS_URL = BRAND.termsUrl;\nconst PRIVACY_URL = BRAND.privacyUrl;\n\n/** POST a JSON body to the unauthenticated sign-up routes. */\nasync function signupRequest(\n apiUrl: string,\n path: string,\n body: Record<string, unknown>\n): Promise<{ status: number; data: any }> {\n const response = await fetch(`${apiUrl}/public/v1${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n const text = await response.text();\n let data: any = text;\n try {\n data = JSON.parse(text);\n } catch {\n // not JSON; keep the text for the error message\n }\n return { status: response.status, data };\n}\n\n/** One shell word: quoted only when it has to be, so the command stays readable. */\nfunction shellWord(value: string): string {\n return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value)\n ? value\n : `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * The person's timezone for the new account: `--timezone`, then the one\n * saved by `config:set`, then this machine's own zone. An agent usually runs\n * on the person's machine, and a workspace without a zone schedules in UTC.\n */\nfunction signupTimezone(argv: any): string | undefined {\n const chosen = argv.timezone || getSetting('timezone');\n if (chosen) return String(chosen);\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The server's refusal as one sentence, whatever shape it came in. */\nfunction refusal(data: any): string {\n if (typeof data === 'string') return data;\n const message = data?.msg ?? data?.message;\n return Array.isArray(message) ? message.join('; ') : String(message ?? JSON.stringify(data));\n}\n\n/**\n * `postemi auth:signup --email <address> [--workspace-name <name>] [--code <code>] [--accept-terms]`\n *\n * CREATES A NEW POSTEMI ACCOUNT for the person at that address, with a code\n * from their mailbox, and stores its key exactly like `auth:login` does\n * (~/.postemi/credentials.json, 0600). The key is never printed.\n *\n * NO FREE TRIAL. An account made this way has no trial and no plan: the key\n * opens only the billing commands until the person pays, so the next step is\n * `postemi billing:plans` and `postemi billing:subscribe`.\n *\n * Two shapes, so both a person at a terminal and an agent without one can\n * drive it:\n * - interactive: one run sends the code, asks for it, asks whether the\n * person agrees to the terms, and finishes;\n * - an agent: the first run (no --code, no TTY) sends the code and prints\n * what to run next; the second run passes --code and --accept-terms,\n * which the agent sends only after the person has read the terms and the\n * privacy notice and agreed.\n */\nexport async function authSignup(argv: any) {\n const email = String(argv.email || '').trim();\n const apiUrl = String(\n argv.apiUrl || readEnv('API_URL') || DEFAULT_API_URL\n ).replace(/\\/+$/, '');\n const language = argv.language ? String(argv.language) : undefined;\n const timezone = signupTimezone(argv);\n const interactive = !!process.stdin.isTTY && !!process.stderr.isTTY;\n\n if (!email.includes('@')) {\n console.error('❌ Give the e-mail address of the new account with --email.');\n process.exit(1);\n }\n\n let code = argv.code ? String(argv.code).trim() : '';\n\n try {\n if (!code) {\n const started = await signupRequest(apiUrl, '/signup/start', {\n email,\n ...(language ? { language } : {}),\n });\n if (started.status !== 202 && started.status !== 200) {\n console.error(\n `❌ Could not send the code (HTTP ${started.status}): ${refusal(started.data)}`\n );\n process.exit(1);\n }\n\n status(`📧 A six-digit code was sent to ${email}. It is valid for 10 minutes.`);\n status(' Accounts created this way have no free trial; a plan is chosen and paid for next.');\n\n if (!interactive) {\n /*\n An agent: the person reads the code back, then the second run.\n EVERY option of this run rides along in the printed command. The\n first version printed only --email, so the second run lost the\n API URL (and hit the wrong server), the language, the workspace\n name and the timezone.\n */\n const nextCommand = [\n `${BRAND.cli} auth:signup`,\n `--email ${shellWord(email)}`,\n '--code <code>',\n '--accept-terms',\n ...(argv.apiUrl ? [`--api-url ${shellWord(apiUrl)}`] : []),\n ...(language ? [`--language ${language}`] : []),\n ...(argv.workspaceName\n ? [`--workspace-name ${shellWord(String(argv.workspaceName))}`]\n : []),\n ...(timezone ? [`--timezone ${shellWord(timezone)}`] : []),\n ].join(' ');\n result({\n codeSent: true,\n email,\n trial: false,\n terms: TERMS_URL,\n privacy: PRIVACY_URL,\n timezone: timezone ?? null,\n language: language ?? null,\n next: `Ask the person for the code, show them ${TERMS_URL} and ${PRIVACY_URL}, and when they agree run: ${nextCommand}`,\n });\n return;\n }\n\n code = (await ask('Code from the e-mail: ')).trim();\n if (!code) {\n console.error('❌ No code given. Run the command again with --code <code>.');\n process.exit(1);\n }\n }\n\n if (!/^[0-9]{6}$/.test(code)) {\n console.error('❌ The code is the six digits from the e-mail.');\n process.exit(1);\n }\n\n status('');\n status('To create the account the person must agree to:');\n status(` Terms of service: ${TERMS_URL}`);\n status(` Privacy notice: ${PRIVACY_URL}`);\n\n let accepted = !!argv.acceptTerms;\n if (!accepted && interactive) {\n const answer = (await ask('Do you agree to both? [y/N] ')).trim().toLowerCase();\n accepted = answer === 'y' || answer === 'yes' || answer === 'i' || answer === 'igen';\n }\n if (!accepted) {\n console.error(\n '❌ No account was created: the terms were not accepted. Show the person the two links above; if they agree, run the command again with --accept-terms.'\n );\n process.exit(1);\n }\n\n const completed = await signupRequest(apiUrl, '/signup/complete', {\n email,\n code,\n acceptTerms: true,\n ...(argv.workspaceName ? { workspaceName: String(argv.workspaceName) } : {}),\n ...(timezone ? { timezone: String(timezone) } : {}),\n ...(language ? { language } : {}),\n });\n\n if (completed.status === 409) {\n console.error(`❌ ${refusal(completed.data)}`);\n console.error(` Sign in instead: ${BRAND.cli} auth:login`);\n process.exit(1);\n }\n if (completed.status !== 201 && completed.status !== 200) {\n console.error(\n `❌ The account was not created (HTTP ${completed.status}): ${refusal(completed.data)}`\n );\n process.exit(1);\n }\n\n const data = completed.data || {};\n if (!data.apiKey) {\n console.error(`❌ The server answered without a key. Sign in with: ${BRAND.cli} auth:login`);\n process.exit(1);\n }\n\n if (loadCredentials()) {\n status('ℹ️ The credentials stored before are replaced by the new account\\'s key.');\n }\n saveCredentials({\n accessToken: data.apiKey,\n apiUrl,\n organizationId: data.workspaceId,\n });\n\n status(`✅ Account created. Workspace: ${data.workspaceName}`);\n status(`📁 Key saved to ${CREDENTIALS_FILE}`);\n status('');\n status('No free trial on this account. Next:');\n status(` ${BRAND.cli} billing:plans`);\n status(` ${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>`);\n status(`The person opens the checkout link and pays. This key then works for every command only on a plan with API access (apiAndMcpAccess: true in billing:plans); ${BRAND.basicPlanName} has none, so say so before the person picks it.`);\n\n result({\n created: true,\n workspaceId: data.workspaceId,\n workspaceName: data.workspaceName,\n trial: false,\n credentials: CREDENTIALS_FILE,\n next: [\n `${BRAND.cli} billing:plans`,\n `${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>`,\n `${BRAND.cli} billing:status`,\n ],\n note: `This key keeps working after the payment only on a plan with apiAndMcpAccess: true in billing:plans. ${BRAND.basicPlanName} has no API access: tell the person before they pay for it.`,\n });\n } catch (error: any) {\n console.error(`❌ ${networkError(`Could not reach the ${BRAND.name} API at ${apiUrl}`, error)}`);\n process.exit(1);\n }\n}\n\nexport async function authLogout() {\n const creds = loadCredentials();\n if (!creds) {\n console.log('ℹ️ No stored credentials found.');\n return;\n }\n\n deleteCredentials();\n console.log('✅ Credentials removed.');\n}\n\n/**\n * Report who we are authenticated as, and whether those credentials still work.\n *\n * OBEYS THE OUTPUT CONTRACT, which it used to break in both directions: it\n * printed its human report to STDOUT and returned 0 even when the credentials\n * were invalid. SKILL.md tells an agent to run this first and pipe it to `jq`,\n * so the emoji went straight into the parser, and a caller that checked the\n * exit code was told \"fine\" about an expired token.\n *\n * Now the prose goes to stderr, a machine-readable verdict goes to stdout, and\n * anything short of working credentials exits 1.\n *\n * ONLY THE KEY PREFIX IS EVER SHOWN. `psty_mcp_` keys are eight characters of\n * literal prefix, so the old `substring(0, 8)` revealed nothing — but for a\n * `pos_` OAuth token those same eight characters were four real secret ones.\n * The prefix is enough to tell two keys apart, which is all this is for.\n */\nexport async function authStatus() {\n const envKey = readEnv('API_KEY');\n const creds = loadCredentials();\n\n /** Enough to identify a key, never enough to use one. */\n const hint = (token: string) => `${token.split('_')[0]}_…`;\n\n /*\n THE METHOD IS THE CREDENTIAL, NOT THE FILE IT CAME FROM. Both\n `auth:login` and `auth:signup` store an API key (`psty_…`) in\n credentials.json; only a `pos_` token is OAuth. This used to say\n \"OAuth2\" for anything in the file.\n */\n const methodOf = (token: string): 'oauth2' | 'api-key' =>\n token.startsWith('pos_') ? 'oauth2' : 'api-key';\n const label = (m: 'oauth2' | 'api-key') =>\n m === 'oauth2' ? 'OAuth token' : 'API key';\n\n let apiKey: string | undefined;\n let apiUrl: string;\n let method: 'oauth2' | 'api-key';\n let source: 'credentials-file' | 'environment';\n\n if (creds) {\n method = methodOf(creds.accessToken);\n source = 'credentials-file';\n apiKey = creds.accessToken;\n apiUrl = creds.apiUrl;\n status(`🔐 Authentication method: ${label(method)} (stored by auth:login or auth:signup)`);\n status(`📡 API URL: ${creds.apiUrl}`);\n status(`🔑 Credential: ${hint(creds.accessToken)}`);\n if (creds.organizationId) {\n status(`🏢 Workspace: ${creds.organizationId}`);\n }\n status(`📁 Credentials file: ${CREDENTIALS_FILE}`);\n } else if (envKey) {\n method = methodOf(envKey);\n source = 'environment';\n apiKey = envKey;\n apiUrl = readEnv('API_URL') || DEFAULT_API_URL;\n status(`🔑 Authentication method: ${label(method)} (${envName('API_KEY')})`);\n status(`🔑 Credential: ${hint(envKey)}`);\n } else {\n status('❌ Not authenticated.');\n status('');\n status('Options:');\n status(` 1. Device login: ${BRAND.cli} auth:login`);\n status(` 2. New account: ${BRAND.cli} auth:signup --email <address>`);\n status(` 3. API Key: export ${envName('API_KEY')}=your_api_key`);\n result({ authenticated: false, reason: 'no-credentials' });\n process.exit(1);\n }\n\n status('');\n status('🔄 Verifying credentials...');\n\n const workspaceId = getWorkspaceId();\n const base = { method, source, apiUrl, workspace: workspaceId ?? null };\n\n /*\n THE PROBE IS `GET /subscription`, which answers for ANY valid credential,\n including one whose workspace has no plan with API access yet. The old\n probe (`GET /integrations`) is plan-gated, so a fresh `auth:signup` key\n was reported as \"expired or invalid\" while it was fine and only waiting\n for the payment.\n */\n let subscription: SubscriptionState;\n try {\n subscription = await new PostemiAPI({\n apiKey,\n apiUrl,\n workspaceId,\n }).getSubscription();\n } catch (error: any) {\n if (error instanceof ApiError && error.isWorkspaceChoice) {\n status('✅ Credentials are valid, but this key spans several workspaces and none is selected.');\n status(` Run: ${BRAND.cli} workspaces:list, then ${BRAND.cli} workspaces:use <id>`);\n result({ authenticated: true, ...base, reason: 'choose-workspace' });\n process.exit(1);\n }\n if (error instanceof ApiError && error.status === 401) {\n status('❌ Credentials are expired or invalid. Please re-authenticate.');\n status(\n creds\n ? ` Run: ${BRAND.cli} auth:login`\n : ` Update your ${envName('API_KEY')} environment variable.`\n );\n result({ authenticated: false, ...base, reason: 'rejected' });\n process.exit(1);\n }\n if (error instanceof ApiError) {\n /*\n UNKNOWN, NOT INVALID. A 500 or a proxy error says nothing about the\n credentials, so this reports that it could not check rather than\n claiming they are bad, but it still exits 1, because a caller that\n asked \"are these good?\" did not get a yes.\n */\n status(`⚠️ Could not verify credentials (HTTP ${error.status}): ${serverSentence(error.body)}`);\n result({ authenticated: null, ...base, reason: `http-${error.status}` });\n process.exit(1);\n }\n status(`⚠️ Could not reach API to verify credentials: ${error.message}`);\n result({ authenticated: null, ...base, reason: 'unreachable' });\n process.exit(1);\n }\n\n /*\n VALID, BUT NO PLAN YET: said as its own answer. The credential works (exit\n 0), and every command except billing:* will be refused until the workspace\n is on a plan with API access.\n */\n if (!subscription.apiAndMcpAccess) {\n const noPlan =\n subscription.state === 'none' ||\n subscription.state === 'cancelled' ||\n subscription.state === 'read_only';\n status(\n noPlan\n ? '✅ Credentials are valid. This workspace has no plan yet, so only the billing commands work.'\n : `✅ Credentials are valid. The current plan (${subscription.plan}) has no API access, so only the billing commands work.`\n );\n status(` Next: ${BRAND.cli} billing:plans, then ${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>`);\n if (subscription.pendingCheckout) {\n status(` An unpaid checkout is waiting: ${subscription.pendingCheckout.checkoutUrl}`);\n }\n result({\n authenticated: true,\n ...base,\n apiAccess: false,\n plan: subscription.plan,\n subscriptionState: subscription.state,\n reason: noPlan ? 'no-plan' : 'plan-without-api-access',\n });\n return;\n }\n\n // A full answer: how many channels, when the key may read them.\n let integrations: number | null = null;\n try {\n const list = (await new PostemiAPI({\n apiKey,\n apiUrl,\n workspaceId,\n }).listIntegrations()) as any[];\n integrations = Array.isArray(list) ? list.length : null;\n } catch {\n // A scoped key without channels:read; the credential is still valid.\n }\n\n status(\n `✅ Credentials are valid. Plan: ${subscription.plan ?? 'none'}${\n integrations === null ? '' : `, ${integrations} channel(s) connected`\n }.`\n );\n result({\n authenticated: true,\n ...base,\n apiAccess: true,\n plan: subscription.plan,\n subscriptionState: subscription.state,\n integrations,\n });\n}\n","/**\n * Persistent CLI settings — `~/.postemi/config.json`.\n *\n * Deliberately separate from `credentials.json`: settings survive\n * `postemi auth:logout`, and the credentials file keeps holding secrets only.\n *\n * Known keys: `timezone` (an IANA name, used to interpret dates\n * written without an explicit offset — see dates.ts for the full ladder).\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { BRAND } from './brand';\n\nconst SETTINGS_DIR = join(homedir(), BRAND.configDirName);\nconst SETTINGS_FILE = join(SETTINGS_DIR, 'config.json');\n\n/*\n `workspace` is the fallback home of the chosen workspace for a key that came\n from POSTEMI_API_KEY rather than from `postemi auth:login`; a device login stores\n it next to its token in credentials.json instead (see `workspaces:use`).\n*/\nexport const KNOWN_SETTINGS = ['timezone', 'workspace'] as const;\nexport type SettingKey = (typeof KNOWN_SETTINGS)[number];\n\nexport function settingsFilePath(): string {\n return SETTINGS_FILE;\n}\n\nexport function loadSettings(): Record<string, string> {\n try {\n if (!existsSync(SETTINGS_FILE)) return {};\n const data = JSON.parse(readFileSync(SETTINGS_FILE, 'utf-8'));\n return data && typeof data === 'object' ? data : {};\n } catch {\n return {};\n }\n}\n\nexport function getSetting(key: SettingKey): string | undefined {\n const value = loadSettings()[key];\n return typeof value === 'string' && value ? value : undefined;\n}\n\nexport function saveSetting(key: SettingKey, value: string): void {\n saveRawSetting(key, value);\n}\n\n/**\n * Any key, for state the CLI keeps for itself (`skills.writing`,\n * `skills.growth`, `skills.hint`: the answers to the optional skills\n * question). Not settable with config:set.\n */\nexport function saveRawSetting(key: string, value: string): void {\n if (!existsSync(SETTINGS_DIR)) {\n mkdirSync(SETTINGS_DIR, { recursive: true, mode: 0o700 });\n }\n const settings = loadSettings();\n settings[key] = value;\n writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + '\\n', {\n encoding: 'utf-8',\n });\n}\n","import { ApiError } from './api';\nimport { BRAND, envName } from './brand';\n\n/**\n * Output contract, kept strict because the primary consumers are scripts and\n * AI agents piping into `jq`:\n *\n * stdout — the JSON result of the command, and NOTHING else.\n * stderr — human-readable status, warnings and errors.\n *\n * Every failure exits 1.\n */\n\n/** The command's result. The only thing that ever goes to stdout. */\nexport function result(data: unknown): void {\n console.log(JSON.stringify(data, null, 2));\n}\n\n/** Human-readable progress/status — stderr, so stdout stays parseable. */\nexport function status(message: string): void {\n console.error(message);\n}\n\n/** Print a failure (with an auth hint when it is one) and exit 1. */\nexport function fail(context: string, error: any): never {\n console.error(`❌ ${context}: ${error?.message || error}`);\n\n if (error instanceof ApiError && error.isWorkspaceChoice) {\n console.error(\n `This key spans several workspaces and none is selected. Run \"${BRAND.cli} workspaces:list\", then \"${BRAND.cli} workspaces:use <id>\" (or pass --workspace <id>).`\n );\n } else if (error instanceof ApiError && error.missingScope) {\n /*\n A VALID credential without the permission. \"Run auth:login\" was the\n wrong advice here: the key is fine, logging in again changes nothing.\n */\n const { missing, role } = error.missingScope;\n console.error(\n `This key is valid but lacks the permission ${missing.join(', ') || 'this command needs'}${\n role ? ` (the key owner's role: ${role})` : ''\n }. Create a key that includes it in ${BRAND.name} (Settings, Developers), or ask a workspace owner.`\n );\n } else if (error instanceof ApiError && error.isPlanMissing) {\n console.error(\n `The credential is valid, but this workspace has no plan with API access yet. Run \"${BRAND.cli} billing:plans\", then \"${BRAND.cli} billing:subscribe --tier <slug> --period <monthly|yearly>\".`\n );\n } else if (error instanceof ApiError && error.isForbidden) {\n /*\n A 403 the scope guard did not phrase: the credential is valid, this\n action is not open to it (a scoped key on billing:manage, a colleague\n who is not the payer). The server's message above says why; \"your\n credentials were rejected\" would send the person to log in for nothing.\n */\n console.error(\n 'The credential is valid but not allowed to do this. The message above says why.'\n );\n } else if (error instanceof ApiError && error.isAuthError) {\n console.error(\n `Your credentials were rejected. Run \"${BRAND.cli} auth:login\" to re-authenticate, or check ${envName('API_KEY')}.`\n );\n }\n if (error instanceof ApiError && error.isRateLimit) {\n console.error(\n 'Rate limit hit (per key, per route, per hour). Back off — do not retry in a loop.'\n );\n }\n\n process.exit(1);\n}\n","/**\n * Date input handling.\n *\n * The API stores publish dates as UTC instants, and the backend interprets a\n * datetime WITHOUT a timezone designator in the server's own clock (UTC in\n * production) — which silently shifts a local \"12:00\" by the zone's offset.\n *\n * The CLI therefore refuses to guess. A date is either explicit or explicitly\n * configured, resolved in this priority order:\n *\n * (a) an explicit designator in the string itself (`Z`, `+01:00`) — used\n * as written;\n * (b) `--timezone <IANA name>` on the command;\n * (c) the `POSTEMI_TIMEZONE` environment variable;\n * (d) the `timezone` saved in `~/.postemi/config.json`\n * (`postemi config:set timezone <IANA>`, or confirmed during\n * `postemi auth:login` on a TTY);\n * (e) none of the above and the date is naive → hard error.\n *\n * Timezones must be IANA names (`Europe/London`). Numeric offsets are\n * REJECTED as timezone values on purpose: an offset hand-picked by a human or\n * an LLM is exactly the DST mistake this design exists to prevent. Offsets\n * belong inside the date string, where they are explicit per-instant.\n *\n * Whenever a timezone is applied (b–d), the resolved UTC instant is echoed on\n * stderr so nothing is silent.\n */\n\nimport { getSetting } from './settings';\nimport { BRAND, envName, readEnv } from './brand';\n\nexport type TimezoneSource =\n | '--timezone'\n | 'POSTEMI_TIMEZONE'\n | 'config (postemi config:set timezone)';\n\nexport interface ResolvedTimezone {\n name: string;\n source: TimezoneSource;\n}\n\nconst HAS_DESIGNATOR = /(Z|[+-]\\d{2}:?\\d{2})$/i;\nconst NAIVE_SHAPE =\n /^(\\d{4})-(\\d{2})-(\\d{2})([T ](\\d{2}):(\\d{2})(:(\\d{2}))?)?$/;\n\n/** Offset-shaped \"timezones\" we refuse: +02:00, -0500, UTC+2, GMT-5, Etc/GMT+2 … */\nconst OFFSET_SHAPED = /^(Etc\\/)?(UTC|GMT)?\\s*[+-]?\\d/i;\n\n/**\n * Validate an IANA timezone name. Throws with a corrective message on\n * anything else — including numeric offsets, which are valid concepts but\n * banned as timezone VALUES (see module comment).\n */\nexport function assertIanaTimezone(name: string, origin: string): string {\n const value = name.trim();\n\n if (!value || OFFSET_SHAPED.test(value)) {\n throw new Error(\n `Invalid timezone \"${name}\" (from ${origin}): numeric offsets are not accepted as timezones — DST would be your problem to compute. ` +\n `Use an IANA name like \"${BRAND.exampleTimezone}\" (or put the offset inside the date string itself, e.g. \"2026-12-31T12:00:00+01:00\").`\n );\n }\n\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: value });\n } catch {\n throw new Error(\n `Unknown timezone \"${name}\" (from ${origin}). Use an IANA name like \"${BRAND.exampleTimezone}\" or \"UTC\".`\n );\n }\n\n return value;\n}\n\n/**\n * Walk the ladder (b) → (d). Returns null when nothing is configured — the\n * caller then errors only if it actually meets a naive date. An invalid value\n * at any rung is an error, not a fall-through: silently skipping a typoed\n * POSTEMI_TIMEZONE would reintroduce the guessing this design removes.\n */\nexport function resolveTimezone(flagValue?: string): ResolvedTimezone | null {\n if (flagValue !== undefined) {\n return {\n name: assertIanaTimezone(flagValue, '--timezone'),\n source: '--timezone',\n };\n }\n\n const env = readEnv('TIMEZONE');\n if (env) {\n return {\n name: assertIanaTimezone(env, envName('TIMEZONE')),\n source: 'POSTEMI_TIMEZONE',\n };\n }\n\n const stored = getSetting('timezone');\n if (stored) {\n return {\n name: assertIanaTimezone(stored, `~/${BRAND.configDirName}/config.json`),\n source: 'config (postemi config:set timezone)',\n };\n }\n\n return null;\n}\n\n/** Offset of `timeZone` from UTC at the given instant, in minutes. */\nfunction tzOffsetMinutes(instant: Date, timeZone: string): number {\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n }).formatToParts(instant);\n\n const get = (type: string) =>\n Number(parts.find((p) => p.type === type)?.value);\n\n const asUtc = Date.UTC(\n get('year'),\n get('month') - 1,\n get('day'),\n get('hour') % 24,\n get('minute'),\n get('second')\n );\n\n return Math.round((asUtc - instant.getTime()) / 60000);\n}\n\n/** Interpret naive wall-clock components in `timeZone`; return the instant. */\nfunction zonedToUtc(\n y: number,\n mo: number,\n d: number,\n h: number,\n mi: number,\n s: number,\n timeZone: string\n): Date {\n // First guess: treat the wall clock as UTC, then correct by the zone's\n // offset at that instant. One refinement pass handles DST boundaries.\n const guess = Date.UTC(y, mo - 1, d, h, mi, s);\n let offset = tzOffsetMinutes(new Date(guess), timeZone);\n let instant = guess - offset * 60000;\n const refined = tzOffsetMinutes(new Date(instant), timeZone);\n if (refined !== offset) {\n instant = guess - refined * 60000;\n }\n return new Date(instant);\n}\n\nexport interface ResolvedDate {\n /** UTC ISO 8601, always with `Z` — what goes on the wire. */\n iso: string;\n /** Set when the input carried no designator and a timezone was applied. */\n appliedTimezone: ResolvedTimezone | null;\n}\n\nfunction naiveDateError(input: string, flagName: string): Error {\n return new Error(\n `Date \"${input}\" has no timezone, and no timezone is configured. ` +\n `The server would read it as UTC, silently shifting your post. Fix one of:\\n` +\n ` 1. Explicit offset in the date: ${flagName} \"2026-12-31T12:00:00+01:00\" (or ...T12:00:00Z for UTC)\\n` +\n ` 2. Timezone flag: --timezone ${BRAND.exampleTimezone}\\n` +\n ` 3. Environment variable: export ${envName('TIMEZONE')}=${BRAND.exampleTimezone}\\n` +\n ` 4. Save it once: ${BRAND.cli} config:set timezone ${BRAND.exampleTimezone}`\n );\n}\n\n/**\n * Normalize a user-supplied date to UTC ISO 8601, or throw with a message\n * that says exactly how to fix it. `timezone` comes from `resolveTimezone`.\n */\nexport function resolveDateInput(\n input: string,\n timezone: ResolvedTimezone | null,\n flagName = '--date'\n): ResolvedDate {\n const value = input.trim();\n\n if (HAS_DESIGNATOR.test(value)) {\n const parsed = new Date(value);\n if (isNaN(parsed.getTime())) {\n throw new Error(\n `Invalid date \"${input}\". Use ISO 8601, e.g. \"2026-12-31T12:00:00Z\" or \"2026-12-31T12:00:00+01:00\".`\n );\n }\n return { iso: parsed.toISOString(), appliedTimezone: null };\n }\n\n const m = NAIVE_SHAPE.exec(value);\n if (!m) {\n throw new Error(\n `Invalid date \"${input}\". Use ISO 8601 with an explicit offset (\"2026-12-31T12:00:00Z\"), or \"YYYY-MM-DD HH:mm\" together with a timezone (--timezone ${BRAND.exampleTimezone}).`\n );\n }\n\n if (!timezone) {\n throw naiveDateError(input, flagName);\n }\n\n const instant = zonedToUtc(\n Number(m[1]),\n Number(m[2]),\n Number(m[3]),\n Number(m[5] ?? 0),\n Number(m[6] ?? 0),\n Number(m[8] ?? 0),\n timezone.name\n );\n\n if (isNaN(instant.getTime())) {\n throw new Error(`Invalid date \"${input}\".`);\n }\n\n return { iso: instant.toISOString(), appliedTimezone: timezone };\n}\n","import { homedir } from 'os';\nimport { join } from 'path';\nimport { createInterface } from 'readline';\nimport { loadSettings, saveRawSetting } from '../settings';\nimport { result, status } from '../output';\nimport { BRAND } from '../brand';\nimport {\n ANSWER_KEY,\n OPTIONAL_SETS,\n SET_SUMMARY,\n SKILL_SETS,\n SkillSet,\n Store,\n Terminal,\n chooseAgents,\n detectAgents,\n installSets,\n knownAgents,\n offerOptionalSkills,\n parseSetNames,\n removeSets,\n setState,\n terminalFrom,\n} from '../skills';\n\n/** The package's own skills folder: dist/../skills. */\nexport function bundledSkillsDir(): string {\n return join(__dirname, '..', 'skills');\n}\n\nconst settingsStore: Store = {\n get: (key) => {\n const value = loadSettings()[key];\n return typeof value === 'string' && value ? value : undefined;\n },\n set: (key, value) => saveRawSetting(key, value),\n};\n\nfunction ask(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) =>\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n })\n );\n}\n\nfunction die(message: string): never {\n console.error(`❌ ${message}`);\n process.exit(1);\n}\n\n/** `postemi skills list` */\nexport async function skillsList() {\n const source = bundledSkillsDir();\n const settings = loadSettings();\n const agents = knownAgents(homedir(), process.env);\n const found = new Set(detectAgents(homedir(), process.env).map((a) => a.id));\n const sets: SkillSet[] = ['core', ...OPTIONAL_SETS];\n\n result({\n agents: agents.map((a) => ({ id: a.id, name: a.name, found: found.has(a.id), skillsDir: a.skillsDir })),\n skills: sets.map((set) => ({\n name: set,\n optional: set !== 'core',\n folders: SKILL_SETS[set],\n about: SET_SUMMARY[set],\n answer: set === 'core' ? null : settings[ANSWER_KEY[set]] ?? null,\n installed: Object.fromEntries(\n agents.filter((a) => found.has(a.id)).map((a) => [a.id, setState(source, set, a)])\n ),\n })),\n });\n}\n\nasync function install(sets: SkillSet[], argv: any, terminal: Terminal) {\n const home = homedir();\n const agents = await chooseAgents({\n found: detectAgents(home, process.env),\n all: knownAgents(home, process.env),\n requested: argv.agent,\n yes: !!argv.yes,\n terminal,\n ask,\n log: status,\n });\n if (!agents.length) {\n throw new Error(\n `No agent skill folder found (~/.claude, ~/.codex, ~/.cursor, ~/.grok). Pass --agent claude (or codex, cursor, grok) to create one.`\n );\n }\n\n const installed: Record<string, string[]> = {};\n for (const agent of agents) {\n try {\n installed[agent.id] = installSets(bundledSkillsDir(), sets, agent);\n } catch (error: any) {\n throw new Error(`${agent.name}: ${error.message}`);\n }\n status(`✅ ${agent.name}: ${installed[agent.id].join(', ')} in ${agent.skillsDir}`);\n }\n for (const set of sets) {\n if (set !== 'core') settingsStore.set(ANSWER_KEY[set], 'yes');\n }\n status('Start a new agent session to load them.');\n return installed;\n}\n\n/** `postemi skills add [writing|growth|all|core]` */\nexport async function skillsAdd(argv: any) {\n const terminal = terminalFrom(argv);\n const names: string[] = argv.skills ?? [];\n let sets: SkillSet[];\n\n if (!names.length) {\n if (terminal.json || !terminal.stdinTTY || !terminal.stderrTTY || terminal.ci) {\n die(`Name the skill: ${BRAND.cli} skills add writing|growth|all`);\n }\n sets = await offerOptionalSkills({ terminal, store: settingsStore, ask, log: status }, true);\n if (!sets.length) {\n result({ installed: {} });\n return;\n }\n } else {\n try {\n sets = parseSetNames(names);\n } catch (error: any) {\n die(error.message);\n }\n }\n try {\n result({ installed: await install(sets, argv, terminal) });\n } catch (error: any) {\n die(error.message);\n }\n}\n\n/** `postemi skills remove <writing|growth|all|core>` */\nexport async function skillsRemove(argv: any) {\n const names: string[] = argv.skills ?? [];\n if (!names.length) die(`Name the skill: ${BRAND.cli} skills remove writing|growth|all`);\n let sets: SkillSet[];\n let agents;\n try {\n sets = parseSetNames(names);\n agents = await chooseAgents({\n found: detectAgents(homedir(), process.env),\n all: knownAgents(homedir(), process.env),\n requested: argv.agent ?? ['all'],\n yes: true,\n terminal: terminalFrom(argv),\n ask,\n log: status,\n });\n } catch (error: any) {\n die(error.message);\n }\n const removed: Record<string, string[]> = {};\n for (const agent of agents) {\n removed[agent.id] = removeSets(sets, agent);\n if (removed[agent.id].length) status(`🗑️ ${agent.name}: removed ${removed[agent.id].join(', ')}`);\n }\n for (const set of sets) {\n if (set !== 'core') settingsStore.set(ANSWER_KEY[set], 'no');\n }\n result({ removed });\n}\n\n/**\n * After a successful `auth:login`: offer the optional skills once, on a\n * terminal. Off a terminal, one hint line, once. Never fatal.\n */\nexport async function offerSkillsAfterLogin(argv: any) {\n try {\n const terminal = terminalFrom(argv);\n const sets = await offerOptionalSkills({ terminal, store: settingsStore, ask, log: status });\n if (sets.length) await install(sets, {}, terminal);\n } catch (error: any) {\n status(`Skills not installed: ${error?.message || error}. Try: ${BRAND.cli} skills add`);\n }\n}\n","/**\n * Agent skills that ship inside the npm package (`skills/` next to `dist/`)\n * and that `postemi skills add` copies into the skill folders of the coding\n * agents found on this machine.\n *\n * core skills/postemi always installed with any other set\n * writing skills/postemi-writing optional (ideas, hooks, templates)\n * skills/postemi-templates goes with writing\n * growth skills/postemi-growth optional (niche, cadence, 30-day plan)\n *\n * Everything here takes its paths, environment and I/O as arguments, so the\n * unit tests run it against a temporary home folder and a fake terminal.\n */\n\nimport { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from 'fs';\nimport { join } from 'path';\n\nexport type SkillSet = 'core' | 'writing' | 'growth';\nexport type OptionalSet = Exclude<SkillSet, 'core'>;\n\nexport const OPTIONAL_SETS: OptionalSet[] = ['writing', 'growth'];\n\n/** The folders (each holds a SKILL.md) that make up one set. */\nexport const SKILL_SETS: Record<SkillSet, string[]> = {\n core: ['postemi'],\n writing: ['postemi-writing', 'postemi-templates'],\n growth: ['postemi-growth'],\n};\n\nexport const SET_SUMMARY: Record<SkillSet, string> = {\n core: 'the postemi commands and their rules (always on)',\n writing: 'write posts: ideas, hooks, formatting, network rules, templates',\n growth: 'grow an audience: niche, cadence, 30-day plan, weekly review',\n};\n\nexport type AgentId = 'claude' | 'codex' | 'cursor' | 'grok';\nexport const AGENT_IDS: AgentId[] = ['claude', 'codex', 'cursor', 'grok'];\n\nexport interface Agent {\n id: AgentId;\n name: string;\n /** The agent's own folder; the agent counts as installed when it exists. */\n home: string;\n /** Where its user-level skills live. */\n skillsDir: string;\n}\n\n/*\n Where each agent reads user-level skills:\n - Claude Code: ~/.claude/skills (or $CLAUDE_CONFIG_DIR/skills).\n - Codex: $CODEX_HOME/skills, default ~/.codex/skills (Codex also reads\n ~/.agents/skills; its own skill installer writes to $CODEX_HOME/skills).\n - Cursor: ~/.cursor/skills.\n - Grok Build: ~/.grok/skills (Grok also reads the Claude and Cursor folders\n and keeps one copy per skill name, so a second copy does no harm).\n*/\nexport function knownAgents(home: string, env: NodeJS.ProcessEnv = {}): Agent[] {\n const claudeHome = env.CLAUDE_CONFIG_DIR || join(home, '.claude');\n const codexHome = env.CODEX_HOME || join(home, '.codex');\n const cursorHome = join(home, '.cursor');\n const grokHome = join(home, '.grok');\n return [\n { id: 'claude', name: 'Claude Code', home: claudeHome, skillsDir: join(claudeHome, 'skills') },\n { id: 'codex', name: 'Codex', home: codexHome, skillsDir: join(codexHome, 'skills') },\n { id: 'cursor', name: 'Cursor', home: cursorHome, skillsDir: join(cursorHome, 'skills') },\n { id: 'grok', name: 'Grok Build', home: grokHome, skillsDir: join(grokHome, 'skills') },\n ];\n}\n\n/** The agents whose folder exists on this machine. */\nexport function detectAgents(home: string, env: NodeJS.ProcessEnv = {}): Agent[] {\n return knownAgents(home, env).filter((agent) => isDir(agent.home));\n}\n\n/** `writing`, `growth`, `all`, `core`, or a folder name like `postemi-writing`. */\nexport function parseSetNames(names: string[]): SkillSet[] {\n const out = new Set<SkillSet>();\n for (const raw of names) {\n const name = raw.trim().toLowerCase().replace(/^postemi-?/, '') || 'core';\n if (name === 'all') OPTIONAL_SETS.forEach((s) => out.add(s));\n else if (name === 'templates') out.add('writing');\n else if (name === 'core' || name === 'writing' || name === 'growth') out.add(name);\n else throw new Error(`Unknown skill \"${raw}\". Use writing, growth, all or core.`);\n }\n return [...out];\n}\n\nfunction isDir(path: string): boolean {\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction listFiles(dir: string, prefix = ''): string[] {\n const out: string[] = [];\n for (const name of readdirSync(dir).sort()) {\n const path = join(dir, name);\n if (isDir(path)) out.push(...listFiles(path, join(prefix, name)));\n else out.push(join(prefix, name));\n }\n return out;\n}\n\nfunction sameTree(a: string, b: string): boolean {\n const fa = listFiles(a);\n const fb = listFiles(b);\n return (\n fa.length === fb.length &&\n fa.every((f, i) => fb[i] === f && readFileSync(join(a, f)).equals(readFileSync(join(b, f))))\n );\n}\n\n/** The `name:` in a SKILL.md's front matter, or null. */\nexport function skillName(dir: string): string | null {\n try {\n const text = readFileSync(join(dir, 'SKILL.md'), 'utf8');\n const match = /^---\\r?\\n[\\s\\S]*?^name:\\s*[\"']?([\\w-]+)[\"']?\\s*$/m.exec(text);\n return match ? match[1] : null;\n } catch {\n return null;\n }\n}\n\nexport type FolderState = 'installed' | 'outdated' | 'missing';\n\n/** One skill folder in one agent, compared with the copy in the package. */\nexport function folderState(source: string, folder: string, agent: Agent): FolderState {\n const target = join(agent.skillsDir, folder);\n if (skillName(target) !== folder) return 'missing';\n return sameTree(join(source, folder), target) ? 'installed' : 'outdated';\n}\n\n/** A set is as installed as its least installed folder. */\nexport function setState(source: string, set: SkillSet, agent: Agent): FolderState {\n const states = SKILL_SETS[set].map((f) => folderState(source, f, agent));\n if (states.includes('missing')) return 'missing';\n if (states.includes('outdated')) return 'outdated';\n return 'installed';\n}\n\n/**\n * Copy the sets' folders into the agent's skill folder, replacing an older\n * copy. Core comes along with any set. Refuses to overwrite a folder of the\n * same name that is not this skill (another SKILL.md name, or no SKILL.md).\n * Returns the folders written.\n */\nexport function installSets(source: string, sets: SkillSet[], agent: Agent): string[] {\n const folders = foldersFor(sets.includes('core') ? sets : ['core', ...sets]);\n for (const folder of folders) {\n if (skillName(join(source, folder)) !== folder) {\n throw new Error(`The package has no ${folder} skill at ${join(source, folder)}`);\n }\n const target = join(agent.skillsDir, folder);\n if (existsSync(target) && skillName(target) !== folder) {\n throw new Error(`${target} exists and is not the ${folder} skill; move it away first`);\n }\n }\n mkdirSync(agent.skillsDir, { recursive: true });\n for (const folder of folders) {\n const target = join(agent.skillsDir, folder);\n rmSync(target, { recursive: true, force: true });\n cpSync(join(source, folder), target, { recursive: true });\n }\n return folders;\n}\n\n/** Remove the sets' folders (only folders whose SKILL.md names that skill). */\nexport function removeSets(sets: SkillSet[], agent: Agent): string[] {\n const removed: string[] = [];\n for (const folder of foldersFor(sets)) {\n const target = join(agent.skillsDir, folder);\n if (skillName(target) !== folder) continue;\n rmSync(target, { recursive: true, force: true });\n removed.push(folder);\n }\n return removed;\n}\n\nfunction foldersFor(sets: SkillSet[]): string[] {\n return [...new Set(sets.flatMap((s) => SKILL_SETS[s]))];\n}\n\n/* ------------------------------------------------------------------------ */\n/* The one-time question */\n/* ------------------------------------------------------------------------ */\n\nexport interface Terminal {\n stdinTTY: boolean;\n stderrTTY: boolean;\n /** `--json` on the command: an agent or a script runs it. */\n json: boolean;\n /** The CI environment variable is set. */\n ci: boolean;\n}\n\nexport function terminalFrom(argv: { json?: unknown }, env: NodeJS.ProcessEnv = process.env): Terminal {\n return {\n stdinTTY: !!process.stdin.isTTY,\n stderrTTY: !!process.stderr.isTTY,\n json: !!argv.json,\n ci: !!env.CI && env.CI !== 'false' && env.CI !== '0',\n };\n}\n\n/** Questions only for a person at a terminal. */\nexport function canAsk(t: Terminal): boolean {\n return t.stdinTTY && t.stderrTTY && !t.json && !t.ci;\n}\n\n/** Saved answers live in ~/.postemi/config.json under these keys. */\nexport const ANSWER_KEY: Record<OptionalSet, string> = {\n writing: 'skills.writing',\n growth: 'skills.growth',\n};\nexport const HINT_KEY = 'skills.hint';\n\nexport interface Store {\n get(key: string): string | undefined;\n set(key: string, value: string): void;\n}\n\nexport const QUESTIONS: Record<OptionalSet, string> = {\n writing:\n 'Postemi can also help you write posts. Install the optional writing skill (ideas, hooks, templates)? [y/N] ',\n growth: 'Install the optional growth skill (niche, cadence, 30-day plan)? [y/N] ',\n};\n\nexport const HINT =\n 'Tip: optional agent skills for writing posts and growing an audience: postemi skills list, postemi skills add writing|growth';\n\nexport function isYes(answer: string): boolean {\n return /^(y|yes)$/i.test(answer.trim());\n}\n\n/** Both questions already answered once. */\nexport function alreadyOffered(store: Store): boolean {\n return OPTIONAL_SETS.every((s) => !!store.get(ANSWER_KEY[s]));\n}\n\nexport interface OfferDeps {\n terminal: Terminal;\n store: Store;\n ask: (question: string) => Promise<string>;\n log: (line: string) => void;\n}\n\n/**\n * Ask the two questions and save the answers. Returns the sets the person\n * said yes to. `force` asks again even if both were answered before (an\n * explicit `postemi skills add` with no name); off a terminal it never asks.\n *\n * The rule after `auth:login`: ask once, on a terminal only, default No.\n * Off a terminal (an agent, a pipe, CI, --json) print one hint line to\n * stderr, once ever.\n */\nexport async function offerOptionalSkills(deps: OfferDeps, force = false): Promise<OptionalSet[]> {\n const { terminal, store, ask, log } = deps;\n if (!force && alreadyOffered(store)) return [];\n if (!canAsk(terminal)) {\n if (!store.get(HINT_KEY)) {\n log(HINT);\n store.set(HINT_KEY, 'shown');\n }\n return [];\n }\n const chosen: OptionalSet[] = [];\n for (const set of OPTIONAL_SETS) {\n const yes = isYes(await ask(QUESTIONS[set]));\n store.set(ANSWER_KEY[set], yes ? 'yes' : 'no');\n if (yes) chosen.push(set);\n }\n if (!chosen.length) log('No optional skills. Add them any time with: postemi skills add');\n return chosen;\n}\n\n/**\n * Which agents to install into. `--agent` wins (an agent named there is used\n * even if its folder does not exist yet). Otherwise every agent found; with\n * more than one on a terminal (and no --yes) the person picks.\n */\nexport async function chooseAgents(opts: {\n found: Agent[];\n all: Agent[];\n requested?: string[];\n yes: boolean;\n terminal: Terminal;\n ask: (question: string) => Promise<string>;\n log: (line: string) => void;\n}): Promise<Agent[]> {\n const { found, all, requested, yes, terminal, ask, log } = opts;\n if (requested && requested.length) {\n const ids = requested.flatMap((r) => String(r).split(',')).map((r) => r.trim().toLowerCase()).filter(Boolean);\n if (ids.includes('all')) return found;\n return ids.map((id) => {\n const agent = all.find((a) => a.id === id);\n if (!agent) throw new Error(`Unknown agent \"${id}\". Use ${AGENT_IDS.join(', ')} or all.`);\n return agent;\n });\n }\n if (found.length <= 1 || yes || !canAsk(terminal)) return found;\n\n log('Agents found on this machine:');\n found.forEach((a, i) => log(` ${i + 1}. ${a.name} (${a.skillsDir})`));\n const answer = (await ask(`Install for which? [all, or numbers like 1,3] `)).trim().toLowerCase();\n if (!answer || answer === 'all' || answer === 'a') return found;\n const picked = answer\n .split(/[\\s,]+/)\n .map((n) => found[Number(n) - 1])\n .filter((a): a is Agent => !!a);\n return [...new Set(picked)];\n}\n","import { PostemiConfig } from './api';\nimport { loadCredentials } from './commands/auth';\nimport { getSetting } from './settings';\nimport { BRAND, envName, readEnv } from './brand';\n\n/**\n * Which workspace requests are about, in order of precedence: `--workspace`\n * on the command (the yargs middleware copies it into POSTEMI_WORKSPACE), the\n * environment, the choice saved by `postemi workspaces:use` (in credentials.json\n * for a device login, in config.json for an env key). Undefined is fine for a\n * one-workspace key; the API refuses to guess for a key that spans several.\n */\nexport function getWorkspaceId(): string | undefined {\n const fromEnv = readEnv('WORKSPACE');\n if (fromEnv) return fromEnv;\n const creds = loadCredentials();\n if (creds?.organizationId) return creds.organizationId;\n return getSetting('workspace');\n}\n\nexport function getConfig(): PostemiConfig {\n const workspaceId = getWorkspaceId();\n\n // Check for stored OAuth credentials first\n const creds = loadCredentials();\n if (creds) {\n return {\n apiKey: creds.accessToken,\n apiUrl: creds.apiUrl,\n workspaceId,\n };\n }\n\n // Fall back to environment variable\n const apiKey = readEnv('API_KEY');\n const apiUrl = readEnv('API_URL');\n\n if (!apiKey) {\n console.error('❌ Error: No authentication found.');\n console.error('Options:');\n console.error(` 1. Device login: ${BRAND.cli} auth:login`);\n console.error(` 2. API Key: export ${envName('API_KEY')}=your_api_key`);\n process.exit(1);\n }\n\n return {\n apiKey,\n apiUrl,\n workspaceId,\n };\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport {\n ResolvedDate,\n ResolvedTimezone,\n resolveDateInput,\n resolveTimezone,\n} from '../dates';\nimport { result, status, fail } from '../output';\nimport { readFileSync, existsSync } from 'fs';\nimport { BRAND } from '../brand';\n\n/**\n * Read `--content`/`--media` off the raw argv, keeping the order they were\n * written in, so each `-m` belongs to the `-c` it follows.\n *\n * Exported for the tests, and separate from the handler because it is pure:\n * argv in, pairs out, no process state.\n *\n * Accepts `-c X`, `--content X` and `--content=X`. Repeating `-m` under one\n * `-c` appends, matching the comma syntax a single `-m` already supports.\n */\nexport const pairContentsWithMedia = (\n argv: string[]\n): { content: string; media?: string }[] => {\n const read = (\n token: string,\n next: string | undefined,\n long: string,\n short: string\n ): { value: string; consumed: number } | null => {\n if (token === `--${long}` || token === `-${short}`) {\n return next === undefined ? null : { value: next, consumed: 2 };\n }\n if (token.startsWith(`--${long}=`)) {\n return { value: token.slice(long.length + 3), consumed: 1 };\n }\n return null;\n };\n\n const pairs: { content: string; media?: string }[] = [];\n\n for (let i = 0; i < argv.length; ) {\n const content = read(argv[i], argv[i + 1], 'content', 'c');\n if (content) {\n pairs.push({ content: content.value });\n i += content.consumed;\n continue;\n }\n\n const media = read(argv[i], argv[i + 1], 'media', 'm');\n if (media) {\n /*\n An -m before any -c has nothing to attach to. Guessing (first\n content? all of them?) is how the old bug behaved, so refuse instead.\n */\n if (!pairs.length) {\n console.error('❌ --media/-m must come after the --content/-c it belongs to');\n process.exit(1);\n }\n const last = pairs[pairs.length - 1];\n last.media = last.media ? `${last.media},${media.value}` : media.value;\n i += media.consumed;\n continue;\n }\n\n i += 1;\n }\n\n return pairs;\n};\n\n/** Walk the timezone ladder for this invocation, or exit 1 with the reason. */\nfunction timezoneForArgs(args: any): ResolvedTimezone | null {\n try {\n return resolveTimezone(args.timezone);\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n}\n\nfunction echoInterpretation(input: string, resolved: ResolvedDate) {\n if (resolved.appliedTimezone) {\n status(\n `ℹ️ Interpreted \"${input}\" as ${resolved.appliedTimezone.name} (via ${resolved.appliedTimezone.source}) → ${resolved.iso}`\n );\n }\n}\n\nexport async function getMissingContent(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getMissingContent(args.id);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get missing content', error);\n }\n}\n\nexport async function connectPost(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.updateReleaseId(args.id, args.releaseId);\n status(`✅ Post ${args.id} connected to release ${args.releaseId}`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to connect post', error);\n }\n}\n\nexport async function findSlot(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.findSlot(args.id);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to find a free slot', error);\n }\n}\n\nexport async function createPost(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n // Support both simple and complex post creation\n let postData: any;\n\n if (args.json) {\n // Load from JSON file for complex posts with comments and media\n try {\n const jsonPath = args.json;\n if (!existsSync(jsonPath)) {\n console.error(`❌ JSON file not found: ${jsonPath}`);\n process.exit(1);\n }\n const jsonContent = readFileSync(jsonPath, 'utf-8');\n postData = JSON.parse(jsonContent);\n } catch (error: any) {\n console.error(`❌ Failed to parse JSON file: ${error.message}`);\n process.exit(1);\n }\n } else {\n const integrations = args.integrations\n ? args.integrations.split(',').map((id: string) => id.trim())\n : [];\n\n if (integrations.length === 0) {\n console.error('❌ At least one integration ID is required');\n console.error('Use -i or --integrations to specify integration IDs');\n console.error(`Run \"${BRAND.cli} integrations:list\" to see available integrations`);\n process.exit(1);\n }\n\n const contents = Array.isArray(args.content) ? args.content : [args.content];\n\n if (!contents[0]) {\n console.error('❌ At least one -c/--content is required');\n process.exit(1);\n }\n\n /*\n PAIRED BY POSITION ON THE COMMAND LINE, NOT BY ARRAY INDEX.\n\n yargs collects every -c into one array and every -m into another, and\n this used to pair them by index. The two arrays only line up when every\n -c has an -m, so\n\n -c \"A\" -m one.jpg -c \"B\" -c \"C\" -m three.jpg\n\n produced medias [\"one\",\"three\"] and attached three.jpg to comment B.\n Silently, and to a live social account. Reading the real argv is the\n only way to know which -c an -m was written under.\n */\n const pairs = pairContentsWithMedia(process.argv);\n\n if (pairs.length && pairs.length !== contents.length) {\n console.error(\n `❌ Could not match --media to --content reliably (parsed ${pairs.length} content flags, yargs saw ${contents.length}).`\n );\n console.error('Pass the post structure with --json instead.');\n process.exit(1);\n }\n\n const values = (pairs.length ? pairs : contents.map((content: string) => ({ content, media: undefined })))\n .map(({ content, media }: { content: string; media?: string }) => ({\n content,\n image: media\n ? media.split(',').filter((img: string) => img.trim()).map((img: string) => ({\n id: Math.random().toString(36).substring(7),\n path: img.trim(),\n }))\n : [],\n delay: args?.delay || 0,\n }));\n\n // Parse provider-specific settings if provided\n // Note: __type is automatically added by the backend based on integration ID\n let settings: any = undefined;\n\n if (args.settings) {\n try {\n settings = typeof args.settings === 'string'\n ? JSON.parse(args.settings)\n : args.settings;\n } catch (error: any) {\n console.error(`❌ Failed to parse settings JSON: ${error.message}`);\n process.exit(1);\n }\n }\n\n const type = args.type || 'schedule';\n\n // `now` publishes immediately; the server replaces the date, but the API\n // still requires the field, so send the current instant when it is omitted.\n let dateIso: string;\n if (!args.date && type === 'now') {\n dateIso = new Date().toISOString();\n } else {\n const timezone = timezoneForArgs(args);\n try {\n const resolved = resolveDateInput(args.date, timezone, '--date');\n dateIso = resolved.iso;\n echoInterpretation(args.date, resolved);\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n }\n\n // Build the proper post structure\n postData = {\n type,\n creationMethod: 'CLI',\n date: dateIso,\n shortLink: args.shortLink !== false,\n tags: [],\n posts: integrations.map((integrationId: string) => ({\n integration: { id: integrationId },\n value: values,\n settings: settings,\n })),\n };\n }\n\n try {\n const res = await api.createPost(postData);\n status('✅ Post created successfully!');\n if (postData?.type && postData.type !== 'draft') {\n status(\n 'Note: a key without posts:publish creates a DRAFT even when you asked to schedule — check the type in the response.'\n );\n }\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to create post', error);\n }\n}\n\nexport async function listPosts(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n // Set default date range: last 30 days to 30 days in the future\n const defaultStartDate = new Date();\n defaultStartDate.setDate(defaultStartDate.getDate() - 30);\n\n const defaultEndDate = new Date();\n defaultEndDate.setDate(defaultEndDate.getDate() + 30);\n\n // Only walk the ladder when a date was actually supplied — the defaults are\n // computed instants and must not fail on, say, a typoed POSTEMI_TIMEZONE.\n const timezone =\n args.startDate || args.endDate ? timezoneForArgs(args) : null;\n\n const resolve = (label: string, value: string | undefined, fallback: Date) => {\n if (!value) return fallback.toISOString();\n try {\n const resolved = resolveDateInput(value, timezone, label);\n echoInterpretation(value, resolved);\n return resolved.iso;\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n };\n\n // Only send fields that are in GetPostsDto\n const filters: any = {\n startDate: resolve('--startDate', args.startDate, defaultStartDate),\n endDate: resolve('--endDate', args.endDate, defaultEndDate),\n };\n\n // customer is optional in the DTO\n if (args.customer) {\n filters.customer = args.customer;\n }\n\n try {\n const res = await api.listPosts(filters);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list posts', error);\n }\n}\n\nexport async function changePostStatus(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.changePostStatus(args.id, args.status);\n status(`✅ Post ${args.id} status changed to ${args.status}`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to change post status', error);\n }\n}\n\nexport async function deletePost(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.deletePost(args.id);\n status(`✅ Post ${args.id} deleted successfully!`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to delete post', error);\n }\n}\n\nexport async function deletePostGroup(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.deletePostGroup(args.group);\n status(`✅ Post group ${args.group} deleted from every channel`);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to delete post group', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { result, fail } from '../output';\n\nexport async function listIntegrations(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.listIntegrations(args?.group);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list integrations', error);\n }\n}\n\nexport async function listGroups() {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.listGroups();\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list groups', error);\n }\n}\n\nexport async function getIntegrationSettings(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getIntegrationSettings(args.id);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get integration settings', error);\n }\n}\n\nexport async function triggerIntegrationTool(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n // Parse data from JSON string or use empty object\n let data: Record<string, string> = {};\n if (args.data) {\n try {\n data = JSON.parse(args.data);\n } catch (error: any) {\n console.error(`❌ Failed to parse data JSON: ${error.message}`);\n process.exit(1);\n }\n }\n\n try {\n const res = await api.triggerIntegrationTool(args.id, args.method, data);\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to trigger tool', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { result, fail } from '../output';\n\nfunction daysArg(args: any): string {\n const days = String(args.days ?? '7');\n if (!/^\\d+$/.test(days) || Number(days) < 1) {\n console.error('❌ --days must be a positive whole number of days, e.g. --days 30');\n process.exit(1);\n }\n return days;\n}\n\nexport async function getAnalytics(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getAnalytics(args.id, daysArg(args));\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get analytics', error);\n }\n}\n\nexport async function getPostAnalytics(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getPostAnalytics(args.id, daysArg(args));\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to get post analytics', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { result, status, fail } from '../output';\nimport { readFileSync, existsSync } from 'fs';\nimport { basename } from 'path';\nimport { BRAND } from '../brand';\n\nexport async function uploadFile(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n if (!existsSync(args.file)) {\n console.error(`❌ File not found: ${args.file}`);\n process.exit(1);\n }\n\n try {\n const fileBuffer = readFileSync(args.file);\n const filename = basename(args.file) || 'file';\n\n const res = await api.upload(fileBuffer, filename);\n status('✅ File uploaded successfully!');\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to upload file', error);\n }\n}\n\n/**\n * `postemi upload:link` — for a file that is NOT on this machine.\n *\n * `postemi upload` needs the file on disk. When the person has it on their\n * phone, or the agent running this CLI cannot see their filesystem, mint a\n * link instead: they open it in any browser, drop the files, and\n * `postemi upload:files <id>` returns what arrived.\n */\nexport async function createUploadLink() {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.createUploadLink();\n status(\n `🔗 Upload link created. Open it in a browser, drop the files, then run: ${BRAND.cli} upload:files ${res.id}`\n );\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to create an upload link', error);\n }\n}\n\nexport async function listUploadLinkFiles(args: any) {\n const config = getConfig();\n const api = new PostemiAPI(config);\n\n try {\n const res = await api.getUploadLinkFiles(args.id);\n if (res.status === 'empty') {\n status('⏳ Nothing has arrived through this link yet. Ask the person to check the page says \"uploaded\", then run this again.');\n } else {\n status(`✅ ${res.count} file(s) arrived. Use each .path in posts:create -m`);\n }\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to read the upload link', error);\n }\n}\n","import {\n KNOWN_SETTINGS,\n SettingKey,\n loadSettings,\n saveSetting,\n settingsFilePath,\n} from '../settings';\nimport { assertIanaTimezone } from '../dates';\nimport { result, status } from '../output';\n\nfunction assertKnownKey(key: string): SettingKey {\n if (!(KNOWN_SETTINGS as readonly string[]).includes(key)) {\n console.error(\n `❌ Unknown setting \"${key}\". Known settings: ${KNOWN_SETTINGS.join(', ')}`\n );\n process.exit(1);\n }\n return key as SettingKey;\n}\n\nexport async function configSet(args: any) {\n const key = assertKnownKey(args.key);\n let value = String(args.value);\n\n if (key === 'timezone') {\n try {\n value = assertIanaTimezone(value, 'config:set');\n } catch (error: any) {\n console.error(`❌ ${error.message}`);\n process.exit(1);\n }\n }\n\n saveSetting(key, value);\n status(`✅ ${key} = ${value} saved to ${settingsFilePath()}`);\n result({ [key]: value });\n}\n\nexport async function configGet(args: any) {\n const settings = loadSettings();\n\n if (args.key) {\n const key = assertKnownKey(args.key);\n result({ [key]: settings[key] ?? null });\n return;\n }\n\n result(settings);\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig, getWorkspaceId } from '../config';\nimport { loadCredentials, saveCredentials } from './auth';\nimport { saveSetting, settingsFilePath } from '../settings';\nimport { result, status, fail } from '../output';\nimport { BRAND } from '../brand';\n\n/**\n * `postemi workspaces:list` — every workspace the credential can act on, with\n * `current` marking the one requests go to. A key from `postemi auth:login`\n * spans one workspace unless \"all my workspaces\" was ticked on the approval\n * page; a key made in Settings can span any number.\n */\nexport async function listWorkspaces() {\n const api = new PostemiAPI(getConfig());\n try {\n const res = await api.listWorkspaces();\n result(res);\n return res;\n } catch (error: any) {\n fail('Failed to list workspaces', error);\n }\n}\n\n/**\n * `postemi workspaces:use <id>` — make every following command act on that\n * workspace. Checked against the API first, so a typo is refused here and\n * not on the next post. Stored next to the token for a device login, in\n * config.json for a key that comes from the environment.\n */\nexport async function useWorkspace(args: any) {\n const id = String(args.id || '').trim();\n if (!id) {\n fail('Failed to select workspace', new Error(`Give the workspace id, from \"${BRAND.cli} workspaces:list\"`));\n }\n\n // Listed WITHOUT naming a workspace: the list route is the one route that\n // answers for a multi-workspace key either way, and asking with the header\n // would trip the target's subscription gate before the choice is even saved.\n const api = new PostemiAPI({ ...getConfig(), workspaceId: undefined });\n\n let workspaces;\n try {\n workspaces = await api.listWorkspaces();\n } catch (error: any) {\n fail('Failed to select workspace', error);\n }\n\n const chosen = workspaces.find((w) => w.id === id);\n if (!chosen) {\n fail(\n 'Failed to select workspace',\n new Error(\n `This credential cannot act on workspace ${id}. Available: ${workspaces\n .map((w) => `${w.name} (${w.id})`)\n .join(', ') || 'none'}`\n )\n );\n }\n\n const creds = loadCredentials();\n if (creds) {\n saveCredentials({ ...creds, organizationId: chosen.id });\n status(`✅ Workspace set to ${chosen.name} (saved with your login)`);\n } else {\n saveSetting('workspace', chosen.id);\n status(`✅ Workspace set to ${chosen.name} (saved to ${settingsFilePath()})`);\n }\n result({ id: chosen.id, name: chosen.name, role: chosen.role });\n}\n\n/** `postemi workspaces:current` — the one requests go to, or null. */\nexport async function currentWorkspace() {\n const id = getWorkspaceId();\n const api = new PostemiAPI(getConfig());\n try {\n const workspaces = await api.listWorkspaces();\n const current = workspaces.find((w) => w.current) || null;\n if (!current && workspaces.length > 1) {\n status(\n `No workspace selected and this key spans several. Run: ${BRAND.cli} workspaces:use <id>`\n );\n }\n result(current ?? (id ? { id, name: null } : null));\n } catch (error: any) {\n fail('Failed to read the current workspace', error);\n }\n}\n","import { PostemiAPI } from '../api';\nimport { getConfig } from '../config';\nimport { openBrowser } from './auth';\nimport { result, status, fail } from '../output';\nimport { BRAND, tierForApi } from '../brand';\n\n/*\n SUBSCRIBING FROM A SHELL, WITH THE ONE STEP THAT STAYS HUMAN.\n\n An agent driving this CLI can show the plans, ask for a checkout link and\n confirm afterwards that the plan is live. It cannot pay, and it must not\n try: the link is Stripe's Managed Payments Checkout, the person opens it\n and pays with their own Link wallet or card. A one-time or agent-issued\n card would fail at the first renewal and end the plan, so `billing:subscribe`\n says so on stderr every time it prints a link.\n*/\n\n/** `postemi billing:plans` — the four plans, their prices, and the current tier. */\nexport async function billingPlans() {\n const api = new PostemiAPI(getConfig());\n try {\n result(await api.getPlans());\n } catch (error: any) {\n fail('Failed to read the plans', error);\n }\n}\n\n/**\n * `postemi billing:subscribe --tier pro --period yearly [--open]` — a Stripe\n * Checkout link for the plan. Printed as JSON on stdout; `--open` also opens\n * it in the browser of the machine the CLI runs on, which is only useful when\n * that machine is the person's own.\n */\nexport async function billingSubscribe(args: any) {\n const tier = String(args.tier || '').trim();\n const period = String(args.period || '').trim().toLowerCase();\n\n if (!tier) {\n fail(\n 'Failed to start the subscription',\n new Error(`Give the plan with --tier (${BRAND.tierList}; see \"${BRAND.cli} billing:plans\")`)\n );\n }\n if (period !== 'monthly' && period !== 'yearly') {\n fail(\n 'Failed to start the subscription',\n new Error('Give the period with --period monthly or --period yearly')\n );\n }\n\n const api = new PostemiAPI(getConfig());\n try {\n const checkout = await api.createSubscriptionCheckout(tierForApi(tier), period);\n status(\n `Checkout link for ${checkout.plan} (${checkout.period.toLowerCase()}, ${checkout.amount} ${checkout.currency}${\n checkout.trial ? `, ${checkout.trialDays}-day free trial` : ''\n }). The link expires at ${checkout.expiresAt}.`\n );\n status(\n `The subscriber opens this link and pays in Stripe Checkout with their own Link wallet or card. Do not pay with a one-time or agent-issued card: the subscription renews and a one-time card fails at the first renewal. After paying, run \"${BRAND.cli} billing:status\" to confirm.`\n );\n /*\n The note goes to stderr ONCE, in the CLI's own words: the server's text\n is shared with the MCP tools, and the JSON on stdout carries\n `apiAndMcpAccess: false` for a script to act on. Printing `note` in both\n streams showed the person the same warning twice.\n */\n const { note: _note, ...json } = checkout;\n if (checkout.apiAndMcpAccess === false) {\n status(\n `The ${checkout.plan} plan has no API or MCP access: after the payment this key still reaches only the billing commands, and the person uses ${BRAND.name} in the web app. Tell the person before they pay; a plan with apiAndMcpAccess: true in \"${BRAND.cli} billing:plans\" keeps the CLI working.`\n );\n }\n if (args.open) {\n openBrowser(checkout.checkoutUrl);\n status('Opened the checkout in the browser.');\n }\n result(json);\n } catch (error: any) {\n fail('Failed to start the subscription', error);\n }\n}\n\n/** `postemi billing:status` — the subscription state and any unpaid checkout. */\nexport async function billingStatus() {\n const api = new PostemiAPI(getConfig());\n try {\n const subscription = await api.getSubscription();\n if (subscription.pendingCheckout) {\n const pending = subscription.pendingCheckout;\n const when = (iso: string) =>\n iso ? new Date(iso).toLocaleString() : 'an unknown time';\n status(\n `A checkout for ${pending.plan}${\n pending.period ? ` (${pending.period.toLowerCase()})` : ''\n } started at ${when(pending.startedAt)} has not been paid yet. The link is in pendingCheckout.checkoutUrl and expires at ${when(pending.expiresAt)}.`\n );\n }\n result(subscription);\n } catch (error: any) {\n fail('Failed to read the subscription', error);\n }\n}\n\n/** `postemi billing:manage [--open]` — a link to the Stripe billing portal. */\nexport async function billingManage(args: any) {\n const api = new PostemiAPI(getConfig());\n try {\n const portal = await api.getSubscriptionPortal();\n // Once, on stderr; the JSON keeps only what a script acts on.\n const { note, ...json } = portal;\n status(note);\n if (args.open) {\n openBrowser(portal.portalUrl);\n status('Opened the billing portal in the browser.');\n }\n result(json);\n } catch (error: any) {\n fail('Failed to open the billing portal', error);\n }\n}\n"],"mappings":"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","names":["status","import_fs","import_path","import_os","import_readline","import_os","import_path","import_fs","import_path","ask","ask","import_fs","import_fs","import_path","yargs"]}
|