@adport/core 0.1.0 → 0.3.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/dist/index.d.ts CHANGED
@@ -130,6 +130,8 @@ declare class ProviderRegistry {
130
130
  get(id: string): AdProvider;
131
131
  list(): AdProvider[];
132
132
  }
133
+ /** Select providers for a read operation and fail clearly when none exist. */
134
+ declare function selectConnectedProviders(registry: ProviderRegistry, providerId?: string): AdProvider[];
133
135
 
134
136
  type FindingSeverity = 'info' | 'warn' | 'critical';
135
137
  type FindingStatus = 'open' | 'dismissed' | 'applied';
@@ -318,33 +320,13 @@ declare class PendingStore {
318
320
  }
319
321
 
320
322
  declare const policySchema: z.ZodObject<{
321
- /** Writes must be validated (dry-run) before they can be applied. */
322
323
  require_validation: z.ZodDefault<z.ZodBoolean>;
323
- /** Created campaigns/ad groups/ads are coerced to PAUSED. */
324
324
  paused_creation: z.ZodDefault<z.ZodBoolean>;
325
- /** Reject budget changes exceeding this percentage of the current value. null = no cap. */
326
325
  max_budget_delta_pct: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
327
- /** Reject any budget set above this absolute value (micros). null = no cap. */
328
326
  max_daily_budget_micros: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
329
- /** Account ids that no write may touch. */
330
- protected_accounts: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
331
- /** How long a validated pending operation stays applicable. */
327
+ protected_accounts: z.ZodDefault<z.ZodArray<z.ZodString>>;
332
328
  pending_ttl_minutes: z.ZodDefault<z.ZodNumber>;
333
- }, "strip", z.ZodTypeAny, {
334
- require_validation: boolean;
335
- paused_creation: boolean;
336
- max_budget_delta_pct: number | null;
337
- max_daily_budget_micros: number | null;
338
- protected_accounts: string[];
339
- pending_ttl_minutes: number;
340
- }, {
341
- require_validation?: boolean | undefined;
342
- paused_creation?: boolean | undefined;
343
- max_budget_delta_pct?: number | null | undefined;
344
- max_daily_budget_micros?: number | null | undefined;
345
- protected_accounts?: string[] | undefined;
346
- pending_ttl_minutes?: number | undefined;
347
- }>;
329
+ }, z.core.$strip>;
348
330
  type Policy = z.infer<typeof policySchema>;
349
331
  declare const DEFAULT_POLICY: Policy;
350
332
  interface LoadedPolicy {
@@ -479,8 +461,8 @@ interface CreateContextOptions {
479
461
  /** Extra providers with their tools (e.g. the Google provider from @adport/provider-google). */
480
462
  providerModules?: ProviderModule[];
481
463
  /**
482
- * Include the credential-free mock provider. Defaults to true when no real
483
- * provider module is passed, so a fresh install always has something to try.
464
+ * Include the credential-free mock provider. Disabled by default so a
465
+ * misconfigured live runtime cannot silently substitute synthetic accounts.
484
466
  */
485
467
  includeMock?: boolean;
486
468
  }
@@ -491,4 +473,4 @@ interface AdportRuntime {
491
473
  }
492
474
  declare function createContext(options?: CreateContextOptions): Promise<AdportRuntime>;
493
475
 
494
- export { type Account, type AdProvider, AdportError, type AdportErrorCode, type AdportRuntime, type AnyToolDefinition, type ApplyOutcome, type AuditEntry, type AuditFinding, AuditLog, type AuditRunOptions, type AuditRunResult, AuditRunner, type BudgetDelta, type CreateContextOptions, type CredentialRecord, type CredentialSource, CredentialStore, DATE_PRESETS, DEFAULT_POLICY, type DatePreset, type DateRange, ENTITY_LEVELS, type EntityLevel, type FindingSeverity, type FindingStatus, FindingsStore, type LoadedPolicy, METRICS, type MetricName, MockProvider, type NormalizedQuery, type PendingOperation, PendingStore, type Policy, PolicyEngine, type ProviderCapabilities, type ProviderModule, ProviderRegistry, type Report, type ReportRow, type Rule, type RuleContext, type RuleFinding, type RulePack, type StandardAction, type StandardActions, type ToolAnnotations, type ToolContext, ToolRegistry, type ValidationOutcome, type WriteGuard, type WriteKind, type WriteOperation, type WritePreview, type WriteResult, adportHome, auditTools, builtinTools, corePerformancePack, createContext, defineTool, guardedWriteTool, hashOperation, loadPolicy, mockTools, policySchema, rangeDayCount, resolveDateRange };
476
+ export { type Account, type AdProvider, AdportError, type AdportErrorCode, type AdportRuntime, type AnyToolDefinition, type ApplyOutcome, type AuditEntry, type AuditFinding, AuditLog, type AuditRunOptions, type AuditRunResult, AuditRunner, type BudgetDelta, type CreateContextOptions, type CredentialRecord, type CredentialSource, CredentialStore, DATE_PRESETS, DEFAULT_POLICY, type DatePreset, type DateRange, ENTITY_LEVELS, type EntityLevel, type FindingSeverity, type FindingStatus, FindingsStore, type LoadedPolicy, METRICS, type MetricName, MockProvider, type NormalizedQuery, type PendingOperation, PendingStore, type Policy, PolicyEngine, type ProviderCapabilities, type ProviderModule, ProviderRegistry, type Report, type ReportRow, type Rule, type RuleContext, type RuleFinding, type RulePack, type StandardAction, type StandardActions, type ToolAnnotations, type ToolContext, ToolRegistry, type ValidationOutcome, type WriteGuard, type WriteKind, type WriteOperation, type WritePreview, type WriteResult, adportHome, auditTools, builtinTools, corePerformancePack, createContext, defineTool, guardedWriteTool, hashOperation, loadPolicy, mockTools, policySchema, rangeDayCount, resolveDateRange, selectConnectedProviders };
package/dist/index.js CHANGED
@@ -81,6 +81,17 @@ var ProviderRegistry = class {
81
81
  return [...this.providers.values()];
82
82
  }
83
83
  };
84
+ function selectConnectedProviders(registry, providerId) {
85
+ if (providerId) return [registry.get(providerId)];
86
+ const providers = registry.list();
87
+ if (providers.length === 0) {
88
+ throw new AdportError(
89
+ "NOT_CONNECTED",
90
+ "No ad providers are connected. Run `adport connect <provider>` first, configure provider environment variables, or use `--demo` for synthetic mock data."
91
+ );
92
+ }
93
+ return providers;
94
+ }
84
95
 
85
96
  // src/audit/packs/core-performance.ts
