/** * Scheduler manifest emitter — generates the artifacts a recurring cost-reduction * agent needs to run on a schedule. * * Three output surfaces: * 1. policy.yaml — declarative policy the CLI tick consumes. * 2. Scheduler manifest — CronJob YAML | GHA workflow | crontab line+script. * 3. (optional) Initial dry-run CSV — what would change on the first tick. * * No network calls. Pure string emitters, fully unit-testable. */ export type SchedulePreset = 'daily-03utc' | 'every-6h' | 'every-12h' | 'every-24h-localtz' | string; export type SchedulerKind = 'k8s_cron' | 'github_actions' | 'crontab' | 'eventbridge' | 'container_apps_job'; export interface PolicyOptions { /** List of service names the policy targets. Empty = all services. */ target_services: string[]; /** Desired savings percentage (1-95). */ target_percent: number; /** Volume budget (GB/mo, thermostat). When set it replaces target_percent in policy.yaml. */ budget_gb_monthly?: number; /** Cron schedule. Either a preset name or a raw cron expression. */ schedule: SchedulePreset; /** Which scheduler runtime to emit a manifest for. */ scheduler: SchedulerKind; /** Path or URL to the customer gitops config repo. */ config_plane: string; /** Services that must never be touched regardless of the policy. */ exceptions: string[]; /** * Minimum savings delta (percentage points) required before a new CSV * is committed. Prevents churn on small week-to-week fluctuations. */ min_delta_pp: number; /** Log10x env ID — used to scope the metric queries. */ env_id?: string; /** Kubernetes namespace for the CronJob (k8s_cron only). */ namespace?: string; /** Name of the k8s Secret holding LOG10X_API_KEY (k8s_cron only). */ secret_name?: string; } /** * Resolve a schedule preset to a canonical cron expression (5-field, * UTC). Custom strings are returned as-is — validation of arbitrary * expressions is left to the scheduler runtime. */ export declare function resolveCronExpression(schedule: SchedulePreset): string; /** * Convert a 5-field cron expression to the EventBridge Scheduler form: * `cron(minutes hours day-of-month month day-of-week year)`. * * Scheduler rejects `*` in both day-of-month and day-of-week — exactly one * must be `?`. Day-of-week is turned into `?` when both are wildcards * (the common case for our presets). */ export declare function toAwsCronExpression(cron5: string): string; /** Parse `s3://bucket/prefix` into its parts; null when not an S3 URI. */ export declare function parseS3ConfigPlane(repo: string): { bucket: string; prefix: string; } | null; /** * Emit the `policy.yaml` file the recurring CLI consumes each tick. * * Format is deliberately simple YAML — no anchors, no multi-document * streams. A future CLI flag `--policy policy.yaml` loads this file. */ export declare function emitPolicyYaml(opts: PolicyOptions): string; /** * Emit a Kubernetes CronJob manifest. Mounts a Secret for the API key * and runs `npx log10x-mcp --tick --policy /config/policy.yaml` on the * configured schedule. * * The ConfigMap for `policy.yaml` is emitted as a separate YAML document * (separated by `---`) so the user can `kubectl apply -f` the single file. */ export declare function emitK8sCronJob(opts: PolicyOptions): string; /** * Emit a GitHub Actions workflow YAML that runs `npx log10x-mcp --tick` * on the configured schedule. * * The workflow reads `LOG10X_API_KEY` from repository secrets and checks * out the gitops repo before running the tick so the CLI can read and * write the cap CSV files in-place. */ export declare function emitGitHubActions(opts: PolicyOptions): string; /** * Emit a crontab entry and a companion wrapper script. * * Returns an object with two string fields: * `crontab_line` — one crontab line to add via `crontab -e` * `wrapper_script` — a shell script the crontab entry invokes * * The wrapper script exports env vars and runs the tick, appending to a * local log file so the user can see the last run's output. */ export declare function emitCrontab(opts: PolicyOptions): { crontab_line: string; wrapper_script: string; }; /** * Emit a CloudFormation template that runs the tick entirely inside the * customer's AWS account: an EventBridge Scheduler schedule starts a * CodeBuild build on each tick, and the build runs `tenx-recur` against an * S3 config plane. * * CodeBuild rather than Lambda or Fargate because the tick is a Node CLI * fetched with npx: CodeBuild provides a managed Node container with the * aws CLI present and needs no VPC, cluster, image publish, or bundling. * * The config plane is an S3 prefix (`s3://bucket/prefix`). The build pulls * `policy.yaml` from it and `tenx-recur` reads and writes its state files * under the same prefix. The engine-facing mute file lands at * `/pipelines/run/receive/rate/mutes.csv` — point * `TENX_RECEIVE_MUTE_S3_URI` at that key. */ export declare function emitEventBridge(opts: PolicyOptions): string; /** * Emit a bash deploy script that creates an Azure Container Apps scheduled * Job running the tick inside the customer's subscription — the Azure-native * sibling of the eventbridge kind. The config plane stays the git policy * repo: the certified delivery lane on Azure is the engine's gitops pull * (GH_DEST), so the tick clones, recomputes, and pushes; Azure only provides * the schedule. (An Azure Files plane was certified dead on Container Apps — * REST writes never wake the engine's reload poll and SMB writers are denied * by the reader's mount — so no share-based variant is emitted.) * * Shapes pinned by measurement on a live ACA environment: * - `az containerapp job create --yaml` — mixing --yaml with flags makes * the CLI ignore the flags, so everything lives in the manifest. * - MCR image, not docker.io — anonymous docker.io pulls from Azure IPs * rate-limit and the job dies with "no replicas found". * - replicaTimeout 900 — the npx cold fetch plus clone needs headroom. */ export declare function emitContainerAppsJob(opts: PolicyOptions): string; /** * Minimal YAML scalar quoting: wrap in double-quotes if the string * contains characters that YAML parsers would mis-read as block/flow * indicators, or is a bare number/bool/null. Doesn't handle multi-line * strings (none of our outputs produce them). */ export declare function yamlString(s: string): string;