@adport/core 0.5.2 → 0.6.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 +39 -6
- package/dist/index.js +68 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -202,12 +202,21 @@ interface RulePack {
|
|
|
202
202
|
|
|
203
203
|
declare const corePerformancePack: RulePack;
|
|
204
204
|
|
|
205
|
+
interface FindingsRepository {
|
|
206
|
+
list(filter?: {
|
|
207
|
+
status?: FindingStatus;
|
|
208
|
+
provider?: string;
|
|
209
|
+
}): Promise<AuditFinding[]>;
|
|
210
|
+
get(id: string): Promise<AuditFinding | undefined>;
|
|
211
|
+
save(finding: AuditFinding): Promise<void>;
|
|
212
|
+
setStatus(id: string, status: FindingStatus): Promise<AuditFinding>;
|
|
213
|
+
}
|
|
205
214
|
/**
|
|
206
215
|
* Findings persist on disk with their approval lifecycle — the durable side of
|
|
207
216
|
* the recommendation harness: a recommendation can wait for a human decision
|
|
208
217
|
* across restarts, indefinitely, at zero cost.
|
|
209
218
|
*/
|
|
210
|
-
declare class FindingsStore {
|
|
219
|
+
declare class FindingsStore implements FindingsRepository {
|
|
211
220
|
private readonly dir;
|
|
212
221
|
constructor(dir?: string);
|
|
213
222
|
private file;
|
|
@@ -226,6 +235,8 @@ interface AuditRunOptions {
|
|
|
226
235
|
dateRange?: DateRange | DatePreset;
|
|
227
236
|
packs?: RulePack[];
|
|
228
237
|
configOverrides?: Record<string, number>;
|
|
238
|
+
/** Set false for a read-only preview that evaluates rules without saving findings. */
|
|
239
|
+
persist?: boolean;
|
|
229
240
|
}
|
|
230
241
|
interface AuditRunResult {
|
|
231
242
|
findings: AuditFinding[];
|
|
@@ -245,7 +256,7 @@ interface AuditRunResult {
|
|
|
245
256
|
declare class AuditRunner {
|
|
246
257
|
private readonly providers;
|
|
247
258
|
private readonly store;
|
|
248
|
-
constructor(providers: ProviderRegistry, store?:
|
|
259
|
+
constructor(providers: ProviderRegistry, store?: FindingsRepository);
|
|
249
260
|
run(options?: AuditRunOptions): Promise<AuditRunResult>;
|
|
250
261
|
}
|
|
251
262
|
|
|
@@ -285,8 +296,12 @@ interface AuditEntry {
|
|
|
285
296
|
summary: string;
|
|
286
297
|
details?: unknown;
|
|
287
298
|
}
|
|
299
|
+
/** Append-only persistence contract shared by local and hosted runtimes. */
|
|
300
|
+
interface AuditEntryStore {
|
|
301
|
+
append(entry: Omit<AuditEntry, 'ts'>): Promise<void>;
|
|
302
|
+
}
|
|
288
303
|
/** Append-only JSONL, one file per month: ${ADPORT_HOME}/audit/audit-YYYY-MM.jsonl */
|
|
289
|
-
declare class AuditLog {
|
|
304
|
+
declare class AuditLog implements AuditEntryStore {
|
|
290
305
|
private readonly dir;
|
|
291
306
|
constructor(dir?: string);
|
|
292
307
|
private file;
|
|
@@ -304,11 +319,18 @@ interface PendingOperation {
|
|
|
304
319
|
createdAt: string;
|
|
305
320
|
expiresAt: string;
|
|
306
321
|
}
|
|
322
|
+
/** Persistence contract used by the policy engine in local and hosted runtimes. */
|
|
323
|
+
interface PendingOperationStore {
|
|
324
|
+
put(op: PendingOperation): Promise<void>;
|
|
325
|
+
get(id: string): Promise<PendingOperation | undefined>;
|
|
326
|
+
delete(id: string): Promise<void>;
|
|
327
|
+
sweep(now?: Date): Promise<void>;
|
|
328
|
+
}
|
|
307
329
|
/**
|
|
308
330
|
* File-backed store so validate and apply can happen in different processes
|
|
309
331
|
* (CLI invocations, MCP server restarts).
|
|
310
332
|
*/
|
|
311
|
-
declare class PendingStore {
|
|
333
|
+
declare class PendingStore implements PendingOperationStore {
|
|
312
334
|
private readonly dir;
|
|
313
335
|
constructor(dir?: string);
|
|
314
336
|
private file;
|
|
@@ -361,7 +383,7 @@ declare class PolicyEngine {
|
|
|
361
383
|
readonly policy: Policy;
|
|
362
384
|
private readonly pending;
|
|
363
385
|
private readonly audit;
|
|
364
|
-
constructor(policy: Policy, pending?:
|
|
386
|
+
constructor(policy: Policy, pending?: PendingOperationStore, audit?: AuditEntryStore);
|
|
365
387
|
guard(): WriteGuard;
|
|
366
388
|
validate(provider: AdProvider, op: WriteOperation): Promise<ValidationOutcome>;
|
|
367
389
|
apply(provider: AdProvider, op: WriteOperation, pendingId: string): Promise<ApplyOutcome>;
|
|
@@ -373,6 +395,7 @@ declare class PolicyEngine {
|
|
|
373
395
|
interface ToolAnnotations {
|
|
374
396
|
readOnly?: boolean;
|
|
375
397
|
destructive?: boolean;
|
|
398
|
+
openWorld?: boolean;
|
|
376
399
|
}
|
|
377
400
|
interface ToolContext {
|
|
378
401
|
providers: ProviderRegistry;
|
|
@@ -380,6 +403,10 @@ interface ToolContext {
|
|
|
380
403
|
credentials: CredentialStore;
|
|
381
404
|
/** Set by createContext; lets tools invoke other tools (e.g. recommendation_apply). */
|
|
382
405
|
registry?: ToolRegistry;
|
|
406
|
+
/** Hosted adapters may enforce tenant/account entitlements before handlers run. */
|
|
407
|
+
authorizeToolCall?: (tool: AnyToolDefinition, input: Record<string, unknown>) => void | Promise<void>;
|
|
408
|
+
/** Hosted runtimes inject a tenant-scoped findings repository. */
|
|
409
|
+
findings?: FindingsRepository;
|
|
383
410
|
}
|
|
384
411
|
interface AnyToolDefinition {
|
|
385
412
|
name: string;
|
|
@@ -465,6 +492,12 @@ interface CreateContextOptions {
|
|
|
465
492
|
* misconfigured live runtime cannot silently substitute synthetic accounts.
|
|
466
493
|
*/
|
|
467
494
|
includeMock?: boolean;
|
|
495
|
+
/** Hosted runtimes inject a tenant-scoped engine with durable database stores. */
|
|
496
|
+
engine?: PolicyEngine;
|
|
497
|
+
/** Optional hosted authorization boundary executed before every tool handler. */
|
|
498
|
+
authorizeToolCall?: ToolContext['authorizeToolCall'];
|
|
499
|
+
/** Hosted runtimes inject tenant-scoped finding persistence. */
|
|
500
|
+
findings?: FindingsRepository;
|
|
468
501
|
}
|
|
469
502
|
interface AdportRuntime {
|
|
470
503
|
ctx: ToolContext;
|
|
@@ -473,4 +506,4 @@ interface AdportRuntime {
|
|
|
473
506
|
}
|
|
474
507
|
declare function createContext(options?: CreateContextOptions): Promise<AdportRuntime>;
|
|
475
508
|
|
|
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 };
|
|
509
|
+
export { type Account, type AdProvider, AdportError, type AdportErrorCode, type AdportRuntime, type AnyToolDefinition, type ApplyOutcome, type AuditEntry, type AuditEntryStore, 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, type FindingsRepository, FindingsStore, type LoadedPolicy, METRICS, type MetricName, MockProvider, type NormalizedQuery, type PendingOperation, type PendingOperationStore, 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
|
@@ -288,7 +288,7 @@ var AuditRunner = class {
|
|
|
288
288
|
createdAt: existing?.createdAt ?? now,
|
|
289
289
|
updatedAt: now
|
|
290
290
|
};
|
|
291
|
-
await this.store.save(finding);
|
|
291
|
+
if (options.persist !== false) await this.store.save(finding);
|
|
292
292
|
findings.push(finding);
|
|
293
293
|
}
|
|
294
294
|
}
|
|
@@ -313,9 +313,14 @@ import { z } from "zod";
|
|
|
313
313
|
|
|
314
314
|
// src/tools/registry.ts
|
|
315
315
|
function defineTool(def) {
|
|
316
|
+
const openWorldByDefault = !["core", "mock", "audit"].includes(def.namespace);
|
|
316
317
|
return {
|
|
317
318
|
...def,
|
|
318
|
-
annotations:
|
|
319
|
+
annotations: {
|
|
320
|
+
readOnly: def.annotations?.readOnly ?? false,
|
|
321
|
+
destructive: def.annotations?.destructive ?? false,
|
|
322
|
+
openWorld: def.annotations?.openWorld ?? openWorldByDefault
|
|
323
|
+
}
|
|
319
324
|
};
|
|
320
325
|
}
|
|
321
326
|
var ToolRegistry = class {
|
|
@@ -342,6 +347,7 @@ var ToolRegistry = class {
|
|
|
342
347
|
if (!parsed.success) {
|
|
343
348
|
throw new AdportError("INVALID_INPUT", `Invalid input for ${name}`, parsed.error.issues);
|
|
344
349
|
}
|
|
350
|
+
await ctx.authorizeToolCall?.(tool, parsed.data);
|
|
345
351
|
return tool.handler(parsed.data, ctx);
|
|
346
352
|
}
|
|
347
353
|
};
|
|
@@ -356,18 +362,38 @@ var dateRangeSchema = z.union([
|
|
|
356
362
|
]);
|
|
357
363
|
function auditTools() {
|
|
358
364
|
return [
|
|
365
|
+
defineTool({
|
|
366
|
+
name: "audit_preview",
|
|
367
|
+
namespace: "audit",
|
|
368
|
+
description: "Evaluate the cross-platform audit rule packs over connected accounts and return structured findings without persisting them. Use this read-only audit in Reader workspaces or for one-off analysis.",
|
|
369
|
+
input: z.object({
|
|
370
|
+
provider: z.string().optional(),
|
|
371
|
+
account_ids: z.array(z.string()).optional(),
|
|
372
|
+
date_range: dateRangeSchema.default("last_30_days")
|
|
373
|
+
}),
|
|
374
|
+
annotations: { readOnly: true, openWorld: true },
|
|
375
|
+
async handler(input, ctx) {
|
|
376
|
+
const runner = new AuditRunner(ctx.providers, ctx.findings ?? new FindingsStore());
|
|
377
|
+
return runner.run({
|
|
378
|
+
provider: input.provider,
|
|
379
|
+
accountIds: input.account_ids,
|
|
380
|
+
dateRange: input.date_range,
|
|
381
|
+
persist: false
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
359
385
|
defineTool({
|
|
360
386
|
name: "audit_run",
|
|
361
387
|
namespace: "audit",
|
|
362
|
-
description: "Run the cross-platform audit rule packs over connected accounts (campaign level).
|
|
388
|
+
description: "Run the cross-platform audit rule packs over connected accounts (campaign level). Persists structured findings for recommendation lifecycle management; some carry a ready-to-apply proposed action.",
|
|
363
389
|
input: z.object({
|
|
364
390
|
provider: z.string().optional(),
|
|
365
391
|
account_ids: z.array(z.string()).optional(),
|
|
366
392
|
date_range: dateRangeSchema.default("last_30_days")
|
|
367
393
|
}),
|
|
368
|
-
annotations: { readOnly:
|
|
394
|
+
annotations: { readOnly: false, openWorld: false },
|
|
369
395
|
async handler(input, ctx) {
|
|
370
|
-
const runner = new AuditRunner(ctx.providers);
|
|
396
|
+
const runner = new AuditRunner(ctx.providers, ctx.findings ?? new FindingsStore());
|
|
371
397
|
const result = await runner.run({
|
|
372
398
|
provider: input.provider,
|
|
373
399
|
accountIds: input.account_ids,
|
|
@@ -385,8 +411,8 @@ function auditTools() {
|
|
|
385
411
|
provider: z.string().optional()
|
|
386
412
|
}),
|
|
387
413
|
annotations: { readOnly: true },
|
|
388
|
-
async handler(input) {
|
|
389
|
-
const findings = await new FindingsStore().list(input);
|
|
414
|
+
async handler(input, ctx) {
|
|
415
|
+
const findings = await (ctx.findings ?? new FindingsStore()).list(input);
|
|
390
416
|
return { findings, count: findings.length };
|
|
391
417
|
}
|
|
392
418
|
}),
|
|
@@ -396,8 +422,8 @@ function auditTools() {
|
|
|
396
422
|
description: "Dismiss a finding (it will not be re-opened by future audit runs).",
|
|
397
423
|
input: z.object({ finding_id: z.string() }),
|
|
398
424
|
annotations: { readOnly: false },
|
|
399
|
-
async handler(input) {
|
|
400
|
-
const finding = await new FindingsStore().setStatus(input.finding_id, "dismissed");
|
|
425
|
+
async handler(input, ctx) {
|
|
426
|
+
const finding = await (ctx.findings ?? new FindingsStore()).setStatus(input.finding_id, "dismissed");
|
|
401
427
|
return { finding };
|
|
402
428
|
}
|
|
403
429
|
}),
|
|
@@ -409,12 +435,12 @@ function auditTools() {
|
|
|
409
435
|
finding_id: z.string(),
|
|
410
436
|
pending_operation_id: z.string().optional()
|
|
411
437
|
}),
|
|
412
|
-
annotations: { readOnly: false },
|
|
438
|
+
annotations: { readOnly: false, openWorld: true },
|
|
413
439
|
async handler(input, ctx) {
|
|
414
440
|
if (!ctx.registry) {
|
|
415
441
|
throw new AdportError("PROVIDER_ERROR", "recommendation_apply requires a tool registry in context");
|
|
416
442
|
}
|
|
417
|
-
const store = new FindingsStore();
|
|
443
|
+
const store = ctx.findings ?? new FindingsStore();
|
|
418
444
|
const finding = await store.get(input.finding_id);
|
|
419
445
|
if (!finding) throw new AdportError("INVALID_INPUT", `Finding not found: ${input.finding_id}`);
|
|
420
446
|
if (finding.status !== "open") {
|
|
@@ -819,16 +845,23 @@ function builtinTools() {
|
|
|
819
845
|
namespace: "core",
|
|
820
846
|
description: "List connected ad accounts across all providers (or one provider).",
|
|
821
847
|
input: z4.object({
|
|
822
|
-
provider: z4.string().optional().describe('Limit to one provider id, e.g. "google".')
|
|
848
|
+
provider: z4.string().optional().describe('Limit to one provider id, e.g. "google".'),
|
|
849
|
+
continue_on_error: z4.boolean().default(false).describe("Return successful providers plus per-provider errors instead of failing the whole read.")
|
|
823
850
|
}),
|
|
824
|
-
annotations: { readOnly: true },
|
|
851
|
+
annotations: { readOnly: true, openWorld: true },
|
|
825
852
|
async handler(input, ctx) {
|
|
826
853
|
const providers = selectConnectedProviders(ctx.providers, input.provider);
|
|
827
854
|
const accounts = [];
|
|
855
|
+
const errors = [];
|
|
828
856
|
for (const provider of providers) {
|
|
829
|
-
|
|
857
|
+
try {
|
|
858
|
+
accounts.push(...await provider.listAccounts());
|
|
859
|
+
} catch (error) {
|
|
860
|
+
if (!input.continue_on_error) throw error;
|
|
861
|
+
errors.push({ provider: provider.id, message: error instanceof Error ? error.message : String(error) });
|
|
862
|
+
}
|
|
830
863
|
}
|
|
831
|
-
return { accounts };
|
|
864
|
+
return { accounts, errors };
|
|
832
865
|
}
|
|
833
866
|
}),
|
|
834
867
|
defineTool({
|
|
@@ -841,9 +874,10 @@ function builtinTools() {
|
|
|
841
874
|
level: z4.enum(ENTITY_LEVELS).default("campaign"),
|
|
842
875
|
metrics: z4.array(z4.enum(METRICS)).min(1).default(["spend", "impressions", "clicks", "conversions"]),
|
|
843
876
|
date_range: dateRangeSchema2.default("last_7_days"),
|
|
844
|
-
limit: z4.number().int().positive().max(1e3).default(100)
|
|
877
|
+
limit: z4.number().int().positive().max(1e3).default(100),
|
|
878
|
+
continue_on_error: z4.boolean().default(false).describe("Return successful providers plus per-provider errors instead of failing the whole read.")
|
|
845
879
|
}),
|
|
846
|
-
annotations: { readOnly: true },
|
|
880
|
+
annotations: { readOnly: true, openWorld: true },
|
|
847
881
|
async handler(input, ctx) {
|
|
848
882
|
const providers = selectConnectedProviders(ctx.providers, input.provider);
|
|
849
883
|
const query = {
|
|
@@ -854,12 +888,18 @@ function builtinTools() {
|
|
|
854
888
|
limit: input.limit
|
|
855
889
|
};
|
|
856
890
|
const rows = [];
|
|
891
|
+
const errors = [];
|
|
857
892
|
for (const provider of providers) {
|
|
858
|
-
|
|
859
|
-
|
|
893
|
+
try {
|
|
894
|
+
const report = await provider.report(query);
|
|
895
|
+
rows.push(...report.rows);
|
|
896
|
+
} catch (error) {
|
|
897
|
+
if (!input.continue_on_error) throw error;
|
|
898
|
+
errors.push({ provider: provider.id, message: error instanceof Error ? error.message : String(error) });
|
|
899
|
+
}
|
|
860
900
|
}
|
|
861
901
|
const truncated = rows.length > input.limit;
|
|
862
|
-
return { rows: rows.slice(0, input.limit), truncated };
|
|
902
|
+
return { rows: rows.slice(0, input.limit), truncated, errors };
|
|
863
903
|
}
|
|
864
904
|
})
|
|
865
905
|
];
|
|
@@ -1113,7 +1153,7 @@ async function createContext(options = {}) {
|
|
|
1113
1153
|
const includeMock = options.includeMock ?? false;
|
|
1114
1154
|
const providers = new ProviderRegistry();
|
|
1115
1155
|
const { policy, source } = await loadPolicy(options.policyPath);
|
|
1116
|
-
const engine = new PolicyEngine(policy);
|
|
1156
|
+
const engine = options.engine ?? new PolicyEngine(policy);
|
|
1117
1157
|
const credentials = new CredentialStore();
|
|
1118
1158
|
const registry = new ToolRegistry();
|
|
1119
1159
|
registry.register(builtinTools());
|
|
@@ -1126,7 +1166,13 @@ async function createContext(options = {}) {
|
|
|
1126
1166
|
providers.register(new MockProvider());
|
|
1127
1167
|
registry.register(mockTools());
|
|
1128
1168
|
}
|
|
1129
|
-
const ctx = {
|
|
1169
|
+
const ctx = {
|
|
1170
|
+
providers,
|
|
1171
|
+
engine,
|
|
1172
|
+
credentials,
|
|
1173
|
+
authorizeToolCall: options.authorizeToolCall,
|
|
1174
|
+
findings: options.findings
|
|
1175
|
+
};
|
|
1130
1176
|
ctx.registry = registry;
|
|
1131
1177
|
return { ctx, registry, policySource: source };
|
|
1132
1178
|
}
|
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\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"]}
|
|
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\nexport interface FindingsRepository {\n list(filter?: { status?: FindingStatus; provider?: string }): Promise<AuditFinding[]>;\n get(id: string): Promise<AuditFinding | undefined>;\n save(finding: AuditFinding): Promise<void>;\n setStatus(id: string, status: FindingStatus): Promise<AuditFinding>;\n}\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 implements FindingsRepository {\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, type FindingsRepository } 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 /** Set false for a read-only preview that evaluates rules without saving findings. */\n persist?: boolean;\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: FindingsRepository = 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 if (options.persist !== false) 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_preview',\n namespace: 'audit',\n description:\n 'Evaluate the cross-platform audit rule packs over connected accounts and return structured findings ' +\n 'without persisting them. Use this read-only audit in Reader workspaces or for one-off analysis.',\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, openWorld: true },\n async handler(input, ctx) {\n const runner = new AuditRunner(ctx.providers, ctx.findings ?? new FindingsStore());\n return runner.run({\n provider: input.provider,\n accountIds: input.account_ids,\n dateRange: input.date_range,\n persist: false,\n });\n },\n }),\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 'Persists structured findings for recommendation lifecycle management; some carry a ready-to-apply proposed action.',\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: false, openWorld: false },\n async handler(input, ctx) {\n const runner = new AuditRunner(ctx.providers, ctx.findings ?? new FindingsStore());\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, ctx) {\n const findings = await (ctx.findings ?? 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, ctx) {\n const finding = await (ctx.findings ?? 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, openWorld: true },\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 = ctx.findings ?? 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 type { FindingsRepository } from '../audit/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 openWorld?: 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 /** Hosted adapters may enforce tenant/account entitlements before handlers run. */\n authorizeToolCall?: (tool: AnyToolDefinition, input: Record<string, unknown>) => void | Promise<void>;\n /** Hosted runtimes inject a tenant-scoped findings repository. */\n findings?: FindingsRepository;\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 const openWorldByDefault = !['core', 'mock', 'audit'].includes(def.namespace);\n return {\n ...def,\n annotations: {\n readOnly: def.annotations?.readOnly ?? false,\n destructive: def.annotations?.destructive ?? false,\n openWorld: def.annotations?.openWorld ?? openWorldByDefault,\n },\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 await ctx.authorizeToolCall?.(tool, parsed.data as Record<string, unknown>);\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/** Persistence contract used by the policy engine in local and hosted runtimes. */\nexport interface PendingOperationStore {\n put(op: PendingOperation): Promise<void>;\n get(id: string): Promise<PendingOperation | undefined>;\n delete(id: string): Promise<void>;\n sweep(now?: Date): Promise<void>;\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 implements PendingOperationStore {\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 persistence contract shared by local and hosted runtimes. */\nexport interface AuditEntryStore {\n append(entry: Omit<AuditEntry, 'ts'>): Promise<void>;\n}\n\n/** Append-only JSONL, one file per month: ${ADPORT_HOME}/audit/audit-YYYY-MM.jsonl */\nexport class AuditLog implements AuditEntryStore {\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, type AuditEntryStore } from './audit.js';\nimport { PendingStore, type PendingOperationStore } 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: PendingOperationStore = new PendingStore(),\n private readonly audit: AuditEntryStore = 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 continue_on_error: z.boolean().default(false).describe('Return successful providers plus per-provider errors instead of failing the whole read.'),\n }),\n annotations: { readOnly: true, openWorld: true },\n async handler(input, ctx) {\n const providers = selectConnectedProviders(ctx.providers, input.provider);\n const accounts: Account[] = [];\n const errors: Array<{ provider: string; message: string }> = [];\n for (const provider of providers) {\n try {\n accounts.push(...(await provider.listAccounts()));\n } catch (error) {\n if (!input.continue_on_error) throw error;\n errors.push({ provider: provider.id, message: error instanceof Error ? error.message : String(error) });\n }\n }\n return { accounts, errors };\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 continue_on_error: z.boolean().default(false).describe('Return successful providers plus per-provider errors instead of failing the whole read.'),\n }),\n annotations: { readOnly: true, openWorld: 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 const errors: Array<{ provider: string; message: string }> = [];\n for (const provider of providers) {\n try {\n const report = await provider.report(query);\n rows.push(...report.rows);\n } catch (error) {\n if (!input.continue_on_error) throw error;\n errors.push({ provider: provider.id, message: error instanceof Error ? error.message : String(error) });\n }\n }\n const truncated = rows.length > input.limit;\n return { rows: rows.slice(0, input.limit), truncated, errors };\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';\nimport type { FindingsRepository } from './audit/store.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 /** Hosted runtimes inject a tenant-scoped engine with durable database stores. */\n engine?: PolicyEngine;\n /** Optional hosted authorization boundary executed before every tool handler. */\n authorizeToolCall?: ToolContext['authorizeToolCall'];\n /** Hosted runtimes inject tenant-scoped finding persistence. */\n findings?: FindingsRepository;\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 = options.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 = {\n providers,\n engine,\n credentials,\n authorizeToolCall: options.authorizeToolCall,\n findings: options.findings,\n };\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"]}
|