86
97
  function isActive(status) {
@@ -232,7 +243,7 @@ var AuditRunner = class {
232
243
  async run(options = {}) {
233
244
  const range = resolveDateRange(options.dateRange ?? "last_30_days");
234
245
  const packs = options.packs ?? [corePerformancePack];
235
- const providers = options.provider ? [this.providers.get(options.provider)] : this.providers.list();
246
+ const providers = selectConnectedProviders(this.providers, options.provider);
236
247
  const findings = [];
237
248
  let evaluatedAccounts = 0;
238
249
  for (const provider of providers) {
@@ -812,7 +823,7 @@ function builtinTools() {
812
823
  }),
813
824
  annotations: { readOnly: true },
814
825
  async handler(input, ctx) {
815
- const providers = input.provider ? [ctx.providers.get(input.provider)] : ctx.providers.list();
826
+ const providers = selectConnectedProviders(ctx.providers, input.provider);
816
827
  const accounts = [];
817
828
  for (const provider of providers) {
818
829
  accounts.push(...await provider.listAccounts());
@@ -834,7 +845,7 @@ function builtinTools() {
834
845
  }),
835
846
  annotations: { readOnly: true },
836
847
  async handler(input, ctx) {
837
- const providers = input.provider ? [ctx.providers.get(input.provider)] : ctx.providers.list();
848
+ const providers = selectConnectedProviders(ctx.providers, input.provider);
838
849
  const query = {
839
850
  accountIds: input.account_ids,
840
851
  level: input.level,
@@ -1099,7 +1110,7 @@ function mockTools() {
1099
1110
  // src/context.ts
1100
1111
  async function createContext(options = {}) {
1101
1112
  const modules = options.providerModules ?? [];
1102
- const includeMock = options.includeMock ?? modules.length === 0;
1113
+ const includeMock = options.includeMock ?? false;
1103
1114
  const providers = new ProviderRegistry();
1104
1115
  const { policy, source } = await loadPolicy(options.policyPath);
1105
1116
  const engine = new PolicyEngine(policy);
@@ -1146,6 +1157,7 @@ export {
1146
1157
  mockTools,
1147
1158
  policySchema,
1148
1159
  rangeDayCount,
1149
- resolveDateRange
1160
+ resolveDateRange,
1161
+ selectConnectedProviders
1150
1162
  };
1151
1163
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/paths.ts","../src/model.ts","../src/provider.ts","../src/audit/packs/core-performance.ts","../src/audit/store.ts","../src/audit/runner.ts","../src/audit/tools.ts","../src/tools/registry.ts","../src/credentials/store.ts","../src/policy/policy.ts","../src/policy/pending.ts","../src/policy/audit.ts","../src/policy/engine.ts","../src/tools/write.ts","../src/tools/builtin.ts","../src/testing/mock-provider.ts","../src/context.ts"],"sourcesContent":["export type AdportErrorCode =\n | 'POLICY_VIOLATION'\n | 'PENDING_NOT_FOUND'\n | 'PENDING_EXPIRED'\n | 'PENDING_MISMATCH'\n | 'PROVIDER_ERROR'\n | 'INVALID_INPUT'\n | 'NOT_CONNECTED'\n | 'UNKNOWN_TOOL';\n\nexport class AdportError extends Error {\n constructor(\n public readonly code: AdportErrorCode,\n message: string,\n public readonly details?: unknown,\n ) {\n super(message);\n this.name = 'AdportError';\n }\n\n toJSON() {\n return { error: this.code, message: this.message, details: this.details };\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\n/**\n * All adport state (credentials, pending operations, audit log, policy) lives\n * under this directory. ADPORT_HOME overrides it — used by tests and CI.\n */\nexport function adportHome(): string {\n return process.env.ADPORT_HOME ?? path.join(os.homedir(), '.config', 'adport');\n}\n","export const METRICS = [\n 'spend',\n 'impressions',\n 'clicks',\n 'conversions',\n 'conversion_value',\n 'ctr',\n 'cpc',\n 'cpm',\n 'cpa',\n 'roas',\n] as const;\nexport type MetricName = (typeof METRICS)[number];\n\nexport const ENTITY_LEVELS = ['account', 'campaign', 'ad_group', 'ad'] as const;\nexport type EntityLevel = (typeof ENTITY_LEVELS)[number];\n\nexport const DATE_PRESETS = ['today', 'yesterday', 'last_7_days', 'last_30_days', 'this_month'] as const;\nexport type DatePreset = (typeof DATE_PRESETS)[number];\n\n/** ISO dates, inclusive on both ends. */\nexport interface DateRange {\n start: string;\n end: string;\n}\n\nexport interface NormalizedQuery {\n /** Provider ids to query; omit for all connected providers. */\n providers?: string[];\n /** Account ids to include; omit for all accounts of the selected providers. */\n accountIds?: string[];\n level: EntityLevel;\n metrics: MetricName[];\n dateRange: DateRange | DatePreset;\n limit?: number;\n}\n\nexport interface ReportRow {\n provider: string;\n accountId: string;\n entity: { level: EntityLevel; id: string; name: string; status?: string };\n metrics: Partial<Record<MetricName, number>>;\n}\n\nexport interface Report {\n rows: ReportRow[];\n truncated?: boolean;\n}\n\nfunction iso(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\nexport function resolveDateRange(range: DateRange | DatePreset, now = new Date()): DateRange {\n if (typeof range !== 'string') return range;\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const daysAgo = (n: number) => new Date(today.getTime() - n * 86_400_000);\n switch (range) {\n case 'today':\n return { start: iso(today), end: iso(today) };\n case 'yesterday':\n return { start: iso(daysAgo(1)), end: iso(daysAgo(1)) };\n case 'last_7_days':\n return { start: iso(daysAgo(7)), end: iso(daysAgo(1)) };\n case 'last_30_days':\n return { start: iso(daysAgo(30)), end: iso(daysAgo(1)) };\n case 'this_month':\n return { start: iso(new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))), end: iso(today) };\n }\n}\n\nexport function rangeDayCount(range: DateRange): number {\n const start = Date.parse(`${range.start}T00:00:00Z`);\n const end = Date.parse(`${range.end}T00:00:00Z`);\n return Math.max(1, Math.round((end - start) / 86_400_000) + 1);\n}\n","import { AdportError } from './errors.js';\nimport type { NormalizedQuery, Report } from './model.js';\n\nexport interface Account {\n provider: string;\n id: string;\n name: string;\n currency?: string;\n status?: string;\n}\n\nexport type WriteKind = 'create' | 'update' | 'remove';\n\nexport interface WriteOperation {\n /** Tool name that produced this operation — part of the audit trail. */\n tool: string;\n provider: string;\n accountId: string;\n kind: WriteKind;\n payload: Record<string, unknown>;\n}\n\nexport interface BudgetDelta {\n /** Human-readable target, e.g. \"campaign c1 daily budget\". */\n target: string;\n fromMicros?: number;\n toMicros: number;\n}\n\nexport interface WritePreview {\n summary: string;\n changes: string[];\n /** Adjustments the guard forced (e.g. \"status coerced to PAUSED\"). Never silent. */\n coercions: string[];\n budgetDeltas: BudgetDelta[];\n /** True when the platform validated the operation server-side (dry run). */\n serverValidated: boolean;\n}\n\nexport interface WriteResult {\n applied: true;\n resourceIds: string[];\n details?: unknown;\n}\n\n/** Policy-derived constraints handed to providers on every preview/apply. */\nexport interface WriteGuard {\n forcePausedCreation: boolean;\n}\n\nexport interface ProviderCapabilities {\n serverDryRun: boolean;\n}\n\n/** A ready-to-call tool invocation (flows through the normal validate→apply gate). */\nexport interface StandardAction {\n tool: string;\n input: Record<string, unknown>;\n}\n\n/**\n * Provider-declared mappings for cross-platform actions the audit harness can\n * propose (each provider knows its own tool names and native status values).\n */\nexport interface StandardActions {\n pauseCampaign?: (accountId: string, campaignId: string) => StandardAction;\n}\n\nexport interface AdProvider {\n readonly id: string;\n capabilities(): ProviderCapabilities;\n listAccounts(): Promise<Account[]>;\n report(query: NormalizedQuery): Promise<Report>;\n /** Dry-run the operation (server-side where supported, client-side diff otherwise). */\n previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview>;\n /** Execute the operation for real. Only the policy engine may call this. */\n applyWrite(op: WriteOperation, guard: WriteGuard): Promise<WriteResult>;\n /** Optional cross-platform action mappings used by the recommendation harness. */\n standardActions?(): StandardActions;\n}\n\nexport class ProviderRegistry {\n private providers = new Map<string, AdProvider>();\n\n register(provider: AdProvider): void {\n this.providers.set(provider.id, provider);\n }\n\n get(id: string): AdProvider {\n const provider = this.providers.get(id);\n if (!provider) {\n throw new AdportError(\n 'NOT_CONNECTED',\n `Provider \"${id}\" is not connected. Run \\`adport connect ${id}\\` first.`,\n );\n }\n return provider;\n }\n\n list(): AdProvider[] {\n return [...this.providers.values()];\n }\n}\n","import type { Rule, RulePack } from '../types.js';\n\n/** Active unless the status clearly says otherwise (provider vocabularies differ). */\nfunction isActive(status?: string): boolean {\n return !/(PAUS|DISABLE|REMOV|DELET|CLOS|ARCHIV)/i.test(status ?? 'ENABLED');\n}\n\nconst zeroConversionSpend: Rule = {\n id: 'zero-conversion-spend',\n title: 'Active campaign spending with zero conversions',\n description: 'Flags campaigns that spent above the threshold over the range without a single tracked conversion.',\n evaluate(ctx) {\n const minSpend = ctx.config.zero_conversion_min_spend!;\n return ctx.rows\n .filter((row) => isActive(row.entity.status))\n .filter((row) => (row.metrics.spend ?? 0) >= minSpend && (row.metrics.conversions ?? 0) === 0)\n .map((row) => ({\n entity: row.entity,\n severity: (row.metrics.spend ?? 0) >= minSpend * 3 ? ('critical' as const) : ('warn' as const),\n title: `\"${row.entity.name}\" spent ${row.metrics.spend} with 0 conversions`,\n detail:\n `Campaign ${row.entity.id} spent ${row.metrics.spend} between ${ctx.range.start} and ${ctx.range.end} ` +\n 'without any tracked conversion. Either conversion tracking is broken or the spend is wasted.',\n recommendation:\n 'Verify conversion tracking first; if tracking is correct, pause the campaign and rework targeting/creative.',\n proposedAction: ctx.actions.pauseCampaign?.(ctx.accountId, row.entity.id),\n metrics: row.metrics,\n }));\n },\n};\n\nconst lowCtr: Rule = {\n id: 'low-ctr',\n title: 'High impressions with very low CTR',\n description: 'Flags campaigns whose creative/targeting is not resonating (lots of impressions, few clicks).',\n evaluate(ctx) {\n const minImpressions = ctx.config.low_ctr_min_impressions!;\n const threshold = ctx.config.low_ctr_threshold_pct!;\n return ctx.rows\n .filter((row) => isActive(row.entity.status))\n .filter((row) => (row.metrics.impressions ?? 0) >= minImpressions && (row.metrics.ctr ?? 100) < threshold)\n .map((row) => ({\n entity: row.entity,\n severity: 'warn' as const,\n title: `\"${row.entity.name}\" CTR ${row.metrics.ctr}% over ${row.metrics.impressions} impressions`,\n detail: `CTR is below ${threshold}% despite meaningful reach — the ad or audience likely needs work.`,\n recommendation: 'Review creative and audience targeting; test new headlines/assets before touching budgets.',\n metrics: row.metrics,\n }));\n },\n};\n\nconst cpaOutlier: Rule = {\n id: 'cpa-outlier',\n title: 'Campaign CPA far above account median',\n description: 'Flags converting campaigns whose cost per conversion is a large multiple of the account median.',\n evaluate(ctx) {\n const multiplier = ctx.config.cpa_outlier_multiplier!;\n const converting = ctx.rows.filter((row) => (row.metrics.conversions ?? 0) > 0 && (row.metrics.cpa ?? 0) > 0);\n if (converting.length < 3) return [];\n const cpas = converting.map((row) => row.metrics.cpa!).sort((a, b) => a - b);\n const median = cpas[Math.floor(cpas.length / 2)]!;\n return converting\n .filter((row) => row.metrics.cpa! > median * multiplier)\n .map((row) => ({\n entity: row.entity,\n severity: 'warn' as const,\n title: `\"${row.entity.name}\" CPA ${row.metrics.cpa} vs account median ${median}`,\n detail: `Cost per conversion is more than ${multiplier}× the account median over the range.`,\n recommendation: 'Shift budget toward lower-CPA campaigns, or tighten targeting/bids here.',\n metrics: row.metrics,\n }));\n },\n};\n\nconst negativeRoas: Rule = {\n id: 'negative-roas',\n title: 'Campaign returning less than it spends',\n description: 'Flags campaigns with tracked revenue whose ROAS is below break-even.',\n evaluate(ctx) {\n const minSpend = ctx.config.roas_min_spend!;\n return ctx.rows\n .filter((row) => isActive(row.entity.status))\n .filter(\n (row) =>\n (row.metrics.spend ?? 0) >= minSpend &&\n (row.metrics.conversion_value ?? 0) > 0 &&\n (row.metrics.roas ?? 0) < 1,\n )\n .map((row) => ({\n entity: row.entity,\n severity: 'warn' as const,\n title: `\"${row.entity.name}\" ROAS ${row.metrics.roas} (below break-even)`,\n detail: `Spent ${row.metrics.spend} for ${row.metrics.conversion_value} in tracked revenue over the range.`,\n recommendation: 'Check margins and attribution windows; consider bid/budget reduction or audience changes.',\n metrics: row.metrics,\n }));\n },\n};\n\nexport const corePerformancePack: RulePack = {\n name: 'core-performance',\n version: '0.1.0',\n rules: [zeroConversionSpend, lowCtr, cpaOutlier, negativeRoas],\n defaults: {\n zero_conversion_min_spend: 50,\n low_ctr_min_impressions: 5000,\n low_ctr_threshold_pct: 0.5,\n cpa_outlier_multiplier: 2.5,\n roas_min_spend: 50,\n },\n};\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\nimport type { AuditFinding, FindingStatus } from './types.js';\n\n/**\n * Findings persist on disk with their approval lifecycle — the durable side of\n * the recommendation harness: a recommendation can wait for a human decision\n * across restarts, indefinitely, at zero cost.\n */\nexport class FindingsStore {\n constructor(private readonly dir: string = path.join(adportHome(), 'findings')) {}\n\n private file(id: string): string {\n return path.join(this.dir, `${id.replace(/[^a-zA-Z0-9_.:-]/g, '_')}.json`);\n }\n\n async list(filter: { status?: FindingStatus; provider?: string } = {}): Promise<AuditFinding[]> {\n let names: string[];\n try {\n names = await fs.readdir(this.dir);\n } catch {\n return [];\n }\n const findings: AuditFinding[] = [];\n for (const name of names) {\n if (!name.endsWith('.json')) continue;\n const finding = JSON.parse(await fs.readFile(path.join(this.dir, name), 'utf8')) as AuditFinding;\n if (filter.status && finding.status !== filter.status) continue;\n if (filter.provider && finding.provider !== filter.provider) continue;\n findings.push(finding);\n }\n const order: Record<string, number> = { critical: 0, warn: 1, info: 2 };\n return findings.sort((a, b) => (order[a.severity] ?? 3) - (order[b.severity] ?? 3));\n }\n\n async get(id: string): Promise<AuditFinding | undefined> {\n try {\n return JSON.parse(await fs.readFile(this.file(id), 'utf8')) as AuditFinding;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n }\n\n async save(finding: AuditFinding): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await fs.writeFile(this.file(finding.id), JSON.stringify(finding, null, 2), { mode: 0o600 });\n }\n\n async setStatus(id: string, status: FindingStatus): Promise<AuditFinding> {\n const finding = await this.get(id);\n if (!finding) throw new Error(`Finding not found: ${id}`);\n const updated = { ...finding, status, updatedAt: new Date().toISOString() };\n await this.save(updated);\n return updated;\n }\n}\n","import { resolveDateRange, type DatePreset, type DateRange, type ReportRow } from '../model.js';\nimport type { ProviderRegistry } from '../provider.js';\nimport { corePerformancePack } from './packs/core-performance.js';\nimport { FindingsStore } from './store.js';\nimport type { AuditFinding, RulePack } from './types.js';\n\nexport interface AuditRunOptions {\n provider?: string;\n accountIds?: string[];\n dateRange?: DateRange | DatePreset;\n packs?: RulePack[];\n configOverrides?: Record<string, number>;\n}\n\nexport interface AuditRunResult {\n findings: AuditFinding[];\n counts: { critical: number; warn: number; info: number };\n evaluatedAccounts: number;\n range: DateRange;\n}\n\n/**\n * The audit engine (OPA pattern): providers supply normalized state as input,\n * rule packs supply the checks, the runner evaluates and returns structured\n * findings. Rules never call provider APIs directly.\n */\nexport class AuditRunner {\n constructor(\n private readonly providers: ProviderRegistry,\n private readonly store: FindingsStore = new FindingsStore(),\n ) {}\n\n async run(options: AuditRunOptions = {}): Promise<AuditRunResult> {\n const range = resolveDateRange(options.dateRange ?? 'last_30_days');\n const packs = options.packs ?? [corePerformancePack];\n const providers = options.provider ? [this.providers.get(options.provider)] : this.providers.list();\n\n const findings: AuditFinding[] = [];\n let evaluatedAccounts = 0;\n\n for (const provider of providers) {\n const report = await provider.report({\n accountIds: options.accountIds,\n level: 'campaign',\n metrics: ['spend', 'impressions', 'clicks', 'conversions', 'conversion_value', 'ctr', 'cpc', 'cpa', 'roas'],\n dateRange: range,\n limit: 1000,\n });\n const byAccount = new Map<string, ReportRow[]>();\n for (const row of report.rows) {\n const rows = byAccount.get(row.accountId) ?? [];\n rows.push(row);\n byAccount.set(row.accountId, rows);\n }\n const actions = provider.standardActions?.() ?? {};\n\n for (const [accountId, rows] of byAccount) {\n evaluatedAccounts += 1;\n for (const pack of packs) {\n const config = { ...pack.defaults, ...options.configOverrides };\n for (const rule of pack.rules) {\n for (const ruleFinding of rule.evaluate({ provider: provider.id, accountId, rows, range, actions, config })) {\n const id = `${rule.id}:${provider.id}:${accountId}:${ruleFinding.entity.id}`;\n const existing = await this.store.get(id);\n // Respect earlier human decisions: don't reopen dismissed/applied findings.\n if (existing && existing.status !== 'open') continue;\n const now = new Date().toISOString();\n const finding: AuditFinding = {\n id,\n ruleId: rule.id,\n severity: ruleFinding.severity,\n provider: provider.id,\n accountId,\n entity: ruleFinding.entity,\n title: ruleFinding.title,\n detail: ruleFinding.detail,\n recommendation: ruleFinding.recommendation,\n proposedAction: ruleFinding.proposedAction,\n metrics: ruleFinding.metrics,\n dateRange: range,\n status: 'open',\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n };\n await this.store.save(finding);\n findings.push(finding);\n }\n }\n }\n }\n }\n\n return {\n findings,\n counts: {\n critical: findings.filter((f) => f.severity === 'critical').length,\n warn: findings.filter((f) => f.severity === 'warn').length,\n info: findings.filter((f) => f.severity === 'info').length,\n },\n evaluatedAccounts,\n range,\n };\n }\n}\n","import { z } from 'zod';\nimport { AdportError } from '../errors.js';\nimport { DATE_PRESETS } from '../model.js';\nimport { defineTool, type AnyToolDefinition } from '../tools/registry.js';\nimport { AuditRunner } from './runner.js';\nimport { FindingsStore } from './store.js';\n\nconst dateRangeSchema = z.union([\n z.enum(DATE_PRESETS),\n z.object({\n start: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n end: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n }),\n]);\n\nexport function auditTools(): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'audit_run',\n namespace: 'audit',\n description:\n 'Run the cross-platform audit rule packs over connected accounts (campaign level). ' +\n 'Returns structured findings with recommendations; some carry a ready-to-apply proposed action. ' +\n 'Reads ad data only — never mutates anything.',\n input: z.object({\n provider: z.string().optional(),\n account_ids: z.array(z.string()).optional(),\n date_range: dateRangeSchema.default('last_30_days'),\n }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const runner = new AuditRunner(ctx.providers);\n const result = await runner.run({\n provider: input.provider,\n accountIds: input.account_ids,\n dateRange: input.date_range,\n });\n return result;\n },\n }),\n defineTool({\n name: 'recommendations_list',\n namespace: 'audit',\n description: 'List persisted audit findings/recommendations (default: open ones), most severe first.',\n input: z.object({\n status: z.enum(['open', 'dismissed', 'applied']).default('open'),\n provider: z.string().optional(),\n }),\n annotations: { readOnly: true },\n async handler(input) {\n const findings = await new FindingsStore().list(input);\n return { findings, count: findings.length };\n },\n }),\n defineTool({\n name: 'recommendation_dismiss',\n namespace: 'audit',\n description: 'Dismiss a finding (it will not be re-opened by future audit runs).',\n input: z.object({ finding_id: z.string() }),\n annotations: { readOnly: false },\n async handler(input) {\n const finding = await new FindingsStore().setStatus(input.finding_id, 'dismissed');\n return { finding };\n },\n }),\n defineTool({\n name: 'recommendation_apply',\n namespace: 'audit',\n description:\n \"Execute a finding's proposed action through the normal two-step write flow: first call returns the dry-run \" +\n 'preview and pending_operation_id; second call (with the id) applies and marks the finding applied.',\n input: z.object({\n finding_id: z.string(),\n pending_operation_id: z.string().optional(),\n }),\n annotations: { readOnly: false },\n async handler(input, ctx) {\n if (!ctx.registry) {\n throw new AdportError('PROVIDER_ERROR', 'recommendation_apply requires a tool registry in context');\n }\n const store = new FindingsStore();\n const finding = await store.get(input.finding_id);\n if (!finding) throw new AdportError('INVALID_INPUT', `Finding not found: ${input.finding_id}`);\n if (finding.status !== 'open') {\n throw new AdportError('INVALID_INPUT', `Finding ${input.finding_id} is ${finding.status}, not open`);\n }\n if (!finding.proposedAction) {\n throw new AdportError(\n 'INVALID_INPUT',\n `Finding ${input.finding_id} has no proposed action — it needs human judgment (${finding.recommendation})`,\n );\n }\n const result = (await ctx.registry.call(\n finding.proposedAction.tool,\n {\n ...finding.proposedAction.input,\n ...(input.pending_operation_id ? { pending_operation_id: input.pending_operation_id } : {}),\n },\n ctx,\n )) as { status?: string };\n if (result.status === 'applied') {\n await store.setStatus(finding.id, 'applied');\n }\n return { finding_id: finding.id, action: finding.proposedAction, result };\n },\n }),\n ];\n}\n","import { z } from 'zod';\nimport type { CredentialStore } from '../credentials/store.js';\nimport { AdportError } from '../errors.js';\nimport type { PolicyEngine } from '../policy/engine.js';\nimport type { ProviderRegistry } from '../provider.js';\n\nexport interface ToolAnnotations {\n readOnly?: boolean;\n destructive?: boolean;\n}\n\nexport interface ToolContext {\n providers: ProviderRegistry;\n engine: PolicyEngine;\n credentials: CredentialStore;\n /** Set by createContext; lets tools invoke other tools (e.g. recommendation_apply). */\n registry?: ToolRegistry;\n}\n\nexport interface AnyToolDefinition {\n name: string;\n /** Grouping key used for config-based enable/disable (\"core\", \"mock\", \"google\", ...). */\n namespace: string;\n description: string;\n input: z.ZodObject<z.ZodRawShape>;\n annotations: ToolAnnotations;\n handler: (input: never, ctx: ToolContext) => Promise<unknown>;\n}\n\nexport function defineTool<S extends z.ZodObject<z.ZodRawShape>>(def: {\n name: string;\n namespace: string;\n description: string;\n input: S;\n annotations?: ToolAnnotations;\n handler: (input: z.infer<S>, ctx: ToolContext) => Promise<unknown>;\n}): AnyToolDefinition {\n return {\n ...def,\n annotations: def.annotations ?? { readOnly: false },\n } as AnyToolDefinition;\n}\n\nexport class ToolRegistry {\n private tools = new Map<string, AnyToolDefinition>();\n\n register(tools: AnyToolDefinition | AnyToolDefinition[]): void {\n for (const tool of Array.isArray(tools) ? tools : [tools]) {\n if (this.tools.has(tool.name)) {\n throw new Error(`Tool \"${tool.name}\" is already registered`);\n }\n this.tools.set(tool.name, tool);\n }\n }\n\n list(): AnyToolDefinition[] {\n return [...this.tools.values()];\n }\n\n get(name: string): AnyToolDefinition {\n const tool = this.tools.get(name);\n if (!tool) throw new AdportError('UNKNOWN_TOOL', `Unknown tool: ${name}`);\n return tool;\n }\n\n async call(name: string, rawInput: unknown, ctx: ToolContext): Promise<unknown> {\n const tool = this.get(name);\n const parsed = tool.input.safeParse(rawInput ?? {});\n if (!parsed.success) {\n throw new AdportError('INVALID_INPUT', `Invalid input for ${name}`, parsed.error.issues);\n }\n return tool.handler(parsed.data as never, ctx);\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\n\nexport type CredentialSource = 'byo' | 'broker';\n\nexport interface CredentialRecord {\n provider: string;\n source: CredentialSource;\n /** Provider-specific key/value secrets (tokens, client ids, ...). */\n data: Record<string, string>;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface CredentialFile {\n version: 1;\n credentials: Record<string, CredentialRecord>;\n}\n\nconst EMPTY: CredentialFile = { version: 1, credentials: {} };\n\n/**\n * File-backed credential store: ${ADPORT_HOME}/credentials.json, chmod 600.\n * OS keychain support may come later; the interface is deliberately async.\n */\nexport class CredentialStore {\n constructor(private readonly dir: string = adportHome()) {}\n\n private file(): string {\n return path.join(this.dir, 'credentials.json');\n }\n\n private async read(): Promise<CredentialFile> {\n try {\n const raw = await fs.readFile(this.file(), 'utf8');\n return JSON.parse(raw) as CredentialFile;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return structuredClone(EMPTY);\n throw err;\n }\n }\n\n private async write(data: CredentialFile): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await fs.writeFile(this.file(), `${JSON.stringify(data, null, 2)}\\n`, { mode: 0o600 });\n await fs.chmod(this.file(), 0o600);\n }\n\n async get(provider: string): Promise<CredentialRecord | undefined> {\n const file = await this.read();\n return file.credentials[provider];\n }\n\n async list(): Promise<CredentialRecord[]> {\n const file = await this.read();\n return Object.values(file.credentials);\n }\n\n async set(record: Omit<CredentialRecord, 'createdAt' | 'updatedAt'>): Promise<CredentialRecord> {\n const file = await this.read();\n const now = new Date().toISOString();\n const existing = file.credentials[record.provider];\n const full: CredentialRecord = { ...record, createdAt: existing?.createdAt ?? now, updatedAt: now };\n file.credentials[record.provider] = full;\n await this.write(file);\n return full;\n }\n\n async delete(provider: string): Promise<boolean> {\n const file = await this.read();\n if (!(provider in file.credentials)) return false;\n delete file.credentials[provider];\n await this.write(file);\n return true;\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { z } from 'zod';\nimport { adportHome } from '../paths.js';\n\nexport const policySchema = z.object({\n /** Writes must be validated (dry-run) before they can be applied. */\n require_validation: z.boolean().default(true),\n /** Created campaigns/ad groups/ads are coerced to PAUSED. */\n paused_creation: z.boolean().default(true),\n /** Reject budget changes exceeding this percentage of the current value. null = no cap. */\n max_budget_delta_pct: z.number().positive().nullable().default(25),\n /** Reject any budget set above this absolute value (micros). null = no cap. */\n max_daily_budget_micros: z.number().positive().nullable().default(null),\n /** Account ids that no write may touch. */\n protected_accounts: z.array(z.string()).default([]),\n /** How long a validated pending operation stays applicable. */\n pending_ttl_minutes: z.number().positive().default(15),\n});\n\nexport type Policy = z.infer<typeof policySchema>;\n\nexport const DEFAULT_POLICY: Policy = policySchema.parse({});\n\nexport interface LoadedPolicy {\n policy: Policy;\n /** Where the policy came from: a file path or \"defaults\". */\n source: string;\n}\n\n/**\n * Resolution order: explicit path → $ADPORT_POLICY → ./adport.policy.yaml →\n * ${ADPORT_HOME}/policy.yaml → built-in defaults.\n * A file that exists but fails validation is a hard error — never silently\n * fall back to weaker rails.\n */\nexport async function loadPolicy(explicitPath?: string): Promise<LoadedPolicy> {\n const candidates = [\n explicitPath,\n process.env.ADPORT_POLICY,\n path.join(process.cwd(), 'adport.policy.yaml'),\n path.join(adportHome(), 'policy.yaml'),\n ].filter((p): p is string => Boolean(p));\n\n for (const candidate of candidates) {\n let raw: string;\n try {\n raw = await fs.readFile(candidate, 'utf8');\n } catch {\n if (candidate === explicitPath || candidate === process.env.ADPORT_POLICY) {\n throw new Error(`Policy file not found: ${candidate}`);\n }\n continue;\n }\n const parsed = policySchema.safeParse(YAML.parse(raw) ?? {});\n if (!parsed.success) {\n throw new Error(`Invalid policy file ${candidate}: ${parsed.error.message}`);\n }\n return { policy: parsed.data, source: candidate };\n }\n return { policy: DEFAULT_POLICY, source: 'defaults' };\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\nimport type { WriteOperation, WritePreview } from '../provider.js';\n\nexport interface PendingOperation {\n id: string;\n provider: string;\n opHash: string;\n op: WriteOperation;\n preview: WritePreview;\n createdAt: string;\n expiresAt: string;\n}\n\n/**\n * File-backed store so validate and apply can happen in different processes\n * (CLI invocations, MCP server restarts).\n */\nexport class PendingStore {\n constructor(private readonly dir: string = path.join(adportHome(), 'pending')) {}\n\n private file(id: string): string {\n if (!/^[a-zA-Z0-9-]+$/.test(id)) throw new Error(`Invalid pending operation id: ${id}`);\n return path.join(this.dir, `${id}.json`);\n }\n\n async put(op: PendingOperation): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await fs.writeFile(this.file(op.id), JSON.stringify(op, null, 2), { mode: 0o600 });\n }\n\n async get(id: string): Promise<PendingOperation | undefined> {\n try {\n return JSON.parse(await fs.readFile(this.file(id), 'utf8')) as PendingOperation;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n }\n\n async delete(id: string): Promise<void> {\n await fs.rm(this.file(id), { force: true });\n }\n\n /** Remove expired entries. Called opportunistically; never throws on races. */\n async sweep(now = new Date()): Promise<void> {\n let names: string[];\n try {\n names = await fs.readdir(this.dir);\n } catch {\n return;\n }\n for (const name of names) {\n if (!name.endsWith('.json')) continue;\n try {\n const op = JSON.parse(await fs.readFile(path.join(this.dir, name), 'utf8')) as PendingOperation;\n if (Date.parse(op.expiresAt) < now.getTime()) {\n await fs.rm(path.join(this.dir, name), { force: true });\n }\n } catch {\n // Unreadable entry: leave it; get() will surface the problem explicitly.\n }\n }\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\n\nexport interface AuditEntry {\n ts: string;\n /** 'note' records external/manual changes made outside adport's write path. */\n event: 'validated' | 'applied' | 'rejected' | 'note';\n provider: string;\n tool: string;\n accountId: string;\n pendingId?: string;\n summary: string;\n details?: unknown;\n}\n\n/** Append-only JSONL, one file per month: ${ADPORT_HOME}/audit/audit-YYYY-MM.jsonl */\nexport class AuditLog {\n constructor(private readonly dir: string = path.join(adportHome(), 'audit')) {}\n\n private file(now = new Date()): string {\n const month = now.toISOString().slice(0, 7);\n return path.join(this.dir, `audit-${month}.jsonl`);\n }\n\n async append(entry: Omit<AuditEntry, 'ts'>): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n const full: AuditEntry = { ts: new Date().toISOString(), ...entry };\n await fs.appendFile(this.file(), `${JSON.stringify(full)}\\n`, { mode: 0o600 });\n }\n\n /** Most recent entries, newest last. Reads across all monthly files. */\n async read(limit = 50): Promise<AuditEntry[]> {\n let names: string[];\n try {\n names = (await fs.readdir(this.dir)).filter((n) => n.endsWith('.jsonl')).sort();\n } catch {\n return [];\n }\n const entries: AuditEntry[] = [];\n for (const name of names) {\n const raw = await fs.readFile(path.join(this.dir, name), 'utf8');\n for (const line of raw.split('\\n')) {\n if (line.trim()) entries.push(JSON.parse(line) as AuditEntry);\n }\n }\n return entries.slice(-limit);\n }\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { AdportError } from '../errors.js';\nimport type { AdProvider, WriteGuard, WriteOperation, WritePreview, WriteResult } from '../provider.js';\nimport { AuditLog } from './audit.js';\nimport { PendingStore } from './pending.js';\nimport type { Policy } from './policy.js';\n\nexport interface ValidationOutcome {\n pendingOperationId: string;\n preview: WritePreview;\n expiresAt: string;\n}\n\nexport interface ApplyOutcome {\n result: WriteResult;\n preview: WritePreview;\n}\n\nfunction canonicalize(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalize);\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => [k, canonicalize(v)]),\n );\n }\n return value;\n}\n\nexport function hashOperation(op: WriteOperation): string {\n const canonical = canonicalize({\n tool: op.tool,\n provider: op.provider,\n accountId: op.accountId,\n kind: op.kind,\n payload: op.payload,\n });\n return createHash('sha256').update(JSON.stringify(canonical)).digest('hex');\n}\n\n/**\n * The single gate for all mutations. Enforces the two-step contract:\n * validate() dry-runs the operation and issues a pending-operation id;\n * apply() only executes an operation whose id, hash, and expiry check out.\n */\nexport class PolicyEngine {\n constructor(\n readonly policy: Policy,\n private readonly pending: PendingStore = new PendingStore(),\n private readonly audit: AuditLog = new AuditLog(),\n ) {}\n\n guard(): WriteGuard {\n return { forcePausedCreation: this.policy.paused_creation };\n }\n\n async validate(provider: AdProvider, op: WriteOperation): Promise<ValidationOutcome> {\n await this.pending.sweep(); // opportunistic cleanup of expired entries\n await this.checkStaticPolicy(op);\n const preview = await provider.previewWrite(op, this.guard());\n await this.checkBudgetPolicy(op, preview);\n\n const id = randomUUID();\n const now = Date.now();\n const expiresAt = new Date(now + this.policy.pending_ttl_minutes * 60_000).toISOString();\n await this.pending.put({\n id,\n provider: provider.id,\n opHash: hashOperation(op),\n op,\n preview,\n createdAt: new Date(now).toISOString(),\n expiresAt,\n });\n await this.audit.append({\n event: 'validated',\n provider: provider.id,\n tool: op.tool,\n accountId: op.accountId,\n pendingId: id,\n summary: preview.summary,\n });\n return { pendingOperationId: id, preview, expiresAt };\n }\n\n async apply(provider: AdProvider, op: WriteOperation, pendingId: string): Promise<ApplyOutcome> {\n // No sweep here: an expired entry must still be readable so the caller\n // gets PENDING_EXPIRED (actionable) instead of PENDING_NOT_FOUND.\n const pending = await this.pending.get(pendingId);\n if (!pending) {\n throw new AdportError(\n 'PENDING_NOT_FOUND',\n `No pending operation \"${pendingId}\". Validate first: call the tool without pending_operation_id.`,\n );\n }\n if (Date.parse(pending.expiresAt) < Date.now()) {\n await this.pending.delete(pendingId);\n throw new AdportError(\n 'PENDING_EXPIRED',\n `Pending operation ${pendingId} expired at ${pending.expiresAt}. Validate again.`,\n );\n }\n if (pending.provider !== provider.id || pending.opHash !== hashOperation(op)) {\n throw new AdportError(\n 'PENDING_MISMATCH',\n 'The operation differs from what was validated. Re-validate with the exact arguments you intend to apply.',\n );\n }\n // Policy may have changed between validate and apply; re-check.\n await this.checkStaticPolicy(op);\n\n const result = await provider.applyWrite(op, this.guard());\n await this.audit.append({\n event: 'applied',\n provider: provider.id,\n tool: op.tool,\n accountId: op.accountId,\n pendingId,\n summary: pending.preview.summary,\n details: { resourceIds: result.resourceIds },\n });\n await this.pending.delete(pendingId);\n return { result, preview: pending.preview };\n }\n\n private async checkStaticPolicy(op: WriteOperation): Promise<void> {\n if (this.policy.protected_accounts.includes(op.accountId)) {\n await this.reject(op, `Account ${op.accountId} is protected by policy`);\n }\n }\n\n private async checkBudgetPolicy(op: WriteOperation, preview: WritePreview): Promise<void> {\n const pctCap = this.policy.max_budget_delta_pct;\n const absCap = this.policy.max_daily_budget_micros;\n for (const delta of preview.budgetDeltas) {\n if (absCap !== null && delta.toMicros > absCap) {\n await this.reject(\n op,\n `${delta.target}: ${delta.toMicros} micros exceeds the absolute budget cap (${absCap})`,\n );\n }\n if (pctCap !== null && delta.fromMicros !== undefined && delta.fromMicros > 0) {\n const pct = (Math.abs(delta.toMicros - delta.fromMicros) / delta.fromMicros) * 100;\n if (pct > pctCap) {\n await this.reject(\n op,\n `${delta.target}: ${pct.toFixed(1)}% change exceeds the ${pctCap}% budget-delta cap`,\n );\n }\n }\n }\n }\n\n private async reject(op: WriteOperation, reason: string): Promise<never> {\n await this.audit.append({\n event: 'rejected',\n provider: op.provider,\n tool: op.tool,\n accountId: op.accountId,\n summary: reason,\n });\n throw new AdportError('POLICY_VIOLATION', `Policy violation: ${reason}`, { policy: this.policy });\n }\n}\n","import { z } from 'zod';\nimport type { WriteKind, WriteOperation } from '../provider.js';\nimport { defineTool, type AnyToolDefinition } from './registry.js';\n\nconst TWO_STEP_NOTE =\n 'Two-step write: call WITHOUT pending_operation_id to get a dry-run preview and a pending_operation_id; ' +\n 'call again with IDENTICAL arguments plus that id to apply.';\n\n/**\n * Wrap a provider mutation as a two-step (validate → apply) tool.\n * This is the only sanctioned way to expose a write; the handler always goes\n * through the policy engine, so rails and audit logging cannot be skipped.\n */\nexport function guardedWriteTool<S extends z.ZodObject<z.ZodRawShape>>(def: {\n name: string;\n namespace: string;\n description: string;\n provider: string;\n kind: WriteKind;\n payload: S;\n destructive?: boolean;\n}): AnyToolDefinition {\n const input = def.payload.extend({\n account_id: z.string().min(1).describe('Target account id'),\n pending_operation_id: z\n .string()\n .optional()\n .describe('Omit to get a dry-run preview; pass the returned id to apply.'),\n });\n\n return defineTool({\n name: def.name,\n namespace: def.namespace,\n description: `${def.description}\\n\\n${TWO_STEP_NOTE}`,\n input,\n annotations: { readOnly: false, destructive: def.destructive ?? false },\n async handler(raw, ctx) {\n const { account_id, pending_operation_id, ...payload } = raw as Record<string, unknown> & {\n account_id: string;\n pending_operation_id?: string;\n };\n const provider = ctx.providers.get(def.provider);\n const op: WriteOperation = {\n tool: def.name,\n provider: def.provider,\n accountId: account_id,\n kind: def.kind,\n payload,\n };\n if (!pending_operation_id) {\n const outcome = await ctx.engine.validate(provider, op);\n return {\n status: 'pending_validation',\n applied: false,\n pending_operation_id: outcome.pendingOperationId,\n expires_at: outcome.expiresAt,\n preview: outcome.preview,\n next_step:\n 'Review the preview. To apply, call this tool again with the same arguments plus pending_operation_id.',\n };\n }\n const outcome = await ctx.engine.apply(provider, op, pending_operation_id);\n return { status: 'applied', applied: true, result: outcome.result, preview: outcome.preview };\n },\n });\n}\n","import { z } from 'zod';\nimport { DATE_PRESETS, ENTITY_LEVELS, METRICS, type NormalizedQuery, type ReportRow } from '../model.js';\nimport type { Account } from '../provider.js';\nimport { defineTool, type AnyToolDefinition } from './registry.js';\n\nconst dateRangeSchema = z.union([\n z.enum(DATE_PRESETS),\n z.object({\n start: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'YYYY-MM-DD'),\n end: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'YYYY-MM-DD'),\n }),\n]);\n\nexport function builtinTools(): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'accounts_list',\n namespace: 'core',\n description: 'List connected ad accounts across all providers (or one provider).',\n input: z.object({\n provider: z.string().optional().describe('Limit to one provider id, e.g. \"google\".'),\n }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const providers = input.provider ? [ctx.providers.get(input.provider)] : ctx.providers.list();\n const accounts: Account[] = [];\n for (const provider of providers) {\n accounts.push(...(await provider.listAccounts()));\n }\n return { accounts };\n },\n }),\n defineTool({\n name: 'report',\n namespace: 'core',\n description:\n 'Cross-platform performance report with normalized metrics (spend, clicks, conversions, ROAS, ...). ' +\n 'Rows are capped by `limit`; the response says when it truncated.',\n input: z.object({\n provider: z.string().optional().describe('Limit to one provider id.'),\n account_ids: z.array(z.string()).optional(),\n level: z.enum(ENTITY_LEVELS).default('campaign'),\n metrics: z.array(z.enum(METRICS)).min(1).default(['spend', 'impressions', 'clicks', 'conversions']),\n date_range: dateRangeSchema.default('last_7_days'),\n limit: z.number().int().positive().max(1000).default(100),\n }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const providers = input.provider ? [ctx.providers.get(input.provider)] : ctx.providers.list();\n const query: NormalizedQuery = {\n accountIds: input.account_ids,\n level: input.level,\n metrics: input.metrics,\n dateRange: input.date_range,\n limit: input.limit,\n };\n const rows: ReportRow[] = [];\n for (const provider of providers) {\n const report = await provider.report(query);\n rows.push(...report.rows);\n }\n const truncated = rows.length > input.limit;\n return { rows: rows.slice(0, input.limit), truncated };\n },\n }),\n ];\n}\n","import { z } from 'zod';\nimport { AdportError } from '../errors.js';\nimport {\n rangeDayCount,\n resolveDateRange,\n type MetricName,\n type NormalizedQuery,\n type Report,\n type ReportRow,\n} from '../model.js';\nimport type {\n Account,\n AdProvider,\n ProviderCapabilities,\n StandardActions,\n WriteGuard,\n WriteOperation,\n WritePreview,\n WriteResult,\n} from '../provider.js';\nimport { defineTool, type AnyToolDefinition } from '../tools/registry.js';\nimport { guardedWriteTool } from '../tools/write.js';\n\ninterface MockCampaign {\n id: string;\n name: string;\n status: 'ENABLED' | 'PAUSED' | 'REMOVED';\n dailyBudgetMicros: number;\n}\n\ninterface MockAccount extends Account {\n campaigns: MockCampaign[];\n}\n\nfunction seedAccounts(): MockAccount[] {\n return [\n {\n provider: 'mock',\n id: 'mock-1',\n name: 'Acme DTC Store',\n currency: 'EUR',\n status: 'ENABLED',\n campaigns: [\n { id: 'c1', name: 'Brand Search', status: 'ENABLED', dailyBudgetMicros: 10_000_000 },\n { id: 'c2', name: 'Prospecting', status: 'ENABLED', dailyBudgetMicros: 25_000_000 },\n // Deliberately conversion-less: exercises the audit harness.\n { id: 'c4', name: 'Legacy Retargeting', status: 'ENABLED', dailyBudgetMicros: 8_000_000 },\n ],\n },\n {\n provider: 'mock',\n id: 'mock-2',\n name: 'Beta App',\n currency: 'USD',\n status: 'ENABLED',\n campaigns: [{ id: 'c3', name: 'Install Campaign', status: 'PAUSED', dailyBudgetMicros: 5_000_000 }],\n },\n ];\n}\n\n/**\n * In-memory provider for tests, demos, and trying adport without credentials.\n * Deterministic: same inputs always produce the same report numbers.\n */\nexport class MockProvider implements AdProvider {\n readonly id = 'mock';\n private accounts: MockAccount[] = seedAccounts();\n\n capabilities(): ProviderCapabilities {\n return { serverDryRun: false };\n }\n\n standardActions(): StandardActions {\n return {\n pauseCampaign: (accountId, campaignId) => ({\n tool: 'mock_set_campaign_status',\n input: { account_id: accountId, campaign_id: campaignId, status: 'PAUSED' },\n }),\n };\n }\n\n async listAccounts(): Promise<Account[]> {\n return this.accounts.map(({ campaigns: _campaigns, ...account }) => account);\n }\n\n listCampaigns(accountId: string): MockCampaign[] {\n return [...this.account(accountId).campaigns];\n }\n\n async report(query: NormalizedQuery): Promise<Report> {\n const range = resolveDateRange(query.dateRange);\n const days = rangeDayCount(range);\n const rows: ReportRow[] = [];\n for (const account of this.accounts) {\n if (query.accountIds && !query.accountIds.includes(account.id)) continue;\n for (const [index, campaign] of account.campaigns.entries()) {\n if (campaign.status === 'REMOVED') continue;\n rows.push({\n provider: this.id,\n accountId: account.id,\n entity: { level: 'campaign', id: campaign.id, name: campaign.name, status: campaign.status },\n metrics: mockMetrics(query.metrics, index, days, campaign.dailyBudgetMicros, campaign.id === 'c4'),\n });\n }\n }\n return { rows };\n }\n\n async previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview> {\n return this.plan(op, guard).preview;\n }\n\n async applyWrite(op: WriteOperation, guard: WriteGuard): Promise<WriteResult> {\n return this.plan(op, guard).apply();\n }\n\n private account(accountId: string): MockAccount {\n const account = this.accounts.find((a) => a.id === accountId);\n if (!account) throw new AdportError('PROVIDER_ERROR', `mock: unknown account ${accountId}`);\n return account;\n }\n\n private campaign(accountId: string, campaignId: string): MockCampaign {\n const campaign = this.account(accountId).campaigns.find((c) => c.id === campaignId);\n if (!campaign) throw new AdportError('PROVIDER_ERROR', `mock: unknown campaign ${campaignId}`);\n return campaign;\n }\n\n /** Compute preview and applier together so dry-run and apply can never drift. */\n private plan(op: WriteOperation, guard: WriteGuard): { preview: WritePreview; apply: () => WriteResult } {\n const base = { coercions: [] as string[], budgetDeltas: [], serverValidated: false };\n switch (op.tool) {\n case 'mock_create_campaign': {\n const payload = op.payload as { name: string; daily_budget_micros: number; status?: string };\n let status = (payload.status ?? 'ENABLED') as MockCampaign['status'];\n const coercions: string[] = [];\n if (guard.forcePausedCreation && status === 'ENABLED') {\n status = 'PAUSED';\n coercions.push('status coerced to PAUSED by policy (paused_creation)');\n }\n const account = this.account(op.accountId);\n const id = `c${100 + account.campaigns.length}`;\n return {\n preview: {\n ...base,\n summary: `Create campaign \"${payload.name}\" (${status}) with daily budget ${payload.daily_budget_micros} micros`,\n changes: [`+ campaign ${id} \"${payload.name}\" status=${status}`],\n coercions,\n budgetDeltas: [{ target: `new campaign \"${payload.name}\" daily budget`, toMicros: payload.daily_budget_micros }],\n },\n apply: () => {\n account.campaigns.push({ id, name: payload.name, status, dailyBudgetMicros: payload.daily_budget_micros });\n return { applied: true, resourceIds: [id] };\n },\n };\n }\n case 'mock_set_budget': {\n const payload = op.payload as { campaign_id: string; daily_budget_micros: number };\n const campaign = this.campaign(op.accountId, payload.campaign_id);\n return {\n preview: {\n ...base,\n summary: `Change \"${campaign.name}\" daily budget ${campaign.dailyBudgetMicros} → ${payload.daily_budget_micros} micros`,\n changes: [`~ campaign ${campaign.id} daily_budget ${campaign.dailyBudgetMicros} → ${payload.daily_budget_micros}`],\n budgetDeltas: [\n {\n target: `campaign \"${campaign.name}\" daily budget`,\n fromMicros: campaign.dailyBudgetMicros,\n toMicros: payload.daily_budget_micros,\n },\n ],\n },\n apply: () => {\n campaign.dailyBudgetMicros = payload.daily_budget_micros;\n return { applied: true, resourceIds: [campaign.id] };\n },\n };\n }\n case 'mock_set_campaign_status': {\n const payload = op.payload as { campaign_id: string; status: 'ENABLED' | 'PAUSED' };\n const campaign = this.campaign(op.accountId, payload.campaign_id);\n return {\n preview: {\n ...base,\n summary: `Set \"${campaign.name}\" status ${campaign.status} → ${payload.status}`,\n changes: [`~ campaign ${campaign.id} status ${campaign.status} → ${payload.status}`],\n },\n apply: () => {\n campaign.status = payload.status;\n return { applied: true, resourceIds: [campaign.id] };\n },\n };\n }\n case 'mock_remove_campaign': {\n const payload = op.payload as { campaign_id: string };\n const campaign = this.campaign(op.accountId, payload.campaign_id);\n return {\n preview: {\n ...base,\n summary: `PERMANENTLY remove campaign \"${campaign.name}\"`,\n changes: [`- campaign ${campaign.id} \"${campaign.name}\"`],\n },\n apply: () => {\n campaign.status = 'REMOVED';\n return { applied: true, resourceIds: [campaign.id] };\n },\n };\n }\n default:\n throw new AdportError('PROVIDER_ERROR', `mock: unsupported write tool ${op.tool}`);\n }\n }\n}\n\nfunction mockMetrics(\n requested: MetricName[],\n seed: number,\n days: number,\n dailyBudgetMicros: number,\n zeroConversions = false,\n): Partial<Record<MetricName, number>> {\n const spend = ((dailyBudgetMicros / 1_000_000) * 0.83 + seed) * days;\n const impressions = (2_000 + seed * 700) * days;\n const clicks = (90 + seed * 35) * days;\n const conversions = zeroConversions ? 0 : (4 + seed) * days;\n const conversionValue = conversions * (35 + seed * 5);\n const all: Record<MetricName, number> = {\n spend: round2(spend),\n impressions,\n clicks,\n conversions,\n conversion_value: round2(conversionValue),\n ctr: round2((clicks / impressions) * 100),\n cpc: round2(spend / clicks),\n cpm: round2((spend / impressions) * 1000),\n cpa: conversions > 0 ? round2(spend / conversions) : 0,\n roas: spend > 0 ? round2(conversionValue / spend) : 0,\n };\n return Object.fromEntries(requested.map((m) => [m, all[m]]));\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nexport function mockTools(): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'mock_list_campaigns',\n namespace: 'mock',\n description: 'List campaigns in a mock account (id, name, status, daily budget).',\n input: z.object({ account_id: z.string() }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const provider = ctx.providers.get('mock') as MockProvider;\n return { campaigns: provider.listCampaigns(input.account_id) };\n },\n }),\n guardedWriteTool({\n name: 'mock_create_campaign',\n namespace: 'mock',\n description: 'Create a campaign in the mock account.',\n provider: 'mock',\n kind: 'create',\n payload: z.object({\n name: z.string().min(1),\n daily_budget_micros: z.number().int().positive(),\n status: z.enum(['ENABLED', 'PAUSED']).optional(),\n }),\n }),\n guardedWriteTool({\n name: 'mock_set_budget',\n namespace: 'mock',\n description: 'Change a mock campaign daily budget.',\n provider: 'mock',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), daily_budget_micros: z.number().int().positive() }),\n }),\n guardedWriteTool({\n name: 'mock_set_campaign_status',\n namespace: 'mock',\n description: 'Enable or pause a mock campaign.',\n provider: 'mock',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), status: z.enum(['ENABLED', 'PAUSED']) }),\n }),\n guardedWriteTool({\n name: 'mock_remove_campaign',\n namespace: 'mock',\n description: 'Permanently remove a mock campaign.',\n provider: 'mock',\n kind: 'remove',\n destructive: true,\n payload: z.object({ campaign_id: z.string() }),\n }),\n ];\n}\n","import { auditTools } from './audit/tools.js';\nimport { CredentialStore } from './credentials/store.js';\nimport { PolicyEngine } from './policy/engine.js';\nimport { loadPolicy } from './policy/policy.js';\nimport { ProviderRegistry, type AdProvider } from './provider.js';\nimport { builtinTools } from './tools/builtin.js';\nimport { ToolRegistry, type AnyToolDefinition, type ToolContext } from './tools/registry.js';\nimport { MockProvider, mockTools } from './testing/mock-provider.js';\n\nexport interface ProviderModule {\n provider: AdProvider;\n tools: AnyToolDefinition[];\n}\n\nexport interface CreateContextOptions {\n policyPath?: string;\n /** Extra providers with their tools (e.g. the Google provider from @adport/provider-google). */\n providerModules?: ProviderModule[];\n /**\n * Include the credential-free mock provider. Defaults to true when no real\n * provider module is passed, so a fresh install always has something to try.\n */\n includeMock?: boolean;\n}\n\nexport interface AdportRuntime {\n ctx: ToolContext;\n registry: ToolRegistry;\n policySource: string;\n}\n\nexport async function createContext(options: CreateContextOptions = {}): Promise<AdportRuntime> {\n const modules = options.providerModules ?? [];\n const includeMock = options.includeMock ?? modules.length === 0;\n\n const providers = new ProviderRegistry();\n const { policy, source } = await loadPolicy(options.policyPath);\n const engine = new PolicyEngine(policy);\n const credentials = new CredentialStore();\n\n const registry = new ToolRegistry();\n registry.register(builtinTools());\n registry.register(auditTools());\n\n for (const module of modules) {\n providers.register(module.provider);\n registry.register(module.tools);\n }\n if (includeMock) {\n providers.register(new MockProvider());\n registry.register(mockTools());\n }\n\n const ctx: ToolContext = { providers, engine, credentials };\n ctx.registry = registry;\n return { ctx, registry, policySource: source };\n}\n"],"mappings":"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","names":["path","path","fs","path","path","fs","fs","path","z","z","path","fs","fs","path","path","fs","fs","path","path","fs","z","z","outcome","z","dateRangeSchema","z","z","z"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/paths.ts","../src/model.ts","../src/provider.ts","../src/audit/packs/core-performance.ts","../src/audit/store.ts","../src/audit/runner.ts","../src/audit/tools.ts","../src/tools/registry.ts","../src/credentials/store.ts","../src/policy/policy.ts","../src/policy/pending.ts","../src/policy/audit.ts","../src/policy/engine.ts","../src/tools/write.ts","../src/tools/builtin.ts","../src/testing/mock-provider.ts","../src/context.ts"],"sourcesContent":["export type AdportErrorCode =\n | 'POLICY_VIOLATION'\n | 'PENDING_NOT_FOUND'\n | 'PENDING_EXPIRED'\n | 'PENDING_MISMATCH'\n | 'PROVIDER_ERROR'\n | 'INVALID_INPUT'\n | 'NOT_CONNECTED'\n | 'UNKNOWN_TOOL';\n\nexport class AdportError extends Error {\n constructor(\n public readonly code: AdportErrorCode,\n message: string,\n public readonly details?: unknown,\n ) {\n super(message);\n this.name = 'AdportError';\n }\n\n toJSON() {\n return { error: this.code, message: this.message, details: this.details };\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\n/**\n * All adport state (credentials, pending operations, audit log, policy) lives\n * under this directory. ADPORT_HOME overrides it — used by tests and CI.\n */\nexport function adportHome(): string {\n return process.env.ADPORT_HOME ?? path.join(os.homedir(), '.config', 'adport');\n}\n","export const METRICS = [\n 'spend',\n 'impressions',\n 'clicks',\n 'conversions',\n 'conversion_value',\n 'ctr',\n 'cpc',\n 'cpm',\n 'cpa',\n 'roas',\n] as const;\nexport type MetricName = (typeof METRICS)[number];\n\nexport const ENTITY_LEVELS = ['account', 'campaign', 'ad_group', 'ad'] as const;\nexport type EntityLevel = (typeof ENTITY_LEVELS)[number];\n\nexport const DATE_PRESETS = ['today', 'yesterday', 'last_7_days', 'last_30_days', 'this_month'] as const;\nexport type DatePreset = (typeof DATE_PRESETS)[number];\n\n/** ISO dates, inclusive on both ends. */\nexport interface DateRange {\n start: string;\n end: string;\n}\n\nexport interface NormalizedQuery {\n /** Provider ids to query; omit for all connected providers. */\n providers?: string[];\n /** Account ids to include; omit for all accounts of the selected providers. */\n accountIds?: string[];\n level: EntityLevel;\n metrics: MetricName[];\n dateRange: DateRange | DatePreset;\n limit?: number;\n}\n\nexport interface ReportRow {\n provider: string;\n accountId: string;\n entity: { level: EntityLevel; id: string; name: string; status?: string };\n metrics: Partial<Record<MetricName, number>>;\n}\n\nexport interface Report {\n rows: ReportRow[];\n truncated?: boolean;\n}\n\nfunction iso(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\nexport function resolveDateRange(range: DateRange | DatePreset, now = new Date()): DateRange {\n if (typeof range !== 'string') return range;\n const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));\n const daysAgo = (n: number) => new Date(today.getTime() - n * 86_400_000);\n switch (range) {\n case 'today':\n return { start: iso(today), end: iso(today) };\n case 'yesterday':\n return { start: iso(daysAgo(1)), end: iso(daysAgo(1)) };\n case 'last_7_days':\n return { start: iso(daysAgo(7)), end: iso(daysAgo(1)) };\n case 'last_30_days':\n return { start: iso(daysAgo(30)), end: iso(daysAgo(1)) };\n case 'this_month':\n return { start: iso(new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))), end: iso(today) };\n }\n}\n\nexport function rangeDayCount(range: DateRange): number {\n const start = Date.parse(`${range.start}T00:00:00Z`);\n const end = Date.parse(`${range.end}T00:00:00Z`);\n return Math.max(1, Math.round((end - start) / 86_400_000) + 1);\n}\n","import { AdportError } from './errors.js';\nimport type { NormalizedQuery, Report } from './model.js';\n\nexport interface Account {\n provider: string;\n id: string;\n name: string;\n currency?: string;\n status?: string;\n}\n\nexport type WriteKind = 'create' | 'update' | 'remove';\n\nexport interface WriteOperation {\n /** Tool name that produced this operation — part of the audit trail. */\n tool: string;\n provider: string;\n accountId: string;\n kind: WriteKind;\n payload: Record<string, unknown>;\n}\n\nexport interface BudgetDelta {\n /** Human-readable target, e.g. \"campaign c1 daily budget\". */\n target: string;\n fromMicros?: number;\n toMicros: number;\n}\n\nexport interface WritePreview {\n summary: string;\n changes: string[];\n /** Adjustments the guard forced (e.g. \"status coerced to PAUSED\"). Never silent. */\n coercions: string[];\n budgetDeltas: BudgetDelta[];\n /** True when the platform validated the operation server-side (dry run). */\n serverValidated: boolean;\n}\n\nexport interface WriteResult {\n applied: true;\n resourceIds: string[];\n details?: unknown;\n}\n\n/** Policy-derived constraints handed to providers on every preview/apply. */\nexport interface WriteGuard {\n forcePausedCreation: boolean;\n}\n\nexport interface ProviderCapabilities {\n serverDryRun: boolean;\n}\n\n/** A ready-to-call tool invocation (flows through the normal validate→apply gate). */\nexport interface StandardAction {\n tool: string;\n input: Record<string, unknown>;\n}\n\n/**\n * Provider-declared mappings for cross-platform actions the audit harness can\n * propose (each provider knows its own tool names and native status values).\n */\nexport interface StandardActions {\n pauseCampaign?: (accountId: string, campaignId: string) => StandardAction;\n}\n\nexport interface AdProvider {\n readonly id: string;\n capabilities(): ProviderCapabilities;\n listAccounts(): Promise<Account[]>;\n report(query: NormalizedQuery): Promise<Report>;\n /** Dry-run the operation (server-side where supported, client-side diff otherwise). */\n previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview>;\n /** Execute the operation for real. Only the policy engine may call this. */\n applyWrite(op: WriteOperation, guard: WriteGuard): Promise<WriteResult>;\n /** Optional cross-platform action mappings used by the recommendation harness. */\n standardActions?(): StandardActions;\n}\n\nexport class ProviderRegistry {\n private providers = new Map<string, AdProvider>();\n\n register(provider: AdProvider): void {\n this.providers.set(provider.id, provider);\n }\n\n get(id: string): AdProvider {\n const provider = this.providers.get(id);\n if (!provider) {\n throw new AdportError(\n 'NOT_CONNECTED',\n `Provider \"${id}\" is not connected. Run \\`adport connect ${id}\\` first.`,\n );\n }\n return provider;\n }\n\n list(): AdProvider[] {\n return [...this.providers.values()];\n }\n}\n\n/** Select providers for a read operation and fail clearly when none exist. */\nexport function selectConnectedProviders(registry: ProviderRegistry, providerId?: string): AdProvider[] {\n if (providerId) return [registry.get(providerId)];\n const providers = registry.list();\n if (providers.length === 0) {\n throw new AdportError(\n 'NOT_CONNECTED',\n 'No ad providers are connected. Run `adport connect <provider>` first, configure provider environment variables, or use `--demo` for synthetic mock data.',\n );\n }\n return providers;\n}\n","import type { Rule, RulePack } from '../types.js';\n\n/** Active unless the status clearly says otherwise (provider vocabularies differ). */\nfunction isActive(status?: string): boolean {\n return !/(PAUS|DISABLE|REMOV|DELET|CLOS|ARCHIV)/i.test(status ?? 'ENABLED');\n}\n\nconst zeroConversionSpend: Rule = {\n id: 'zero-conversion-spend',\n title: 'Active campaign spending with zero conversions',\n description: 'Flags campaigns that spent above the threshold over the range without a single tracked conversion.',\n evaluate(ctx) {\n const minSpend = ctx.config.zero_conversion_min_spend!;\n return ctx.rows\n .filter((row) => isActive(row.entity.status))\n .filter((row) => (row.metrics.spend ?? 0) >= minSpend && (row.metrics.conversions ?? 0) === 0)\n .map((row) => ({\n entity: row.entity,\n severity: (row.metrics.spend ?? 0) >= minSpend * 3 ? ('critical' as const) : ('warn' as const),\n title: `\"${row.entity.name}\" spent ${row.metrics.spend} with 0 conversions`,\n detail:\n `Campaign ${row.entity.id} spent ${row.metrics.spend} between ${ctx.range.start} and ${ctx.range.end} ` +\n 'without any tracked conversion. Either conversion tracking is broken or the spend is wasted.',\n recommendation:\n 'Verify conversion tracking first; if tracking is correct, pause the campaign and rework targeting/creative.',\n proposedAction: ctx.actions.pauseCampaign?.(ctx.accountId, row.entity.id),\n metrics: row.metrics,\n }));\n },\n};\n\nconst lowCtr: Rule = {\n id: 'low-ctr',\n title: 'High impressions with very low CTR',\n description: 'Flags campaigns whose creative/targeting is not resonating (lots of impressions, few clicks).',\n evaluate(ctx) {\n const minImpressions = ctx.config.low_ctr_min_impressions!;\n const threshold = ctx.config.low_ctr_threshold_pct!;\n return ctx.rows\n .filter((row) => isActive(row.entity.status))\n .filter((row) => (row.metrics.impressions ?? 0) >= minImpressions && (row.metrics.ctr ?? 100) < threshold)\n .map((row) => ({\n entity: row.entity,\n severity: 'warn' as const,\n title: `\"${row.entity.name}\" CTR ${row.metrics.ctr}% over ${row.metrics.impressions} impressions`,\n detail: `CTR is below ${threshold}% despite meaningful reach — the ad or audience likely needs work.`,\n recommendation: 'Review creative and audience targeting; test new headlines/assets before touching budgets.',\n metrics: row.metrics,\n }));\n },\n};\n\nconst cpaOutlier: Rule = {\n id: 'cpa-outlier',\n title: 'Campaign CPA far above account median',\n description: 'Flags converting campaigns whose cost per conversion is a large multiple of the account median.',\n evaluate(ctx) {\n const multiplier = ctx.config.cpa_outlier_multiplier!;\n const converting = ctx.rows.filter((row) => (row.metrics.conversions ?? 0) > 0 && (row.metrics.cpa ?? 0) > 0);\n if (converting.length < 3) return [];\n const cpas = converting.map((row) => row.metrics.cpa!).sort((a, b) => a - b);\n const median = cpas[Math.floor(cpas.length / 2)]!;\n return converting\n .filter((row) => row.metrics.cpa! > median * multiplier)\n .map((row) => ({\n entity: row.entity,\n severity: 'warn' as const,\n title: `\"${row.entity.name}\" CPA ${row.metrics.cpa} vs account median ${median}`,\n detail: `Cost per conversion is more than ${multiplier}× the account median over the range.`,\n recommendation: 'Shift budget toward lower-CPA campaigns, or tighten targeting/bids here.',\n metrics: row.metrics,\n }));\n },\n};\n\nconst negativeRoas: Rule = {\n id: 'negative-roas',\n title: 'Campaign returning less than it spends',\n description: 'Flags campaigns with tracked revenue whose ROAS is below break-even.',\n evaluate(ctx) {\n const minSpend = ctx.config.roas_min_spend!;\n return ctx.rows\n .filter((row) => isActive(row.entity.status))\n .filter(\n (row) =>\n (row.metrics.spend ?? 0) >= minSpend &&\n (row.metrics.conversion_value ?? 0) > 0 &&\n (row.metrics.roas ?? 0) < 1,\n )\n .map((row) => ({\n entity: row.entity,\n severity: 'warn' as const,\n title: `\"${row.entity.name}\" ROAS ${row.metrics.roas} (below break-even)`,\n detail: `Spent ${row.metrics.spend} for ${row.metrics.conversion_value} in tracked revenue over the range.`,\n recommendation: 'Check margins and attribution windows; consider bid/budget reduction or audience changes.',\n metrics: row.metrics,\n }));\n },\n};\n\nexport const corePerformancePack: RulePack = {\n name: 'core-performance',\n version: '0.1.0',\n rules: [zeroConversionSpend, lowCtr, cpaOutlier, negativeRoas],\n defaults: {\n zero_conversion_min_spend: 50,\n low_ctr_min_impressions: 5000,\n low_ctr_threshold_pct: 0.5,\n cpa_outlier_multiplier: 2.5,\n roas_min_spend: 50,\n },\n};\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\nimport type { AuditFinding, FindingStatus } from './types.js';\n\n/**\n * Findings persist on disk with their approval lifecycle — the durable side of\n * the recommendation harness: a recommendation can wait for a human decision\n * across restarts, indefinitely, at zero cost.\n */\nexport class FindingsStore {\n constructor(private readonly dir: string = path.join(adportHome(), 'findings')) {}\n\n private file(id: string): string {\n return path.join(this.dir, `${id.replace(/[^a-zA-Z0-9_.:-]/g, '_')}.json`);\n }\n\n async list(filter: { status?: FindingStatus; provider?: string } = {}): Promise<AuditFinding[]> {\n let names: string[];\n try {\n names = await fs.readdir(this.dir);\n } catch {\n return [];\n }\n const findings: AuditFinding[] = [];\n for (const name of names) {\n if (!name.endsWith('.json')) continue;\n const finding = JSON.parse(await fs.readFile(path.join(this.dir, name), 'utf8')) as AuditFinding;\n if (filter.status && finding.status !== filter.status) continue;\n if (filter.provider && finding.provider !== filter.provider) continue;\n findings.push(finding);\n }\n const order: Record<string, number> = { critical: 0, warn: 1, info: 2 };\n return findings.sort((a, b) => (order[a.severity] ?? 3) - (order[b.severity] ?? 3));\n }\n\n async get(id: string): Promise<AuditFinding | undefined> {\n try {\n return JSON.parse(await fs.readFile(this.file(id), 'utf8')) as AuditFinding;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n }\n\n async save(finding: AuditFinding): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await fs.writeFile(this.file(finding.id), JSON.stringify(finding, null, 2), { mode: 0o600 });\n }\n\n async setStatus(id: string, status: FindingStatus): Promise<AuditFinding> {\n const finding = await this.get(id);\n if (!finding) throw new Error(`Finding not found: ${id}`);\n const updated = { ...finding, status, updatedAt: new Date().toISOString() };\n await this.save(updated);\n return updated;\n }\n}\n","import { resolveDateRange, type DatePreset, type DateRange, type ReportRow } from '../model.js';\nimport { selectConnectedProviders, type ProviderRegistry } from '../provider.js';\nimport { corePerformancePack } from './packs/core-performance.js';\nimport { FindingsStore } from './store.js';\nimport type { AuditFinding, RulePack } from './types.js';\n\nexport interface AuditRunOptions {\n provider?: string;\n accountIds?: string[];\n dateRange?: DateRange | DatePreset;\n packs?: RulePack[];\n configOverrides?: Record<string, number>;\n}\n\nexport interface AuditRunResult {\n findings: AuditFinding[];\n counts: { critical: number; warn: number; info: number };\n evaluatedAccounts: number;\n range: DateRange;\n}\n\n/**\n * The audit engine (OPA pattern): providers supply normalized state as input,\n * rule packs supply the checks, the runner evaluates and returns structured\n * findings. Rules never call provider APIs directly.\n */\nexport class AuditRunner {\n constructor(\n private readonly providers: ProviderRegistry,\n private readonly store: FindingsStore = new FindingsStore(),\n ) {}\n\n async run(options: AuditRunOptions = {}): Promise<AuditRunResult> {\n const range = resolveDateRange(options.dateRange ?? 'last_30_days');\n const packs = options.packs ?? [corePerformancePack];\n const providers = selectConnectedProviders(this.providers, options.provider);\n\n const findings: AuditFinding[] = [];\n let evaluatedAccounts = 0;\n\n for (const provider of providers) {\n const report = await provider.report({\n accountIds: options.accountIds,\n level: 'campaign',\n metrics: ['spend', 'impressions', 'clicks', 'conversions', 'conversion_value', 'ctr', 'cpc', 'cpa', 'roas'],\n dateRange: range,\n limit: 1000,\n });\n const byAccount = new Map<string, ReportRow[]>();\n for (const row of report.rows) {\n const rows = byAccount.get(row.accountId) ?? [];\n rows.push(row);\n byAccount.set(row.accountId, rows);\n }\n const actions = provider.standardActions?.() ?? {};\n\n for (const [accountId, rows] of byAccount) {\n evaluatedAccounts += 1;\n for (const pack of packs) {\n const config = { ...pack.defaults, ...options.configOverrides };\n for (const rule of pack.rules) {\n for (const ruleFinding of rule.evaluate({ provider: provider.id, accountId, rows, range, actions, config })) {\n const id = `${rule.id}:${provider.id}:${accountId}:${ruleFinding.entity.id}`;\n const existing = await this.store.get(id);\n // Respect earlier human decisions: don't reopen dismissed/applied findings.\n if (existing && existing.status !== 'open') continue;\n const now = new Date().toISOString();\n const finding: AuditFinding = {\n id,\n ruleId: rule.id,\n severity: ruleFinding.severity,\n provider: provider.id,\n accountId,\n entity: ruleFinding.entity,\n title: ruleFinding.title,\n detail: ruleFinding.detail,\n recommendation: ruleFinding.recommendation,\n proposedAction: ruleFinding.proposedAction,\n metrics: ruleFinding.metrics,\n dateRange: range,\n status: 'open',\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n };\n await this.store.save(finding);\n findings.push(finding);\n }\n }\n }\n }\n }\n\n return {\n findings,\n counts: {\n critical: findings.filter((f) => f.severity === 'critical').length,\n warn: findings.filter((f) => f.severity === 'warn').length,\n info: findings.filter((f) => f.severity === 'info').length,\n },\n evaluatedAccounts,\n range,\n };\n }\n}\n","import { z } from 'zod';\nimport { AdportError } from '../errors.js';\nimport { DATE_PRESETS } from '../model.js';\nimport { defineTool, type AnyToolDefinition } from '../tools/registry.js';\nimport { AuditRunner } from './runner.js';\nimport { FindingsStore } from './store.js';\n\nconst dateRangeSchema = z.union([\n z.enum(DATE_PRESETS),\n z.object({\n start: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n end: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/),\n }),\n]);\n\nexport function auditTools(): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'audit_run',\n namespace: 'audit',\n description:\n 'Run the cross-platform audit rule packs over connected accounts (campaign level). ' +\n 'Returns structured findings with recommendations; some carry a ready-to-apply proposed action. ' +\n 'Reads ad data only — never mutates anything.',\n input: z.object({\n provider: z.string().optional(),\n account_ids: z.array(z.string()).optional(),\n date_range: dateRangeSchema.default('last_30_days'),\n }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const runner = new AuditRunner(ctx.providers);\n const result = await runner.run({\n provider: input.provider,\n accountIds: input.account_ids,\n dateRange: input.date_range,\n });\n return result;\n },\n }),\n defineTool({\n name: 'recommendations_list',\n namespace: 'audit',\n description: 'List persisted audit findings/recommendations (default: open ones), most severe first.',\n input: z.object({\n status: z.enum(['open', 'dismissed', 'applied']).default('open'),\n provider: z.string().optional(),\n }),\n annotations: { readOnly: true },\n async handler(input) {\n const findings = await new FindingsStore().list(input);\n return { findings, count: findings.length };\n },\n }),\n defineTool({\n name: 'recommendation_dismiss',\n namespace: 'audit',\n description: 'Dismiss a finding (it will not be re-opened by future audit runs).',\n input: z.object({ finding_id: z.string() }),\n annotations: { readOnly: false },\n async handler(input) {\n const finding = await new FindingsStore().setStatus(input.finding_id, 'dismissed');\n return { finding };\n },\n }),\n defineTool({\n name: 'recommendation_apply',\n namespace: 'audit',\n description:\n \"Execute a finding's proposed action through the normal two-step write flow: first call returns the dry-run \" +\n 'preview and pending_operation_id; second call (with the id) applies and marks the finding applied.',\n input: z.object({\n finding_id: z.string(),\n pending_operation_id: z.string().optional(),\n }),\n annotations: { readOnly: false },\n async handler(input, ctx) {\n if (!ctx.registry) {\n throw new AdportError('PROVIDER_ERROR', 'recommendation_apply requires a tool registry in context');\n }\n const store = new FindingsStore();\n const finding = await store.get(input.finding_id);\n if (!finding) throw new AdportError('INVALID_INPUT', `Finding not found: ${input.finding_id}`);\n if (finding.status !== 'open') {\n throw new AdportError('INVALID_INPUT', `Finding ${input.finding_id} is ${finding.status}, not open`);\n }\n if (!finding.proposedAction) {\n throw new AdportError(\n 'INVALID_INPUT',\n `Finding ${input.finding_id} has no proposed action — it needs human judgment (${finding.recommendation})`,\n );\n }\n const result = (await ctx.registry.call(\n finding.proposedAction.tool,\n {\n ...finding.proposedAction.input,\n ...(input.pending_operation_id ? { pending_operation_id: input.pending_operation_id } : {}),\n },\n ctx,\n )) as { status?: string };\n if (result.status === 'applied') {\n await store.setStatus(finding.id, 'applied');\n }\n return { finding_id: finding.id, action: finding.proposedAction, result };\n },\n }),\n ];\n}\n","import { z } from 'zod';\nimport type { CredentialStore } from '../credentials/store.js';\nimport { AdportError } from '../errors.js';\nimport type { PolicyEngine } from '../policy/engine.js';\nimport type { ProviderRegistry } from '../provider.js';\n\nexport interface ToolAnnotations {\n readOnly?: boolean;\n destructive?: boolean;\n}\n\nexport interface ToolContext {\n providers: ProviderRegistry;\n engine: PolicyEngine;\n credentials: CredentialStore;\n /** Set by createContext; lets tools invoke other tools (e.g. recommendation_apply). */\n registry?: ToolRegistry;\n}\n\nexport interface AnyToolDefinition {\n name: string;\n /** Grouping key used for config-based enable/disable (\"core\", \"mock\", \"google\", ...). */\n namespace: string;\n description: string;\n input: z.ZodObject<z.ZodRawShape>;\n annotations: ToolAnnotations;\n handler: (input: never, ctx: ToolContext) => Promise<unknown>;\n}\n\nexport function defineTool<S extends z.ZodObject<z.ZodRawShape>>(def: {\n name: string;\n namespace: string;\n description: string;\n input: S;\n annotations?: ToolAnnotations;\n handler: (input: z.infer<S>, ctx: ToolContext) => Promise<unknown>;\n}): AnyToolDefinition {\n return {\n ...def,\n annotations: def.annotations ?? { readOnly: false },\n } as AnyToolDefinition;\n}\n\nexport class ToolRegistry {\n private tools = new Map<string, AnyToolDefinition>();\n\n register(tools: AnyToolDefinition | AnyToolDefinition[]): void {\n for (const tool of Array.isArray(tools) ? tools : [tools]) {\n if (this.tools.has(tool.name)) {\n throw new Error(`Tool \"${tool.name}\" is already registered`);\n }\n this.tools.set(tool.name, tool);\n }\n }\n\n list(): AnyToolDefinition[] {\n return [...this.tools.values()];\n }\n\n get(name: string): AnyToolDefinition {\n const tool = this.tools.get(name);\n if (!tool) throw new AdportError('UNKNOWN_TOOL', `Unknown tool: ${name}`);\n return tool;\n }\n\n async call(name: string, rawInput: unknown, ctx: ToolContext): Promise<unknown> {\n const tool = this.get(name);\n const parsed = tool.input.safeParse(rawInput ?? {});\n if (!parsed.success) {\n throw new AdportError('INVALID_INPUT', `Invalid input for ${name}`, parsed.error.issues);\n }\n return tool.handler(parsed.data as never, ctx);\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\n\nexport type CredentialSource = 'byo' | 'broker';\n\nexport interface CredentialRecord {\n provider: string;\n source: CredentialSource;\n /** Provider-specific key/value secrets (tokens, client ids, ...). */\n data: Record<string, string>;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface CredentialFile {\n version: 1;\n credentials: Record<string, CredentialRecord>;\n}\n\nconst EMPTY: CredentialFile = { version: 1, credentials: {} };\n\n/**\n * File-backed credential store: ${ADPORT_HOME}/credentials.json, chmod 600.\n * OS keychain support may come later; the interface is deliberately async.\n */\nexport class CredentialStore {\n constructor(private readonly dir: string = adportHome()) {}\n\n private file(): string {\n return path.join(this.dir, 'credentials.json');\n }\n\n private async read(): Promise<CredentialFile> {\n try {\n const raw = await fs.readFile(this.file(), 'utf8');\n return JSON.parse(raw) as CredentialFile;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return structuredClone(EMPTY);\n throw err;\n }\n }\n\n private async write(data: CredentialFile): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await fs.writeFile(this.file(), `${JSON.stringify(data, null, 2)}\\n`, { mode: 0o600 });\n await fs.chmod(this.file(), 0o600);\n }\n\n async get(provider: string): Promise<CredentialRecord | undefined> {\n const file = await this.read();\n return file.credentials[provider];\n }\n\n async list(): Promise<CredentialRecord[]> {\n const file = await this.read();\n return Object.values(file.credentials);\n }\n\n async set(record: Omit<CredentialRecord, 'createdAt' | 'updatedAt'>): Promise<CredentialRecord> {\n const file = await this.read();\n const now = new Date().toISOString();\n const existing = file.credentials[record.provider];\n const full: CredentialRecord = { ...record, createdAt: existing?.createdAt ?? now, updatedAt: now };\n file.credentials[record.provider] = full;\n await this.write(file);\n return full;\n }\n\n async delete(provider: string): Promise<boolean> {\n const file = await this.read();\n if (!(provider in file.credentials)) return false;\n delete file.credentials[provider];\n await this.write(file);\n return true;\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { z } from 'zod';\nimport { adportHome } from '../paths.js';\n\nexport const policySchema = z.object({\n /** Writes must be validated (dry-run) before they can be applied. */\n require_validation: z.boolean().default(true),\n /** Created campaigns/ad groups/ads are coerced to PAUSED. */\n paused_creation: z.boolean().default(true),\n /** Reject budget changes exceeding this percentage of the current value. null = no cap. */\n max_budget_delta_pct: z.number().positive().nullable().default(25),\n /** Reject any budget set above this absolute value (micros). null = no cap. */\n max_daily_budget_micros: z.number().positive().nullable().default(null),\n /** Account ids that no write may touch. */\n protected_accounts: z.array(z.string()).default([]),\n /** How long a validated pending operation stays applicable. */\n pending_ttl_minutes: z.number().positive().default(15),\n});\n\nexport type Policy = z.infer<typeof policySchema>;\n\nexport const DEFAULT_POLICY: Policy = policySchema.parse({});\n\nexport interface LoadedPolicy {\n policy: Policy;\n /** Where the policy came from: a file path or \"defaults\". */\n source: string;\n}\n\n/**\n * Resolution order: explicit path → $ADPORT_POLICY → ./adport.policy.yaml →\n * ${ADPORT_HOME}/policy.yaml → built-in defaults.\n * A file that exists but fails validation is a hard error — never silently\n * fall back to weaker rails.\n */\nexport async function loadPolicy(explicitPath?: string): Promise<LoadedPolicy> {\n const candidates = [\n explicitPath,\n process.env.ADPORT_POLICY,\n path.join(process.cwd(), 'adport.policy.yaml'),\n path.join(adportHome(), 'policy.yaml'),\n ].filter((p): p is string => Boolean(p));\n\n for (const candidate of candidates) {\n let raw: string;\n try {\n raw = await fs.readFile(candidate, 'utf8');\n } catch {\n if (candidate === explicitPath || candidate === process.env.ADPORT_POLICY) {\n throw new Error(`Policy file not found: ${candidate}`);\n }\n continue;\n }\n const parsed = policySchema.safeParse(YAML.parse(raw) ?? {});\n if (!parsed.success) {\n throw new Error(`Invalid policy file ${candidate}: ${parsed.error.message}`);\n }\n return { policy: parsed.data, source: candidate };\n }\n return { policy: DEFAULT_POLICY, source: 'defaults' };\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\nimport type { WriteOperation, WritePreview } from '../provider.js';\n\nexport interface PendingOperation {\n id: string;\n provider: string;\n opHash: string;\n op: WriteOperation;\n preview: WritePreview;\n createdAt: string;\n expiresAt: string;\n}\n\n/**\n * File-backed store so validate and apply can happen in different processes\n * (CLI invocations, MCP server restarts).\n */\nexport class PendingStore {\n constructor(private readonly dir: string = path.join(adportHome(), 'pending')) {}\n\n private file(id: string): string {\n if (!/^[a-zA-Z0-9-]+$/.test(id)) throw new Error(`Invalid pending operation id: ${id}`);\n return path.join(this.dir, `${id}.json`);\n }\n\n async put(op: PendingOperation): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n await fs.writeFile(this.file(op.id), JSON.stringify(op, null, 2), { mode: 0o600 });\n }\n\n async get(id: string): Promise<PendingOperation | undefined> {\n try {\n return JSON.parse(await fs.readFile(this.file(id), 'utf8')) as PendingOperation;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n }\n\n async delete(id: string): Promise<void> {\n await fs.rm(this.file(id), { force: true });\n }\n\n /** Remove expired entries. Called opportunistically; never throws on races. */\n async sweep(now = new Date()): Promise<void> {\n let names: string[];\n try {\n names = await fs.readdir(this.dir);\n } catch {\n return;\n }\n for (const name of names) {\n if (!name.endsWith('.json')) continue;\n try {\n const op = JSON.parse(await fs.readFile(path.join(this.dir, name), 'utf8')) as PendingOperation;\n if (Date.parse(op.expiresAt) < now.getTime()) {\n await fs.rm(path.join(this.dir, name), { force: true });\n }\n } catch {\n // Unreadable entry: leave it; get() will surface the problem explicitly.\n }\n }\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { adportHome } from '../paths.js';\n\nexport interface AuditEntry {\n ts: string;\n /** 'note' records external/manual changes made outside adport's write path. */\n event: 'validated' | 'applied' | 'rejected' | 'note';\n provider: string;\n tool: string;\n accountId: string;\n pendingId?: string;\n summary: string;\n details?: unknown;\n}\n\n/** Append-only JSONL, one file per month: ${ADPORT_HOME}/audit/audit-YYYY-MM.jsonl */\nexport class AuditLog {\n constructor(private readonly dir: string = path.join(adportHome(), 'audit')) {}\n\n private file(now = new Date()): string {\n const month = now.toISOString().slice(0, 7);\n return path.join(this.dir, `audit-${month}.jsonl`);\n }\n\n async append(entry: Omit<AuditEntry, 'ts'>): Promise<void> {\n await fs.mkdir(this.dir, { recursive: true, mode: 0o700 });\n const full: AuditEntry = { ts: new Date().toISOString(), ...entry };\n await fs.appendFile(this.file(), `${JSON.stringify(full)}\\n`, { mode: 0o600 });\n }\n\n /** Most recent entries, newest last. Reads across all monthly files. */\n async read(limit = 50): Promise<AuditEntry[]> {\n let names: string[];\n try {\n names = (await fs.readdir(this.dir)).filter((n) => n.endsWith('.jsonl')).sort();\n } catch {\n return [];\n }\n const entries: AuditEntry[] = [];\n for (const name of names) {\n const raw = await fs.readFile(path.join(this.dir, name), 'utf8');\n for (const line of raw.split('\\n')) {\n if (line.trim()) entries.push(JSON.parse(line) as AuditEntry);\n }\n }\n return entries.slice(-limit);\n }\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport { AdportError } from '../errors.js';\nimport type { AdProvider, WriteGuard, WriteOperation, WritePreview, WriteResult } from '../provider.js';\nimport { AuditLog } from './audit.js';\nimport { PendingStore } from './pending.js';\nimport type { Policy } from './policy.js';\n\nexport interface ValidationOutcome {\n pendingOperationId: string;\n preview: WritePreview;\n expiresAt: string;\n}\n\nexport interface ApplyOutcome {\n result: WriteResult;\n preview: WritePreview;\n}\n\nfunction canonicalize(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalize);\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => [k, canonicalize(v)]),\n );\n }\n return value;\n}\n\nexport function hashOperation(op: WriteOperation): string {\n const canonical = canonicalize({\n tool: op.tool,\n provider: op.provider,\n accountId: op.accountId,\n kind: op.kind,\n payload: op.payload,\n });\n return createHash('sha256').update(JSON.stringify(canonical)).digest('hex');\n}\n\n/**\n * The single gate for all mutations. Enforces the two-step contract:\n * validate() dry-runs the operation and issues a pending-operation id;\n * apply() only executes an operation whose id, hash, and expiry check out.\n */\nexport class PolicyEngine {\n constructor(\n readonly policy: Policy,\n private readonly pending: PendingStore = new PendingStore(),\n private readonly audit: AuditLog = new AuditLog(),\n ) {}\n\n guard(): WriteGuard {\n return { forcePausedCreation: this.policy.paused_creation };\n }\n\n async validate(provider: AdProvider, op: WriteOperation): Promise<ValidationOutcome> {\n await this.pending.sweep(); // opportunistic cleanup of expired entries\n await this.checkStaticPolicy(op);\n const preview = await provider.previewWrite(op, this.guard());\n await this.checkBudgetPolicy(op, preview);\n\n const id = randomUUID();\n const now = Date.now();\n const expiresAt = new Date(now + this.policy.pending_ttl_minutes * 60_000).toISOString();\n await this.pending.put({\n id,\n provider: provider.id,\n opHash: hashOperation(op),\n op,\n preview,\n createdAt: new Date(now).toISOString(),\n expiresAt,\n });\n await this.audit.append({\n event: 'validated',\n provider: provider.id,\n tool: op.tool,\n accountId: op.accountId,\n pendingId: id,\n summary: preview.summary,\n });\n return { pendingOperationId: id, preview, expiresAt };\n }\n\n async apply(provider: AdProvider, op: WriteOperation, pendingId: string): Promise<ApplyOutcome> {\n // No sweep here: an expired entry must still be readable so the caller\n // gets PENDING_EXPIRED (actionable) instead of PENDING_NOT_FOUND.\n const pending = await this.pending.get(pendingId);\n if (!pending) {\n throw new AdportError(\n 'PENDING_NOT_FOUND',\n `No pending operation \"${pendingId}\". Validate first: call the tool without pending_operation_id.`,\n );\n }\n if (Date.parse(pending.expiresAt) < Date.now()) {\n await this.pending.delete(pendingId);\n throw new AdportError(\n 'PENDING_EXPIRED',\n `Pending operation ${pendingId} expired at ${pending.expiresAt}. Validate again.`,\n );\n }\n if (pending.provider !== provider.id || pending.opHash !== hashOperation(op)) {\n throw new AdportError(\n 'PENDING_MISMATCH',\n 'The operation differs from what was validated. Re-validate with the exact arguments you intend to apply.',\n );\n }\n // Policy may have changed between validate and apply; re-check.\n await this.checkStaticPolicy(op);\n\n const result = await provider.applyWrite(op, this.guard());\n await this.audit.append({\n event: 'applied',\n provider: provider.id,\n tool: op.tool,\n accountId: op.accountId,\n pendingId,\n summary: pending.preview.summary,\n details: { resourceIds: result.resourceIds },\n });\n await this.pending.delete(pendingId);\n return { result, preview: pending.preview };\n }\n\n private async checkStaticPolicy(op: WriteOperation): Promise<void> {\n if (this.policy.protected_accounts.includes(op.accountId)) {\n await this.reject(op, `Account ${op.accountId} is protected by policy`);\n }\n }\n\n private async checkBudgetPolicy(op: WriteOperation, preview: WritePreview): Promise<void> {\n const pctCap = this.policy.max_budget_delta_pct;\n const absCap = this.policy.max_daily_budget_micros;\n for (const delta of preview.budgetDeltas) {\n if (absCap !== null && delta.toMicros > absCap) {\n await this.reject(\n op,\n `${delta.target}: ${delta.toMicros} micros exceeds the absolute budget cap (${absCap})`,\n );\n }\n if (pctCap !== null && delta.fromMicros !== undefined && delta.fromMicros > 0) {\n const pct = (Math.abs(delta.toMicros - delta.fromMicros) / delta.fromMicros) * 100;\n if (pct > pctCap) {\n await this.reject(\n op,\n `${delta.target}: ${pct.toFixed(1)}% change exceeds the ${pctCap}% budget-delta cap`,\n );\n }\n }\n }\n }\n\n private async reject(op: WriteOperation, reason: string): Promise<never> {\n await this.audit.append({\n event: 'rejected',\n provider: op.provider,\n tool: op.tool,\n accountId: op.accountId,\n summary: reason,\n });\n throw new AdportError('POLICY_VIOLATION', `Policy violation: ${reason}`, { policy: this.policy });\n }\n}\n","import { z } from 'zod';\nimport type { WriteKind, WriteOperation } from '../provider.js';\nimport { defineTool, type AnyToolDefinition } from './registry.js';\n\nconst TWO_STEP_NOTE =\n 'Two-step write: call WITHOUT pending_operation_id to get a dry-run preview and a pending_operation_id; ' +\n 'call again with IDENTICAL arguments plus that id to apply.';\n\n/**\n * Wrap a provider mutation as a two-step (validate → apply) tool.\n * This is the only sanctioned way to expose a write; the handler always goes\n * through the policy engine, so rails and audit logging cannot be skipped.\n */\nexport function guardedWriteTool<S extends z.ZodObject<z.ZodRawShape>>(def: {\n name: string;\n namespace: string;\n description: string;\n provider: string;\n kind: WriteKind;\n payload: S;\n destructive?: boolean;\n}): AnyToolDefinition {\n const input = def.payload.extend({\n account_id: z.string().min(1).describe('Target account id'),\n pending_operation_id: z\n .string()\n .optional()\n .describe('Omit to get a dry-run preview; pass the returned id to apply.'),\n });\n\n return defineTool({\n name: def.name,\n namespace: def.namespace,\n description: `${def.description}\\n\\n${TWO_STEP_NOTE}`,\n input,\n annotations: { readOnly: false, destructive: def.destructive ?? false },\n async handler(raw, ctx) {\n const { account_id, pending_operation_id, ...payload } = raw as Record<string, unknown> & {\n account_id: string;\n pending_operation_id?: string;\n };\n const provider = ctx.providers.get(def.provider);\n const op: WriteOperation = {\n tool: def.name,\n provider: def.provider,\n accountId: account_id,\n kind: def.kind,\n payload,\n };\n if (!pending_operation_id) {\n const outcome = await ctx.engine.validate(provider, op);\n return {\n status: 'pending_validation',\n applied: false,\n pending_operation_id: outcome.pendingOperationId,\n expires_at: outcome.expiresAt,\n preview: outcome.preview,\n next_step:\n 'Review the preview. To apply, call this tool again with the same arguments plus pending_operation_id.',\n };\n }\n const outcome = await ctx.engine.apply(provider, op, pending_operation_id);\n return { status: 'applied', applied: true, result: outcome.result, preview: outcome.preview };\n },\n });\n}\n","import { z } from 'zod';\nimport { DATE_PRESETS, ENTITY_LEVELS, METRICS, type NormalizedQuery, type ReportRow } from '../model.js';\nimport { selectConnectedProviders, type Account } from '../provider.js';\nimport { defineTool, type AnyToolDefinition } from './registry.js';\n\nconst dateRangeSchema = z.union([\n z.enum(DATE_PRESETS),\n z.object({\n start: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'YYYY-MM-DD'),\n end: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'YYYY-MM-DD'),\n }),\n]);\n\nexport function builtinTools(): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'accounts_list',\n namespace: 'core',\n description: 'List connected ad accounts across all providers (or one provider).',\n input: z.object({\n provider: z.string().optional().describe('Limit to one provider id, e.g. \"google\".'),\n }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const providers = selectConnectedProviders(ctx.providers, input.provider);\n const accounts: Account[] = [];\n for (const provider of providers) {\n accounts.push(...(await provider.listAccounts()));\n }\n return { accounts };\n },\n }),\n defineTool({\n name: 'report',\n namespace: 'core',\n description:\n 'Cross-platform performance report with normalized metrics (spend, clicks, conversions, ROAS, ...). ' +\n 'Rows are capped by `limit`; the response says when it truncated.',\n input: z.object({\n provider: z.string().optional().describe('Limit to one provider id.'),\n account_ids: z.array(z.string()).optional(),\n level: z.enum(ENTITY_LEVELS).default('campaign'),\n metrics: z.array(z.enum(METRICS)).min(1).default(['spend', 'impressions', 'clicks', 'conversions']),\n date_range: dateRangeSchema.default('last_7_days'),\n limit: z.number().int().positive().max(1000).default(100),\n }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const providers = selectConnectedProviders(ctx.providers, input.provider);\n const query: NormalizedQuery = {\n accountIds: input.account_ids,\n level: input.level,\n metrics: input.metrics,\n dateRange: input.date_range,\n limit: input.limit,\n };\n const rows: ReportRow[] = [];\n for (const provider of providers) {\n const report = await provider.report(query);\n rows.push(...report.rows);\n }\n const truncated = rows.length > input.limit;\n return { rows: rows.slice(0, input.limit), truncated };\n },\n }),\n ];\n}\n","import { z } from 'zod';\nimport { AdportError } from '../errors.js';\nimport {\n rangeDayCount,\n resolveDateRange,\n type MetricName,\n type NormalizedQuery,\n type Report,\n type ReportRow,\n} from '../model.js';\nimport type {\n Account,\n AdProvider,\n ProviderCapabilities,\n StandardActions,\n WriteGuard,\n WriteOperation,\n WritePreview,\n WriteResult,\n} from '../provider.js';\nimport { defineTool, type AnyToolDefinition } from '../tools/registry.js';\nimport { guardedWriteTool } from '../tools/write.js';\n\ninterface MockCampaign {\n id: string;\n name: string;\n status: 'ENABLED' | 'PAUSED' | 'REMOVED';\n dailyBudgetMicros: number;\n}\n\ninterface MockAccount extends Account {\n campaigns: MockCampaign[];\n}\n\nfunction seedAccounts(): MockAccount[] {\n return [\n {\n provider: 'mock',\n id: 'mock-1',\n name: 'Acme DTC Store',\n currency: 'EUR',\n status: 'ENABLED',\n campaigns: [\n { id: 'c1', name: 'Brand Search', status: 'ENABLED', dailyBudgetMicros: 10_000_000 },\n { id: 'c2', name: 'Prospecting', status: 'ENABLED', dailyBudgetMicros: 25_000_000 },\n // Deliberately conversion-less: exercises the audit harness.\n { id: 'c4', name: 'Legacy Retargeting', status: 'ENABLED', dailyBudgetMicros: 8_000_000 },\n ],\n },\n {\n provider: 'mock',\n id: 'mock-2',\n name: 'Beta App',\n currency: 'USD',\n status: 'ENABLED',\n campaigns: [{ id: 'c3', name: 'Install Campaign', status: 'PAUSED', dailyBudgetMicros: 5_000_000 }],\n },\n ];\n}\n\n/**\n * In-memory provider for tests, demos, and trying adport without credentials.\n * Deterministic: same inputs always produce the same report numbers.\n */\nexport class MockProvider implements AdProvider {\n readonly id = 'mock';\n private accounts: MockAccount[] = seedAccounts();\n\n capabilities(): ProviderCapabilities {\n return { serverDryRun: false };\n }\n\n standardActions(): StandardActions {\n return {\n pauseCampaign: (accountId, campaignId) => ({\n tool: 'mock_set_campaign_status',\n input: { account_id: accountId, campaign_id: campaignId, status: 'PAUSED' },\n }),\n };\n }\n\n async listAccounts(): Promise<Account[]> {\n return this.accounts.map(({ campaigns: _campaigns, ...account }) => account);\n }\n\n listCampaigns(accountId: string): MockCampaign[] {\n return [...this.account(accountId).campaigns];\n }\n\n async report(query: NormalizedQuery): Promise<Report> {\n const range = resolveDateRange(query.dateRange);\n const days = rangeDayCount(range);\n const rows: ReportRow[] = [];\n for (const account of this.accounts) {\n if (query.accountIds && !query.accountIds.includes(account.id)) continue;\n for (const [index, campaign] of account.campaigns.entries()) {\n if (campaign.status === 'REMOVED') continue;\n rows.push({\n provider: this.id,\n accountId: account.id,\n entity: { level: 'campaign', id: campaign.id, name: campaign.name, status: campaign.status },\n metrics: mockMetrics(query.metrics, index, days, campaign.dailyBudgetMicros, campaign.id === 'c4'),\n });\n }\n }\n return { rows };\n }\n\n async previewWrite(op: WriteOperation, guard: WriteGuard): Promise<WritePreview> {\n return this.plan(op, guard).preview;\n }\n\n async applyWrite(op: WriteOperation, guard: WriteGuard): Promise<WriteResult> {\n return this.plan(op, guard).apply();\n }\n\n private account(accountId: string): MockAccount {\n const account = this.accounts.find((a) => a.id === accountId);\n if (!account) throw new AdportError('PROVIDER_ERROR', `mock: unknown account ${accountId}`);\n return account;\n }\n\n private campaign(accountId: string, campaignId: string): MockCampaign {\n const campaign = this.account(accountId).campaigns.find((c) => c.id === campaignId);\n if (!campaign) throw new AdportError('PROVIDER_ERROR', `mock: unknown campaign ${campaignId}`);\n return campaign;\n }\n\n /** Compute preview and applier together so dry-run and apply can never drift. */\n private plan(op: WriteOperation, guard: WriteGuard): { preview: WritePreview; apply: () => WriteResult } {\n const base = { coercions: [] as string[], budgetDeltas: [], serverValidated: false };\n switch (op.tool) {\n case 'mock_create_campaign': {\n const payload = op.payload as { name: string; daily_budget_micros: number; status?: string };\n let status = (payload.status ?? 'ENABLED') as MockCampaign['status'];\n const coercions: string[] = [];\n if (guard.forcePausedCreation && status === 'ENABLED') {\n status = 'PAUSED';\n coercions.push('status coerced to PAUSED by policy (paused_creation)');\n }\n const account = this.account(op.accountId);\n const id = `c${100 + account.campaigns.length}`;\n return {\n preview: {\n ...base,\n summary: `Create campaign \"${payload.name}\" (${status}) with daily budget ${payload.daily_budget_micros} micros`,\n changes: [`+ campaign ${id} \"${payload.name}\" status=${status}`],\n coercions,\n budgetDeltas: [{ target: `new campaign \"${payload.name}\" daily budget`, toMicros: payload.daily_budget_micros }],\n },\n apply: () => {\n account.campaigns.push({ id, name: payload.name, status, dailyBudgetMicros: payload.daily_budget_micros });\n return { applied: true, resourceIds: [id] };\n },\n };\n }\n case 'mock_set_budget': {\n const payload = op.payload as { campaign_id: string; daily_budget_micros: number };\n const campaign = this.campaign(op.accountId, payload.campaign_id);\n return {\n preview: {\n ...base,\n summary: `Change \"${campaign.name}\" daily budget ${campaign.dailyBudgetMicros} → ${payload.daily_budget_micros} micros`,\n changes: [`~ campaign ${campaign.id} daily_budget ${campaign.dailyBudgetMicros} → ${payload.daily_budget_micros}`],\n budgetDeltas: [\n {\n target: `campaign \"${campaign.name}\" daily budget`,\n fromMicros: campaign.dailyBudgetMicros,\n toMicros: payload.daily_budget_micros,\n },\n ],\n },\n apply: () => {\n campaign.dailyBudgetMicros = payload.daily_budget_micros;\n return { applied: true, resourceIds: [campaign.id] };\n },\n };\n }\n case 'mock_set_campaign_status': {\n const payload = op.payload as { campaign_id: string; status: 'ENABLED' | 'PAUSED' };\n const campaign = this.campaign(op.accountId, payload.campaign_id);\n return {\n preview: {\n ...base,\n summary: `Set \"${campaign.name}\" status ${campaign.status} → ${payload.status}`,\n changes: [`~ campaign ${campaign.id} status ${campaign.status} → ${payload.status}`],\n },\n apply: () => {\n campaign.status = payload.status;\n return { applied: true, resourceIds: [campaign.id] };\n },\n };\n }\n case 'mock_remove_campaign': {\n const payload = op.payload as { campaign_id: string };\n const campaign = this.campaign(op.accountId, payload.campaign_id);\n return {\n preview: {\n ...base,\n summary: `PERMANENTLY remove campaign \"${campaign.name}\"`,\n changes: [`- campaign ${campaign.id} \"${campaign.name}\"`],\n },\n apply: () => {\n campaign.status = 'REMOVED';\n return { applied: true, resourceIds: [campaign.id] };\n },\n };\n }\n default:\n throw new AdportError('PROVIDER_ERROR', `mock: unsupported write tool ${op.tool}`);\n }\n }\n}\n\nfunction mockMetrics(\n requested: MetricName[],\n seed: number,\n days: number,\n dailyBudgetMicros: number,\n zeroConversions = false,\n): Partial<Record<MetricName, number>> {\n const spend = ((dailyBudgetMicros / 1_000_000) * 0.83 + seed) * days;\n const impressions = (2_000 + seed * 700) * days;\n const clicks = (90 + seed * 35) * days;\n const conversions = zeroConversions ? 0 : (4 + seed) * days;\n const conversionValue = conversions * (35 + seed * 5);\n const all: Record<MetricName, number> = {\n spend: round2(spend),\n impressions,\n clicks,\n conversions,\n conversion_value: round2(conversionValue),\n ctr: round2((clicks / impressions) * 100),\n cpc: round2(spend / clicks),\n cpm: round2((spend / impressions) * 1000),\n cpa: conversions > 0 ? round2(spend / conversions) : 0,\n roas: spend > 0 ? round2(conversionValue / spend) : 0,\n };\n return Object.fromEntries(requested.map((m) => [m, all[m]]));\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nexport function mockTools(): AnyToolDefinition[] {\n return [\n defineTool({\n name: 'mock_list_campaigns',\n namespace: 'mock',\n description: 'List campaigns in a mock account (id, name, status, daily budget).',\n input: z.object({ account_id: z.string() }),\n annotations: { readOnly: true },\n async handler(input, ctx) {\n const provider = ctx.providers.get('mock') as MockProvider;\n return { campaigns: provider.listCampaigns(input.account_id) };\n },\n }),\n guardedWriteTool({\n name: 'mock_create_campaign',\n namespace: 'mock',\n description: 'Create a campaign in the mock account.',\n provider: 'mock',\n kind: 'create',\n payload: z.object({\n name: z.string().min(1),\n daily_budget_micros: z.number().int().positive(),\n status: z.enum(['ENABLED', 'PAUSED']).optional(),\n }),\n }),\n guardedWriteTool({\n name: 'mock_set_budget',\n namespace: 'mock',\n description: 'Change a mock campaign daily budget.',\n provider: 'mock',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), daily_budget_micros: z.number().int().positive() }),\n }),\n guardedWriteTool({\n name: 'mock_set_campaign_status',\n namespace: 'mock',\n description: 'Enable or pause a mock campaign.',\n provider: 'mock',\n kind: 'update',\n payload: z.object({ campaign_id: z.string(), status: z.enum(['ENABLED', 'PAUSED']) }),\n }),\n guardedWriteTool({\n name: 'mock_remove_campaign',\n namespace: 'mock',\n description: 'Permanently remove a mock campaign.',\n provider: 'mock',\n kind: 'remove',\n destructive: true,\n payload: z.object({ campaign_id: z.string() }),\n }),\n ];\n}\n","import { auditTools } from './audit/tools.js';\nimport { CredentialStore } from './credentials/store.js';\nimport { PolicyEngine } from './policy/engine.js';\nimport { loadPolicy } from './policy/policy.js';\nimport { ProviderRegistry, type AdProvider } from './provider.js';\nimport { builtinTools } from './tools/builtin.js';\nimport { ToolRegistry, type AnyToolDefinition, type ToolContext } from './tools/registry.js';\nimport { MockProvider, mockTools } from './testing/mock-provider.js';\n\nexport interface ProviderModule {\n provider: AdProvider;\n tools: AnyToolDefinition[];\n}\n\nexport interface CreateContextOptions {\n policyPath?: string;\n /** Extra providers with their tools (e.g. the Google provider from @adport/provider-google). */\n providerModules?: ProviderModule[];\n /**\n * Include the credential-free mock provider. Disabled by default so a\n * misconfigured live runtime cannot silently substitute synthetic accounts.\n */\n includeMock?: boolean;\n}\n\nexport interface AdportRuntime {\n ctx: ToolContext;\n registry: ToolRegistry;\n policySource: string;\n}\n\nexport async function createContext(options: CreateContextOptions = {}): Promise<AdportRuntime> {\n const modules = options.providerModules ?? [];\n const includeMock = options.includeMock ?? false;\n\n const providers = new ProviderRegistry();\n const { policy, source } = await loadPolicy(options.policyPath);\n const engine = new PolicyEngine(policy);\n const credentials = new CredentialStore();\n\n const registry = new ToolRegistry();\n registry.register(builtinTools());\n registry.register(auditTools());\n\n for (const module of modules) {\n providers.register(module.provider);\n registry.register(module.tools);\n }\n if (includeMock) {\n providers.register(new MockProvider());\n registry.register(mockTools());\n }\n\n const ctx: ToolContext = { providers, engine, credentials };\n ctx.registry = registry;\n return { ctx, registry, policySource: source };\n}\n"],"mappings":"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","names":["path","path","fs","path","path","fs","fs","path","z","z","path","fs","fs","path","path","fs","fs","path","path","fs","z","z","outcome","z","dateRangeSchema","z","z","z"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adport/core",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "adport core: provider interface, tool registry, policy engine, credential store",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -17,13 +17,13 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "yaml": "^2.6.0",
20
- "zod": "^3.25.0"
20
+ "zod": "^4.4.3"
21
21
  },
22
22
  "devDependencies": {
23
- "@types/node": "^22.10.0",
23
+ "@types/node": "^26.1.2",
24
24
  "tsup": "^8.3.0",
25
25
  "typescript": "^5.8.0",
26
- "vitest": "^3.0.0"
26
+ "vitest": "^4.1.10"
27
27
  },
28
28
  "scripts": {
29
29
  "build": "tsup src/index.ts --format esm --dts --sourcemap --clean",