@canonry/canonry 4.170.0 → 4.171.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/{chunk-NMCLLN5X.js → chunk-5KGN224W.js} +34 -3
- package/dist/{chunk-BMW3AURU.js → chunk-IIFDS3K2.js} +232 -0
- package/dist/{chunk-CCZNCH7Y.js → chunk-O226BLC7.js} +252 -3
- package/dist/{chunk-HTUI6BSK.js → chunk-RR4KSDOD.js} +1 -1
- package/dist/cli.js +689 -110
- package/dist/index.js +3 -3
- package/dist/{intelligence-service-64IPZ4NU.js → intelligence-service-KT6K4ODY.js} +1 -1
- package/dist/mcp.js +36 -3
- package/package.json +8 -8
package/dist/cli.js
CHANGED
|
@@ -26,11 +26,11 @@ import {
|
|
|
26
26
|
showFirstRunNotice,
|
|
27
27
|
trackCliCommandFinished,
|
|
28
28
|
trackEvent
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-5KGN224W.js";
|
|
30
30
|
import {
|
|
31
31
|
autoSyncSkills,
|
|
32
32
|
formatAutoSyncNotice
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-RR4KSDOD.js";
|
|
34
34
|
import {
|
|
35
35
|
CliError,
|
|
36
36
|
EXIT_SYSTEM_ERROR,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
saveConfigPatch,
|
|
56
56
|
systemError,
|
|
57
57
|
usageError
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-IIFDS3K2.js";
|
|
59
59
|
import {
|
|
60
60
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
61
61
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
projects,
|
|
70
70
|
queries,
|
|
71
71
|
renderReportHtml
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-O226BLC7.js";
|
|
73
73
|
import {
|
|
74
74
|
AdsDeliverySnapshotStatuses,
|
|
75
75
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -104,6 +104,9 @@ import {
|
|
|
104
104
|
adsPauseRequestSchema,
|
|
105
105
|
backlinkSourceSchema,
|
|
106
106
|
buildModelChangeNotice,
|
|
107
|
+
canonicalizeGtmAccountId,
|
|
108
|
+
canonicalizeGtmResourceSelection,
|
|
109
|
+
conversionTrackingContractWriteRequestSchema,
|
|
107
110
|
describeError,
|
|
108
111
|
discoveryBucketSchema,
|
|
109
112
|
discoveryCompetitorTypeSchema,
|
|
@@ -3880,9 +3883,9 @@ async function gaConnect(project, opts) {
|
|
|
3880
3883
|
propertyId: opts.propertyId
|
|
3881
3884
|
};
|
|
3882
3885
|
if (opts.keyFile) {
|
|
3883
|
-
const
|
|
3886
|
+
const fs20 = await import("fs");
|
|
3884
3887
|
try {
|
|
3885
|
-
const content =
|
|
3888
|
+
const content = fs20.readFileSync(opts.keyFile, "utf-8");
|
|
3886
3889
|
JSON.parse(content);
|
|
3887
3890
|
body.keyJson = content;
|
|
3888
3891
|
} catch (e) {
|
|
@@ -5233,6 +5236,581 @@ var GBP_CLI_COMMANDS = [
|
|
|
5233
5236
|
}
|
|
5234
5237
|
];
|
|
5235
5238
|
|
|
5239
|
+
// src/commands/google-marketing.ts
|
|
5240
|
+
import fs4 from "fs";
|
|
5241
|
+
function printMachine(value, format) {
|
|
5242
|
+
if (!isMachineFormat(format)) return false;
|
|
5243
|
+
console.log(JSON.stringify(value, null, 2));
|
|
5244
|
+
return true;
|
|
5245
|
+
}
|
|
5246
|
+
function connectionSummary(status) {
|
|
5247
|
+
if (!status.connected) return "not connected";
|
|
5248
|
+
if (status.status === "selection-required") return "connected; selection required";
|
|
5249
|
+
return status.status === "stale" ? "connected; stored evidence is stale" : "connected";
|
|
5250
|
+
}
|
|
5251
|
+
function snapshotSummary(snapshot) {
|
|
5252
|
+
return `${snapshot.capturedAt} ${snapshot.kind.padEnd(22)} ${snapshot.id} ${snapshot.payloadChecksum.slice(0, 12)}`;
|
|
5253
|
+
}
|
|
5254
|
+
function canonicalGtmReadAccountId(accountId) {
|
|
5255
|
+
const canonical = canonicalizeGtmAccountId(accountId);
|
|
5256
|
+
if (canonical) return canonical;
|
|
5257
|
+
throw new CliError({
|
|
5258
|
+
code: "GTM_RESOURCE_INPUT_INVALID",
|
|
5259
|
+
message: "GTM account must be a safe bare ID or an accounts/{id} resource path.",
|
|
5260
|
+
displayMessage: "Error: GTM account must be a safe bare ID or an accounts/{id} resource path."
|
|
5261
|
+
});
|
|
5262
|
+
}
|
|
5263
|
+
function canonicalGtmReadSelection(accountId, containerId) {
|
|
5264
|
+
const canonical = canonicalizeGtmResourceSelection({ accountId, containerId });
|
|
5265
|
+
if (canonical) return canonical;
|
|
5266
|
+
throw new CliError({
|
|
5267
|
+
code: "GTM_RESOURCE_INPUT_INVALID",
|
|
5268
|
+
message: "GTM account and container must be matching safe IDs or resource paths.",
|
|
5269
|
+
displayMessage: "Error: GTM account and container must be matching safe IDs or resource paths."
|
|
5270
|
+
});
|
|
5271
|
+
}
|
|
5272
|
+
function readConversionTrackingContractInput(inputPath) {
|
|
5273
|
+
if (!inputPath) {
|
|
5274
|
+
throw new CliError({
|
|
5275
|
+
code: "CONVERSION_TRACKING_INPUT_REQUIRED",
|
|
5276
|
+
message: "A conversion-tracking contract JSON input file is required",
|
|
5277
|
+
displayMessage: "Error: --input <json-file> is required (use --input - for stdin)"
|
|
5278
|
+
});
|
|
5279
|
+
}
|
|
5280
|
+
try {
|
|
5281
|
+
const raw = fs4.readFileSync(inputPath === "-" ? 0 : inputPath, "utf8");
|
|
5282
|
+
return conversionTrackingContractWriteRequestSchema.parse(JSON.parse(raw));
|
|
5283
|
+
} catch (err) {
|
|
5284
|
+
const message = describeError(err);
|
|
5285
|
+
throw new CliError({
|
|
5286
|
+
code: "CONVERSION_TRACKING_INPUT_INVALID",
|
|
5287
|
+
message,
|
|
5288
|
+
displayMessage: `Error: invalid conversion-tracking contract input (${message})`,
|
|
5289
|
+
details: { inputPath }
|
|
5290
|
+
});
|
|
5291
|
+
}
|
|
5292
|
+
}
|
|
5293
|
+
async function googleAdsDisconnect(client, project, opts) {
|
|
5294
|
+
const result = await client.disconnectGoogleAds(project);
|
|
5295
|
+
if (printMachine(result, opts.format)) return;
|
|
5296
|
+
console.log(result.disconnected ? `Disconnected Google Ads from project "${project}". Stored redacted evidence was retained.` : `Google Ads was not connected to project "${project}".`);
|
|
5297
|
+
}
|
|
5298
|
+
async function gtmDisconnect(client, project, opts) {
|
|
5299
|
+
const result = await client.disconnectGtm(project);
|
|
5300
|
+
if (printMachine(result, opts.format)) return;
|
|
5301
|
+
console.log(result.disconnected ? `Disconnected Google Tag Manager from project "${project}". Stored redacted evidence was retained.` : `Google Tag Manager was not connected to project "${project}".`);
|
|
5302
|
+
}
|
|
5303
|
+
async function googleAdsStatus(client, project, opts) {
|
|
5304
|
+
const result = await client.getGoogleAdsStatus(project);
|
|
5305
|
+
if (printMachine(result, opts.format)) return;
|
|
5306
|
+
console.log(`Google Ads: ${connectionSummary(result)}`);
|
|
5307
|
+
if (!result.connected) {
|
|
5308
|
+
console.log(`Open project "${project}" in the Canonry dashboard to authorize Google Ads.`);
|
|
5309
|
+
return;
|
|
5310
|
+
}
|
|
5311
|
+
const selection = result.connection.selection;
|
|
5312
|
+
console.log(`Customer: ${selection.customerId ?? "not selected"}`);
|
|
5313
|
+
if (selection.loginCustomerId) console.log(`Login customer: ${selection.loginCustomerId}`);
|
|
5314
|
+
if (result.selectedCustomer) {
|
|
5315
|
+
console.log(`Selected: ${result.selectedCustomer.descriptiveName ?? result.selectedCustomer.customerId} (${result.selectedCustomer.status})`);
|
|
5316
|
+
}
|
|
5317
|
+
console.log(`Last inventory snapshot: ${result.connection.lastInventorySnapshotAt ?? "none"}`);
|
|
5318
|
+
console.log(`Last metrics snapshot: ${result.connection.lastMetricsSnapshotAt ?? "none"}`);
|
|
5319
|
+
}
|
|
5320
|
+
async function gtmStatus(client, project, opts) {
|
|
5321
|
+
const result = await client.getGtmStatus(project);
|
|
5322
|
+
if (printMachine(result, opts.format)) return;
|
|
5323
|
+
console.log(`Google Tag Manager: ${connectionSummary(result)}`);
|
|
5324
|
+
if (!result.connected) {
|
|
5325
|
+
console.log(`Open project "${project}" in the Canonry dashboard to authorize Google Tag Manager.`);
|
|
5326
|
+
return;
|
|
5327
|
+
}
|
|
5328
|
+
console.log(`Account: ${result.selection.accountId ?? "not selected"}`);
|
|
5329
|
+
console.log(`Container: ${result.selection.containerId ?? "not selected"}`);
|
|
5330
|
+
console.log(`Workspace: ${result.selection.workspaceId ?? "none (live only)"}`);
|
|
5331
|
+
console.log(`Last snapshot: ${result.connection.lastSnapshotAt ?? "none"}`);
|
|
5332
|
+
}
|
|
5333
|
+
async function googleAdsCustomers(client, project, opts) {
|
|
5334
|
+
const result = await client.listGoogleAdsCustomers(project);
|
|
5335
|
+
if (opts.format === "jsonl") {
|
|
5336
|
+
emitJsonl(result.customers.map((customer) => ({ project, fetchedAt: result.fetchedAt, ...customer })));
|
|
5337
|
+
return;
|
|
5338
|
+
}
|
|
5339
|
+
if (printMachine(result, opts.format)) return;
|
|
5340
|
+
if (result.customers.length === 0) {
|
|
5341
|
+
console.log("No Google Ads customers are visible to this OAuth connection.");
|
|
5342
|
+
return;
|
|
5343
|
+
}
|
|
5344
|
+
console.log(`${result.totalAccessible} accessible customer(s)${result.truncated ? " (bounded list; truncated)" : ""}:
|
|
5345
|
+
`);
|
|
5346
|
+
for (const customer of result.customers) {
|
|
5347
|
+
const role = customer.manager ? "manager" : "client";
|
|
5348
|
+
const name = customer.descriptiveName ?? "(unnamed)";
|
|
5349
|
+
console.log(` ${customer.customerId.padEnd(16)} ${name} ${role}, ${customer.status}`);
|
|
5350
|
+
}
|
|
5351
|
+
console.log(`
|
|
5352
|
+
Select one with: canonry google-ads select ${project} --customer <customer-id>`);
|
|
5353
|
+
}
|
|
5354
|
+
async function googleAdsSelect(client, project, request, opts) {
|
|
5355
|
+
const result = await client.setGoogleAdsSelection(project, request);
|
|
5356
|
+
if (printMachine(result, opts.format)) return;
|
|
5357
|
+
console.log(`Selected Google Ads customer ${request.customerId}${request.loginCustomerId ? ` through login customer ${request.loginCustomerId}` : ""}.`);
|
|
5358
|
+
console.log(`Run \`canonry google-ads sync ${project}\` to capture read-only conversion and goal evidence.`);
|
|
5359
|
+
}
|
|
5360
|
+
async function googleAdsSync(client, project, opts) {
|
|
5361
|
+
const run = await client.triggerGoogleAdsSync(project);
|
|
5362
|
+
if (printMachine(run, opts.format)) return;
|
|
5363
|
+
console.log(`Google Ads read-only sync queued (run ${run.id}). Use \`canonry run show ${run.id}\` to check it.`);
|
|
5364
|
+
}
|
|
5365
|
+
async function googleAdsSnapshots(client, project, opts) {
|
|
5366
|
+
const result = await client.listGoogleAdsSnapshots(project, { limit: opts.limit, cursor: opts.cursor });
|
|
5367
|
+
if (opts.format === "jsonl") {
|
|
5368
|
+
emitJsonl(result.snapshots.map((snapshot) => ({ project, ...snapshot })));
|
|
5369
|
+
return;
|
|
5370
|
+
}
|
|
5371
|
+
if (printMachine(result, opts.format)) return;
|
|
5372
|
+
if (result.snapshots.length === 0) {
|
|
5373
|
+
console.log(`No stored Google Ads snapshots. Run \`canonry google-ads sync ${project}\` after selecting a customer.`);
|
|
5374
|
+
return;
|
|
5375
|
+
}
|
|
5376
|
+
console.log(`${result.total} stored Google Ads snapshot(s):
|
|
5377
|
+
`);
|
|
5378
|
+
for (const snapshot of result.snapshots) console.log(` ${snapshotSummary(snapshot)}`);
|
|
5379
|
+
if (result.nextCursor) console.log(`
|
|
5380
|
+
Next cursor: ${result.nextCursor}`);
|
|
5381
|
+
}
|
|
5382
|
+
async function googleAdsSnapshot(client, project, snapshotId, opts) {
|
|
5383
|
+
const result = await client.getGoogleAdsSnapshot(project, snapshotId);
|
|
5384
|
+
if (printMachine(result, opts.format)) return;
|
|
5385
|
+
const { metadata, payload } = result.snapshot;
|
|
5386
|
+
console.log(`Google Ads ${metadata.kind} snapshot ${metadata.id}`);
|
|
5387
|
+
console.log(`Captured: ${metadata.capturedAt}`);
|
|
5388
|
+
console.log(`Checksum: ${metadata.payloadChecksum}`);
|
|
5389
|
+
console.log(`Payload kind: ${payload.kind}`);
|
|
5390
|
+
}
|
|
5391
|
+
async function gtmAccounts(client, project, opts) {
|
|
5392
|
+
const result = await client.listGtmAccounts(project);
|
|
5393
|
+
if (opts.format === "jsonl") {
|
|
5394
|
+
emitJsonl(result.accounts.map((account) => ({ project, fetchedAt: result.fetchedAt, ...account })));
|
|
5395
|
+
return;
|
|
5396
|
+
}
|
|
5397
|
+
if (printMachine(result, opts.format)) return;
|
|
5398
|
+
if (result.accounts.length === 0) {
|
|
5399
|
+
console.log("No GTM accounts are visible to this OAuth connection.");
|
|
5400
|
+
return;
|
|
5401
|
+
}
|
|
5402
|
+
console.log(`${result.totalAccessible} accessible GTM account(s)${result.truncated ? " (bounded list; truncated)" : ""}:
|
|
5403
|
+
`);
|
|
5404
|
+
for (const account of result.accounts) console.log(` ${account.id.padEnd(16)} ${account.name}`);
|
|
5405
|
+
console.log(`
|
|
5406
|
+
Discover containers with: canonry gtm containers ${project} --account <account-id>`);
|
|
5407
|
+
}
|
|
5408
|
+
async function gtmContainers(client, project, accountId, opts) {
|
|
5409
|
+
const canonicalAccountId = canonicalGtmReadAccountId(accountId);
|
|
5410
|
+
const result = await client.listGtmContainers(project, canonicalAccountId);
|
|
5411
|
+
if (opts.format === "jsonl") {
|
|
5412
|
+
emitJsonl(result.containers.map((container) => ({ project, fetchedAt: result.fetchedAt, ...container })));
|
|
5413
|
+
return;
|
|
5414
|
+
}
|
|
5415
|
+
if (printMachine(result, opts.format)) return;
|
|
5416
|
+
if (result.containers.length === 0) {
|
|
5417
|
+
console.log(`No GTM containers are visible under account ${accountId}.`);
|
|
5418
|
+
return;
|
|
5419
|
+
}
|
|
5420
|
+
console.log(`${result.totalAccessible} GTM container(s)${result.truncated ? " (bounded list; truncated)" : ""}:
|
|
5421
|
+
`);
|
|
5422
|
+
for (const container of result.containers) {
|
|
5423
|
+
const publicId = container.publicId ? ` (${container.publicId})` : "";
|
|
5424
|
+
console.log(` ${container.id.padEnd(16)} ${container.name}${publicId}`);
|
|
5425
|
+
}
|
|
5426
|
+
console.log(`
|
|
5427
|
+
Discover workspaces with: canonry gtm workspaces ${project} --account ${accountId} --container <container-id>`);
|
|
5428
|
+
}
|
|
5429
|
+
async function gtmWorkspaces(client, project, accountId, containerId, opts) {
|
|
5430
|
+
const selection = canonicalGtmReadSelection(accountId, containerId);
|
|
5431
|
+
const result = await client.listGtmWorkspaces(project, selection.accountId, selection.containerId);
|
|
5432
|
+
if (opts.format === "jsonl") {
|
|
5433
|
+
emitJsonl(result.workspaces.map((workspace) => ({ project, fetchedAt: result.fetchedAt, ...workspace })));
|
|
5434
|
+
return;
|
|
5435
|
+
}
|
|
5436
|
+
if (printMachine(result, opts.format)) return;
|
|
5437
|
+
if (result.workspaces.length === 0) {
|
|
5438
|
+
console.log(`No GTM workspaces are visible for container ${containerId}. A sync can still capture the live container graph.`);
|
|
5439
|
+
return;
|
|
5440
|
+
}
|
|
5441
|
+
console.log(`${result.totalAccessible} GTM workspace(s)${result.truncated ? " (bounded list; truncated)" : ""}:
|
|
5442
|
+
`);
|
|
5443
|
+
for (const workspace of result.workspaces) console.log(` ${workspace.id.padEnd(16)} ${workspace.name}`);
|
|
5444
|
+
}
|
|
5445
|
+
async function gtmSelect(client, project, request, opts) {
|
|
5446
|
+
const result = await client.setGtmSelection(project, request);
|
|
5447
|
+
if (printMachine(result, opts.format)) return;
|
|
5448
|
+
console.log(`Selected GTM account ${request.accountId}, container ${request.containerId}${request.workspaceId ? `, and workspace ${request.workspaceId}` : ""}.`);
|
|
5449
|
+
console.log(`Run \`canonry gtm sync ${project}\` to capture redacted live${request.workspaceId ? " and draft" : ""} evidence.`);
|
|
5450
|
+
}
|
|
5451
|
+
async function gtmSync(client, project, opts) {
|
|
5452
|
+
const run = await client.triggerGtmSync(project);
|
|
5453
|
+
if (printMachine(run, opts.format)) return;
|
|
5454
|
+
console.log(`GTM read-only sync queued (run ${run.id}). Use \`canonry run show ${run.id}\` to check it.`);
|
|
5455
|
+
}
|
|
5456
|
+
async function gtmSnapshots(client, project, opts) {
|
|
5457
|
+
const result = await client.listGtmSnapshots(project, { limit: opts.limit, cursor: opts.cursor });
|
|
5458
|
+
if (opts.format === "jsonl") {
|
|
5459
|
+
emitJsonl(result.snapshots.map((snapshot) => ({ project, ...snapshot })));
|
|
5460
|
+
return;
|
|
5461
|
+
}
|
|
5462
|
+
if (printMachine(result, opts.format)) return;
|
|
5463
|
+
if (result.snapshots.length === 0) {
|
|
5464
|
+
console.log(`No stored GTM snapshots. Run \`canonry gtm sync ${project}\` after selecting a container.`);
|
|
5465
|
+
return;
|
|
5466
|
+
}
|
|
5467
|
+
console.log(`${result.total} stored GTM snapshot(s):
|
|
5468
|
+
`);
|
|
5469
|
+
for (const snapshot of result.snapshots) console.log(` ${snapshotSummary(snapshot)}`);
|
|
5470
|
+
if (result.nextCursor) console.log(`
|
|
5471
|
+
Next cursor: ${result.nextCursor}`);
|
|
5472
|
+
}
|
|
5473
|
+
async function gtmSnapshot(client, project, snapshotId, opts) {
|
|
5474
|
+
const result = await client.getGtmSnapshot(project, snapshotId);
|
|
5475
|
+
if (printMachine(result, opts.format)) return;
|
|
5476
|
+
const { metadata, payload } = result.snapshot;
|
|
5477
|
+
console.log(`GTM ${metadata.kind} snapshot ${metadata.id}`);
|
|
5478
|
+
console.log(`Captured: ${metadata.capturedAt}`);
|
|
5479
|
+
console.log(`Checksum: ${metadata.payloadChecksum}`);
|
|
5480
|
+
console.log(`Payload kind: ${payload.kind}`);
|
|
5481
|
+
}
|
|
5482
|
+
async function conversionTrackingContracts(client, project, opts) {
|
|
5483
|
+
const contracts = await client.listConversionTrackingContracts(project);
|
|
5484
|
+
if (opts.format === "jsonl") {
|
|
5485
|
+
emitJsonl(contracts.map((contract) => ({ project, ...contract })));
|
|
5486
|
+
return;
|
|
5487
|
+
}
|
|
5488
|
+
if (printMachine(contracts, opts.format)) return;
|
|
5489
|
+
if (contracts.length === 0) {
|
|
5490
|
+
console.log("No conversion-tracking contracts are declared for this project.");
|
|
5491
|
+
return;
|
|
5492
|
+
}
|
|
5493
|
+
console.log(`${contracts.length} conversion-tracking contract(s):
|
|
5494
|
+
`);
|
|
5495
|
+
for (const contract of contracts) {
|
|
5496
|
+
console.log(` ${contract.id.padEnd(16)} ${contract.name} event=${contract.eventName}`);
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
async function conversionTrackingContract(client, project, contractId, opts) {
|
|
5500
|
+
const contract = await client.getConversionTrackingContract(project, contractId);
|
|
5501
|
+
if (printMachine(contract, opts.format)) return;
|
|
5502
|
+
printConversionTrackingContract(contract);
|
|
5503
|
+
}
|
|
5504
|
+
function printConversionTrackingContract(contract) {
|
|
5505
|
+
console.log(`Conversion contract: ${contract.name} (${contract.id})`);
|
|
5506
|
+
console.log(`Event: ${contract.eventName}`);
|
|
5507
|
+
console.log(`Google Ads: customer ${contract.googleAds.customerId}, conversion action ${contract.googleAds.conversionActionId}`);
|
|
5508
|
+
console.log(`GTM: account ${contract.gtm.accountId}, container ${contract.gtm.containerId}, tag ${contract.gtm.tagId}`);
|
|
5509
|
+
console.log(`Runtime verification: ${contract.runtime.verificationRequired ? "required" : "not required"}`);
|
|
5510
|
+
}
|
|
5511
|
+
async function conversionTrackingCreate(client, project, request, opts) {
|
|
5512
|
+
const contract = await client.createConversionTrackingContract(project, request);
|
|
5513
|
+
if (printMachine(contract, opts.format)) return;
|
|
5514
|
+
console.log(`Created conversion-tracking contract "${contract.name}" (${contract.id}).`);
|
|
5515
|
+
}
|
|
5516
|
+
async function conversionTrackingUpdate(client, project, contractId, request, opts) {
|
|
5517
|
+
const contract = await client.updateConversionTrackingContract(project, contractId, request);
|
|
5518
|
+
if (printMachine(contract, opts.format)) return;
|
|
5519
|
+
console.log(`Updated conversion-tracking contract "${contract.name}" (${contract.id}).`);
|
|
5520
|
+
}
|
|
5521
|
+
async function conversionTrackingDelete(client, project, contractId, opts) {
|
|
5522
|
+
await client.deleteConversionTrackingContract(project, contractId);
|
|
5523
|
+
if (printMachine({ project, contractId, deleted: true }, opts.format)) return;
|
|
5524
|
+
console.log(`Deleted conversion-tracking contract ${contractId}.`);
|
|
5525
|
+
}
|
|
5526
|
+
async function conversionTrackingIntegrity(client, project, contractId, opts) {
|
|
5527
|
+
const result = await client.getConversionTrackingIntegrity(project, contractId);
|
|
5528
|
+
if (opts.format === "jsonl") {
|
|
5529
|
+
emitJsonl(result.assessment.findings.map((finding) => ({
|
|
5530
|
+
project,
|
|
5531
|
+
contractId: result.assessment.contract.id,
|
|
5532
|
+
integrityStatus: result.assessment.status,
|
|
5533
|
+
evaluatedAt: result.assessment.evaluatedAt,
|
|
5534
|
+
...finding
|
|
5535
|
+
})));
|
|
5536
|
+
return;
|
|
5537
|
+
}
|
|
5538
|
+
if (printMachine(result, opts.format)) return;
|
|
5539
|
+
console.log(`Conversion integrity: ${result.assessment.contract.name} \u2014 ${result.assessment.status}`);
|
|
5540
|
+
console.log(`Evaluated: ${result.assessment.evaluatedAt}`);
|
|
5541
|
+
for (const finding of result.assessment.findings) {
|
|
5542
|
+
console.log(` ${finding.outcome.toUpperCase().padEnd(7)} ${finding.code} \u2014 ${finding.subject}`);
|
|
5543
|
+
}
|
|
5544
|
+
if (result.assessment.status === "runtime-unverified") {
|
|
5545
|
+
console.log("\nStatic configuration is consistent, but a GTM API snapshot cannot prove that the website event fired or Google Ads observed a conversion.");
|
|
5546
|
+
}
|
|
5547
|
+
}
|
|
5548
|
+
|
|
5549
|
+
// src/cli-commands/google-marketing.ts
|
|
5550
|
+
function snapshotLimit(input, command, usage) {
|
|
5551
|
+
const limit = parseIntegerOption(input, "limit", {
|
|
5552
|
+
command,
|
|
5553
|
+
usage,
|
|
5554
|
+
message: "--limit must be an integer from 1 to 100"
|
|
5555
|
+
});
|
|
5556
|
+
if (limit !== void 0 && (limit < 1 || limit > 100)) {
|
|
5557
|
+
throw usageError(`Error: --limit must be an integer from 1 to 100
|
|
5558
|
+
Usage: ${usage}`, {
|
|
5559
|
+
message: "--limit must be an integer from 1 to 100",
|
|
5560
|
+
details: { command, usage, option: "limit", value: limit }
|
|
5561
|
+
});
|
|
5562
|
+
}
|
|
5563
|
+
return limit;
|
|
5564
|
+
}
|
|
5565
|
+
function createGoogleMarketingCliCommands(createClient2) {
|
|
5566
|
+
return [
|
|
5567
|
+
{
|
|
5568
|
+
path: ["google-ads", "disconnect"],
|
|
5569
|
+
usage: "canonry google-ads disconnect <project> [--format json]",
|
|
5570
|
+
run: async (input) => {
|
|
5571
|
+
const usage = "canonry google-ads disconnect <project> [--format json]";
|
|
5572
|
+
await googleAdsDisconnect(createClient2(), requireProject(input, "google-ads.disconnect", usage), { format: input.format });
|
|
5573
|
+
}
|
|
5574
|
+
},
|
|
5575
|
+
{
|
|
5576
|
+
path: ["google-ads", "status"],
|
|
5577
|
+
usage: "canonry google-ads status <project> [--format json]",
|
|
5578
|
+
run: async (input) => {
|
|
5579
|
+
const usage = "canonry google-ads status <project> [--format json]";
|
|
5580
|
+
await googleAdsStatus(createClient2(), requireProject(input, "google-ads.status", usage), { format: input.format });
|
|
5581
|
+
}
|
|
5582
|
+
},
|
|
5583
|
+
{
|
|
5584
|
+
path: ["google-ads", "customers"],
|
|
5585
|
+
usage: "canonry google-ads customers <project> [--format json|jsonl]",
|
|
5586
|
+
run: async (input) => {
|
|
5587
|
+
const usage = "canonry google-ads customers <project> [--format json|jsonl]";
|
|
5588
|
+
await googleAdsCustomers(createClient2(), requireProject(input, "google-ads.customers", usage), { format: input.format });
|
|
5589
|
+
}
|
|
5590
|
+
},
|
|
5591
|
+
{
|
|
5592
|
+
path: ["google-ads", "select"],
|
|
5593
|
+
usage: "canonry google-ads select <project> --customer <customer-id> [--login-customer <manager-id>] [--format json]",
|
|
5594
|
+
options: { customer: stringOption(), "login-customer": stringOption() },
|
|
5595
|
+
run: async (input) => {
|
|
5596
|
+
const usage = "canonry google-ads select <project> --customer <customer-id> [--login-customer <manager-id>] [--format json]";
|
|
5597
|
+
const project = requireProject(input, "google-ads.select", usage);
|
|
5598
|
+
const customerId = requireStringOption(input, "customer", {
|
|
5599
|
+
command: "google-ads.select",
|
|
5600
|
+
usage,
|
|
5601
|
+
message: "--customer is required"
|
|
5602
|
+
});
|
|
5603
|
+
await googleAdsSelect(createClient2(), project, {
|
|
5604
|
+
customerId,
|
|
5605
|
+
...getString(input.values, "login-customer") ? { loginCustomerId: getString(input.values, "login-customer") } : {}
|
|
5606
|
+
}, { format: input.format });
|
|
5607
|
+
}
|
|
5608
|
+
},
|
|
5609
|
+
{
|
|
5610
|
+
path: ["google-ads", "sync"],
|
|
5611
|
+
usage: "canonry google-ads sync <project> [--format json]",
|
|
5612
|
+
run: async (input) => {
|
|
5613
|
+
const usage = "canonry google-ads sync <project> [--format json]";
|
|
5614
|
+
await googleAdsSync(createClient2(), requireProject(input, "google-ads.sync", usage), { format: input.format });
|
|
5615
|
+
}
|
|
5616
|
+
},
|
|
5617
|
+
{
|
|
5618
|
+
path: ["google-ads", "snapshots"],
|
|
5619
|
+
usage: "canonry google-ads snapshots <project> [--limit <n>] [--cursor <opaque>] [--format json|jsonl]",
|
|
5620
|
+
options: { limit: stringOption(), cursor: stringOption() },
|
|
5621
|
+
run: async (input) => {
|
|
5622
|
+
const usage = "canonry google-ads snapshots <project> [--limit <n>] [--cursor <opaque>] [--format json|jsonl]";
|
|
5623
|
+
await googleAdsSnapshots(createClient2(), requireProject(input, "google-ads.snapshots", usage), {
|
|
5624
|
+
limit: snapshotLimit(input, "google-ads.snapshots", usage),
|
|
5625
|
+
cursor: getString(input.values, "cursor"),
|
|
5626
|
+
format: input.format
|
|
5627
|
+
});
|
|
5628
|
+
}
|
|
5629
|
+
},
|
|
5630
|
+
{
|
|
5631
|
+
path: ["google-ads", "snapshot"],
|
|
5632
|
+
usage: "canonry google-ads snapshot <project> <snapshot-id> [--format json]",
|
|
5633
|
+
run: async (input) => {
|
|
5634
|
+
const usage = "canonry google-ads snapshot <project> <snapshot-id> [--format json]";
|
|
5635
|
+
const project = requireProject(input, "google-ads.snapshot", usage);
|
|
5636
|
+
await googleAdsSnapshot(createClient2(), project, requirePositional(input, 1, {
|
|
5637
|
+
command: "google-ads.snapshot",
|
|
5638
|
+
usage,
|
|
5639
|
+
message: "snapshot id is required"
|
|
5640
|
+
}), { format: input.format });
|
|
5641
|
+
}
|
|
5642
|
+
},
|
|
5643
|
+
{
|
|
5644
|
+
path: ["gtm", "disconnect"],
|
|
5645
|
+
usage: "canonry gtm disconnect <project> [--format json]",
|
|
5646
|
+
run: async (input) => {
|
|
5647
|
+
const usage = "canonry gtm disconnect <project> [--format json]";
|
|
5648
|
+
await gtmDisconnect(createClient2(), requireProject(input, "gtm.disconnect", usage), { format: input.format });
|
|
5649
|
+
}
|
|
5650
|
+
},
|
|
5651
|
+
{
|
|
5652
|
+
path: ["gtm", "status"],
|
|
5653
|
+
usage: "canonry gtm status <project> [--format json]",
|
|
5654
|
+
run: async (input) => {
|
|
5655
|
+
const usage = "canonry gtm status <project> [--format json]";
|
|
5656
|
+
await gtmStatus(createClient2(), requireProject(input, "gtm.status", usage), { format: input.format });
|
|
5657
|
+
}
|
|
5658
|
+
},
|
|
5659
|
+
{
|
|
5660
|
+
path: ["gtm", "accounts"],
|
|
5661
|
+
usage: "canonry gtm accounts <project> [--format json|jsonl]",
|
|
5662
|
+
run: async (input) => {
|
|
5663
|
+
const usage = "canonry gtm accounts <project> [--format json|jsonl]";
|
|
5664
|
+
await gtmAccounts(createClient2(), requireProject(input, "gtm.accounts", usage), { format: input.format });
|
|
5665
|
+
}
|
|
5666
|
+
},
|
|
5667
|
+
{
|
|
5668
|
+
path: ["gtm", "containers"],
|
|
5669
|
+
usage: "canonry gtm containers <project> --account <account-id> [--format json|jsonl]",
|
|
5670
|
+
options: { account: stringOption() },
|
|
5671
|
+
run: async (input) => {
|
|
5672
|
+
const usage = "canonry gtm containers <project> --account <account-id> [--format json|jsonl]";
|
|
5673
|
+
const project = requireProject(input, "gtm.containers", usage);
|
|
5674
|
+
await gtmContainers(createClient2(), project, requireStringOption(input, "account", {
|
|
5675
|
+
command: "gtm.containers",
|
|
5676
|
+
usage,
|
|
5677
|
+
message: "--account is required"
|
|
5678
|
+
}), { format: input.format });
|
|
5679
|
+
}
|
|
5680
|
+
},
|
|
5681
|
+
{
|
|
5682
|
+
path: ["gtm", "workspaces"],
|
|
5683
|
+
usage: "canonry gtm workspaces <project> --account <account-id> --container <container-id> [--format json|jsonl]",
|
|
5684
|
+
options: { account: stringOption(), container: stringOption() },
|
|
5685
|
+
run: async (input) => {
|
|
5686
|
+
const usage = "canonry gtm workspaces <project> --account <account-id> --container <container-id> [--format json|jsonl]";
|
|
5687
|
+
const project = requireProject(input, "gtm.workspaces", usage);
|
|
5688
|
+
const accountId = requireStringOption(input, "account", { command: "gtm.workspaces", usage, message: "--account is required" });
|
|
5689
|
+
const containerId = requireStringOption(input, "container", { command: "gtm.workspaces", usage, message: "--container is required" });
|
|
5690
|
+
await gtmWorkspaces(createClient2(), project, accountId, containerId, { format: input.format });
|
|
5691
|
+
}
|
|
5692
|
+
},
|
|
5693
|
+
{
|
|
5694
|
+
path: ["gtm", "select"],
|
|
5695
|
+
usage: "canonry gtm select <project> --account <account-id> --container <container-id> [--workspace <workspace-id>] [--format json]",
|
|
5696
|
+
options: { account: stringOption(), container: stringOption(), workspace: stringOption() },
|
|
5697
|
+
run: async (input) => {
|
|
5698
|
+
const usage = "canonry gtm select <project> --account <account-id> --container <container-id> [--workspace <workspace-id>] [--format json]";
|
|
5699
|
+
const project = requireProject(input, "gtm.select", usage);
|
|
5700
|
+
const accountId = requireStringOption(input, "account", { command: "gtm.select", usage, message: "--account is required" });
|
|
5701
|
+
const containerId = requireStringOption(input, "container", { command: "gtm.select", usage, message: "--container is required" });
|
|
5702
|
+
const workspaceId = getString(input.values, "workspace");
|
|
5703
|
+
await gtmSelect(createClient2(), project, {
|
|
5704
|
+
accountId,
|
|
5705
|
+
containerId,
|
|
5706
|
+
...workspaceId ? { workspaceId } : {}
|
|
5707
|
+
}, { format: input.format });
|
|
5708
|
+
}
|
|
5709
|
+
},
|
|
5710
|
+
{
|
|
5711
|
+
path: ["gtm", "sync"],
|
|
5712
|
+
usage: "canonry gtm sync <project> [--format json]",
|
|
5713
|
+
run: async (input) => {
|
|
5714
|
+
const usage = "canonry gtm sync <project> [--format json]";
|
|
5715
|
+
await gtmSync(createClient2(), requireProject(input, "gtm.sync", usage), { format: input.format });
|
|
5716
|
+
}
|
|
5717
|
+
},
|
|
5718
|
+
{
|
|
5719
|
+
path: ["gtm", "snapshots"],
|
|
5720
|
+
usage: "canonry gtm snapshots <project> [--limit <n>] [--cursor <opaque>] [--format json|jsonl]",
|
|
5721
|
+
options: { limit: stringOption(), cursor: stringOption() },
|
|
5722
|
+
run: async (input) => {
|
|
5723
|
+
const usage = "canonry gtm snapshots <project> [--limit <n>] [--cursor <opaque>] [--format json|jsonl]";
|
|
5724
|
+
await gtmSnapshots(createClient2(), requireProject(input, "gtm.snapshots", usage), {
|
|
5725
|
+
limit: snapshotLimit(input, "gtm.snapshots", usage),
|
|
5726
|
+
cursor: getString(input.values, "cursor"),
|
|
5727
|
+
format: input.format
|
|
5728
|
+
});
|
|
5729
|
+
}
|
|
5730
|
+
},
|
|
5731
|
+
{
|
|
5732
|
+
path: ["gtm", "snapshot"],
|
|
5733
|
+
usage: "canonry gtm snapshot <project> <snapshot-id> [--format json]",
|
|
5734
|
+
run: async (input) => {
|
|
5735
|
+
const usage = "canonry gtm snapshot <project> <snapshot-id> [--format json]";
|
|
5736
|
+
const project = requireProject(input, "gtm.snapshot", usage);
|
|
5737
|
+
await gtmSnapshot(createClient2(), project, requirePositional(input, 1, {
|
|
5738
|
+
command: "gtm.snapshot",
|
|
5739
|
+
usage,
|
|
5740
|
+
message: "snapshot id is required"
|
|
5741
|
+
}), { format: input.format });
|
|
5742
|
+
}
|
|
5743
|
+
},
|
|
5744
|
+
{
|
|
5745
|
+
path: ["conversion-tracking", "contracts"],
|
|
5746
|
+
usage: "canonry conversion-tracking contracts <project> [--format json|jsonl]",
|
|
5747
|
+
run: async (input) => {
|
|
5748
|
+
const usage = "canonry conversion-tracking contracts <project> [--format json|jsonl]";
|
|
5749
|
+
await conversionTrackingContracts(createClient2(), requireProject(input, "conversion-tracking.contracts", usage), { format: input.format });
|
|
5750
|
+
}
|
|
5751
|
+
},
|
|
5752
|
+
{
|
|
5753
|
+
path: ["conversion-tracking", "contracts", "get"],
|
|
5754
|
+
usage: "canonry conversion-tracking contracts get <project> <contract-id> [--format json]",
|
|
5755
|
+
run: async (input) => {
|
|
5756
|
+
const usage = "canonry conversion-tracking contracts get <project> <contract-id> [--format json]";
|
|
5757
|
+
const project = requireProject(input, "conversion-tracking.contracts.get", usage);
|
|
5758
|
+
await conversionTrackingContract(createClient2(), project, requirePositional(input, 1, {
|
|
5759
|
+
command: "conversion-tracking.contracts.get",
|
|
5760
|
+
usage,
|
|
5761
|
+
message: "contract id is required"
|
|
5762
|
+
}), { format: input.format });
|
|
5763
|
+
}
|
|
5764
|
+
},
|
|
5765
|
+
{
|
|
5766
|
+
path: ["conversion-tracking", "contracts", "create"],
|
|
5767
|
+
usage: "canonry conversion-tracking contracts create <project> --input <json-file|-> [--format json]",
|
|
5768
|
+
options: { input: stringOption() },
|
|
5769
|
+
run: async (input) => {
|
|
5770
|
+
const usage = "canonry conversion-tracking contracts create <project> --input <json-file|-> [--format json]";
|
|
5771
|
+
await conversionTrackingCreate(createClient2(), requireProject(input, "conversion-tracking.contracts.create", usage), readConversionTrackingContractInput(getString(input.values, "input")), { format: input.format });
|
|
5772
|
+
}
|
|
5773
|
+
},
|
|
5774
|
+
{
|
|
5775
|
+
path: ["conversion-tracking", "contracts", "update"],
|
|
5776
|
+
usage: "canonry conversion-tracking contracts update <project> <contract-id> --input <json-file|-> [--format json]",
|
|
5777
|
+
options: { input: stringOption() },
|
|
5778
|
+
run: async (input) => {
|
|
5779
|
+
const usage = "canonry conversion-tracking contracts update <project> <contract-id> --input <json-file|-> [--format json]";
|
|
5780
|
+
const project = requireProject(input, "conversion-tracking.contracts.update", usage);
|
|
5781
|
+
const contractId = requirePositional(input, 1, { command: "conversion-tracking.contracts.update", usage, message: "contract id is required" });
|
|
5782
|
+
await conversionTrackingUpdate(createClient2(), project, contractId, readConversionTrackingContractInput(getString(input.values, "input")), { format: input.format });
|
|
5783
|
+
}
|
|
5784
|
+
},
|
|
5785
|
+
{
|
|
5786
|
+
path: ["conversion-tracking", "contracts", "delete"],
|
|
5787
|
+
usage: "canonry conversion-tracking contracts delete <project> <contract-id> [--format json]",
|
|
5788
|
+
run: async (input) => {
|
|
5789
|
+
const usage = "canonry conversion-tracking contracts delete <project> <contract-id> [--format json]";
|
|
5790
|
+
const project = requireProject(input, "conversion-tracking.contracts.delete", usage);
|
|
5791
|
+
await conversionTrackingDelete(createClient2(), project, requirePositional(input, 1, {
|
|
5792
|
+
command: "conversion-tracking.contracts.delete",
|
|
5793
|
+
usage,
|
|
5794
|
+
message: "contract id is required"
|
|
5795
|
+
}), { format: input.format });
|
|
5796
|
+
}
|
|
5797
|
+
},
|
|
5798
|
+
{
|
|
5799
|
+
path: ["conversion-tracking", "contracts", "integrity"],
|
|
5800
|
+
usage: "canonry conversion-tracking contracts integrity <project> <contract-id> [--format json|jsonl]",
|
|
5801
|
+
run: async (input) => {
|
|
5802
|
+
const usage = "canonry conversion-tracking contracts integrity <project> <contract-id> [--format json|jsonl]";
|
|
5803
|
+
const project = requireProject(input, "conversion-tracking.contracts.integrity", usage);
|
|
5804
|
+
await conversionTrackingIntegrity(createClient2(), project, requirePositional(input, 1, {
|
|
5805
|
+
command: "conversion-tracking.contracts.integrity",
|
|
5806
|
+
usage,
|
|
5807
|
+
message: "contract id is required"
|
|
5808
|
+
}), { format: input.format });
|
|
5809
|
+
}
|
|
5810
|
+
}
|
|
5811
|
+
];
|
|
5812
|
+
}
|
|
5813
|
+
|
|
5236
5814
|
// src/commands/get.ts
|
|
5237
5815
|
var SOURCE_FETCHERS = {
|
|
5238
5816
|
overview: async (project) => createApiClient().getProjectOverview(project),
|
|
@@ -5336,12 +5914,12 @@ var GET_CLI_COMMANDS = [
|
|
|
5336
5914
|
];
|
|
5337
5915
|
|
|
5338
5916
|
// src/commands/traffic.ts
|
|
5339
|
-
import
|
|
5917
|
+
import fs6 from "fs";
|
|
5340
5918
|
|
|
5341
5919
|
// src/cloudflare-worker-deploy.ts
|
|
5342
5920
|
import { spawn } from "child_process";
|
|
5343
5921
|
import { randomUUID } from "crypto";
|
|
5344
|
-
import
|
|
5922
|
+
import fs5 from "fs";
|
|
5345
5923
|
import os from "os";
|
|
5346
5924
|
import path2 from "path";
|
|
5347
5925
|
import { stripVTControlCharacters } from "util";
|
|
@@ -5359,7 +5937,7 @@ function projectSlug(project) {
|
|
|
5359
5937
|
}
|
|
5360
5938
|
function lstatIfPresent(filePath) {
|
|
5361
5939
|
try {
|
|
5362
|
-
return
|
|
5940
|
+
return fs5.lstatSync(filePath);
|
|
5363
5941
|
} catch (error) {
|
|
5364
5942
|
if (error.code === "ENOENT") return null;
|
|
5365
5943
|
throw error;
|
|
@@ -5377,7 +5955,7 @@ function prepareCloudflareWorkerOutputDirectory(outputDirectory) {
|
|
|
5377
5955
|
throw new Error(`output directory is not a regular directory: ${resolved}`);
|
|
5378
5956
|
}
|
|
5379
5957
|
} else {
|
|
5380
|
-
|
|
5958
|
+
fs5.mkdirSync(resolved, { recursive: true, mode: 448 });
|
|
5381
5959
|
}
|
|
5382
5960
|
const artifacts = {
|
|
5383
5961
|
outputDirectory: resolved,
|
|
@@ -5390,7 +5968,7 @@ function prepareCloudflareWorkerOutputDirectory(outputDirectory) {
|
|
|
5390
5968
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
5391
5969
|
throw new Error(`artifact path is not a regular file: ${artifactPath}`);
|
|
5392
5970
|
}
|
|
5393
|
-
const contents =
|
|
5971
|
+
const contents = fs5.readFileSync(artifactPath, "utf-8");
|
|
5394
5972
|
if (!isRecognizablyCanonryGenerated(artifactPath, contents)) {
|
|
5395
5973
|
throw new Error(`refusing to overwrite an operator-owned artifact: ${artifactPath}`);
|
|
5396
5974
|
}
|
|
@@ -5403,7 +5981,7 @@ function readRegularArtifact(filePath) {
|
|
|
5403
5981
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
5404
5982
|
throw new Error(`artifact path is not a regular file: ${filePath}`);
|
|
5405
5983
|
}
|
|
5406
|
-
return
|
|
5984
|
+
return fs5.readFileSync(filePath, "utf-8");
|
|
5407
5985
|
}
|
|
5408
5986
|
function isRecognizablyCanonryGenerated(filePath, contents) {
|
|
5409
5987
|
if (path2.basename(filePath) === "worker.js") {
|
|
@@ -5420,22 +5998,22 @@ function writePrivateTemporaryFile(filePath, contents) {
|
|
|
5420
5998
|
path2.dirname(filePath),
|
|
5421
5999
|
`.${path2.basename(filePath)}.${randomUUID()}.tmp`
|
|
5422
6000
|
);
|
|
5423
|
-
const fd =
|
|
6001
|
+
const fd = fs5.openSync(temporaryPath, "wx", 384);
|
|
5424
6002
|
let closed = false;
|
|
5425
6003
|
try {
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
6004
|
+
fs5.writeFileSync(fd, contents, "utf-8");
|
|
6005
|
+
fs5.fsyncSync(fd);
|
|
6006
|
+
fs5.closeSync(fd);
|
|
5429
6007
|
closed = true;
|
|
5430
6008
|
} catch (error) {
|
|
5431
6009
|
if (!closed) {
|
|
5432
6010
|
try {
|
|
5433
|
-
|
|
6011
|
+
fs5.closeSync(fd);
|
|
5434
6012
|
} catch {
|
|
5435
6013
|
}
|
|
5436
6014
|
}
|
|
5437
6015
|
try {
|
|
5438
|
-
|
|
6016
|
+
fs5.unlinkSync(temporaryPath);
|
|
5439
6017
|
} catch {
|
|
5440
6018
|
}
|
|
5441
6019
|
throw error;
|
|
@@ -5469,10 +6047,10 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
5469
6047
|
throw new Error(`artifact changed during update: ${change.filePath}`);
|
|
5470
6048
|
}
|
|
5471
6049
|
if (change.previous === null) {
|
|
5472
|
-
|
|
5473
|
-
|
|
6050
|
+
fs5.linkSync(change.temporaryPath, change.filePath);
|
|
6051
|
+
fs5.unlinkSync(change.temporaryPath);
|
|
5474
6052
|
} else {
|
|
5475
|
-
|
|
6053
|
+
fs5.renameSync(change.temporaryPath, change.filePath);
|
|
5476
6054
|
}
|
|
5477
6055
|
applied.push(change);
|
|
5478
6056
|
}
|
|
@@ -5481,10 +6059,10 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
5481
6059
|
try {
|
|
5482
6060
|
if (readRegularArtifact(change.filePath) !== change.contents) continue;
|
|
5483
6061
|
if (change.previous === null) {
|
|
5484
|
-
|
|
6062
|
+
fs5.unlinkSync(change.filePath);
|
|
5485
6063
|
} else {
|
|
5486
6064
|
const restorePath = writePrivateTemporaryFile(change.filePath, change.previous);
|
|
5487
|
-
|
|
6065
|
+
fs5.renameSync(restorePath, change.filePath);
|
|
5488
6066
|
}
|
|
5489
6067
|
} catch {
|
|
5490
6068
|
}
|
|
@@ -5493,7 +6071,7 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
5493
6071
|
} finally {
|
|
5494
6072
|
for (const change of pending) {
|
|
5495
6073
|
try {
|
|
5496
|
-
if (
|
|
6074
|
+
if (fs5.existsSync(change.temporaryPath)) fs5.unlinkSync(change.temporaryPath);
|
|
5497
6075
|
} catch {
|
|
5498
6076
|
}
|
|
5499
6077
|
}
|
|
@@ -5579,7 +6157,7 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
5579
6157
|
if (missing.length > 0) {
|
|
5580
6158
|
throw new Error(`Wrangler deploy does not support required flags: ${missing.join(", ")}`);
|
|
5581
6159
|
}
|
|
5582
|
-
const tempDirectory =
|
|
6160
|
+
const tempDirectory = fs5.mkdtempSync(path2.join(
|
|
5583
6161
|
opts.tempRoot ?? os.tmpdir(),
|
|
5584
6162
|
"canonry-cloudflare-wrangler-preflight-"
|
|
5585
6163
|
));
|
|
@@ -5587,13 +6165,13 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
5587
6165
|
const wranglerTomlPath = path2.join(tempDirectory, "wrangler.toml");
|
|
5588
6166
|
const secretsPath = path2.join(tempDirectory, "secrets.json");
|
|
5589
6167
|
try {
|
|
5590
|
-
|
|
5591
|
-
|
|
6168
|
+
fs5.chmodSync(tempDirectory, 448);
|
|
6169
|
+
fs5.writeFileSync(workerScriptPath, generateWorkerScript({
|
|
5592
6170
|
deliveryMode,
|
|
5593
6171
|
workerVersion: "preflight",
|
|
5594
6172
|
botList: DEFAULT_BOT_LIST
|
|
5595
6173
|
}), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
5596
|
-
|
|
6174
|
+
fs5.writeFileSync(wranglerTomlPath, generateWranglerToml(
|
|
5597
6175
|
deliveryMode === "queue-pull" ? {
|
|
5598
6176
|
deliveryMode,
|
|
5599
6177
|
sourceId: "preflight",
|
|
@@ -5609,7 +6187,7 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
5609
6187
|
}
|
|
5610
6188
|
), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
5611
6189
|
if (deliveryMode === "direct-push") {
|
|
5612
|
-
|
|
6190
|
+
fs5.writeFileSync(secretsPath, JSON.stringify({
|
|
5613
6191
|
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]: "preflight-bearer",
|
|
5614
6192
|
[CLOUDFLARE_WORKER_BINDINGS.hmacSecret]: "preflight-hmac"
|
|
5615
6193
|
}), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
@@ -5637,7 +6215,7 @@ ${wranglerDiagnostic(validationOutput)}`
|
|
|
5637
6215
|
);
|
|
5638
6216
|
}
|
|
5639
6217
|
} finally {
|
|
5640
|
-
|
|
6218
|
+
fs5.rmSync(tempDirectory, { recursive: true, force: true });
|
|
5641
6219
|
}
|
|
5642
6220
|
}
|
|
5643
6221
|
async function deployCloudflareWorker(opts) {
|
|
@@ -5653,11 +6231,11 @@ async function deployCloudflareWorker(opts) {
|
|
|
5653
6231
|
}
|
|
5654
6232
|
if (!opts.secrets) throw new Error("Direct-push Worker deploy requires bearer and HMAC secrets");
|
|
5655
6233
|
const secrets = opts.secrets;
|
|
5656
|
-
const tempDirectory =
|
|
6234
|
+
const tempDirectory = fs5.mkdtempSync(path2.join(opts.tempRoot ?? os.tmpdir(), "canonry-cloudflare-secrets-"));
|
|
5657
6235
|
const secretsPath = path2.join(tempDirectory, "secrets.json");
|
|
5658
6236
|
try {
|
|
5659
|
-
|
|
5660
|
-
|
|
6237
|
+
fs5.chmodSync(tempDirectory, 448);
|
|
6238
|
+
fs5.writeFileSync(
|
|
5661
6239
|
secretsPath,
|
|
5662
6240
|
JSON.stringify({
|
|
5663
6241
|
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]: secrets.bearerToken,
|
|
@@ -5665,7 +6243,7 @@ async function deployCloudflareWorker(opts) {
|
|
|
5665
6243
|
}),
|
|
5666
6244
|
{ encoding: "utf-8", flag: "wx", mode: 384 }
|
|
5667
6245
|
);
|
|
5668
|
-
|
|
6246
|
+
fs5.chmodSync(secretsPath, 384);
|
|
5669
6247
|
const runner = opts.run ?? runWrangler;
|
|
5670
6248
|
await runner(
|
|
5671
6249
|
"wrangler",
|
|
@@ -5681,9 +6259,9 @@ async function deployCloudflareWorker(opts) {
|
|
|
5681
6259
|
);
|
|
5682
6260
|
} finally {
|
|
5683
6261
|
try {
|
|
5684
|
-
if (
|
|
6262
|
+
if (fs5.existsSync(secretsPath)) fs5.unlinkSync(secretsPath);
|
|
5685
6263
|
} finally {
|
|
5686
|
-
|
|
6264
|
+
fs5.rmSync(tempDirectory, { recursive: true, force: true });
|
|
5687
6265
|
}
|
|
5688
6266
|
}
|
|
5689
6267
|
}
|
|
@@ -5713,11 +6291,11 @@ function requireCloudflareQueueOption(project, value, option) {
|
|
|
5713
6291
|
}
|
|
5714
6292
|
function readCloudflareQueueApiToken(project, tokenFile) {
|
|
5715
6293
|
try {
|
|
5716
|
-
const stat =
|
|
6294
|
+
const stat = fs6.lstatSync(tokenFile);
|
|
5717
6295
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
5718
6296
|
throw new Error("not a regular file");
|
|
5719
6297
|
}
|
|
5720
|
-
const apiToken =
|
|
6298
|
+
const apiToken = fs6.readFileSync(tokenFile, "utf-8").trim();
|
|
5721
6299
|
if (!apiToken) throw new Error("file is empty");
|
|
5722
6300
|
return apiToken;
|
|
5723
6301
|
} catch (error) {
|
|
@@ -5999,9 +6577,9 @@ async function trafficConnectWordpress(project, opts) {
|
|
|
5999
6577
|
}
|
|
6000
6578
|
let applicationPassword = opts.appPassword?.trim() ?? "";
|
|
6001
6579
|
if (!applicationPassword && opts.appPasswordFile) {
|
|
6002
|
-
const
|
|
6580
|
+
const fs20 = await import("fs");
|
|
6003
6581
|
try {
|
|
6004
|
-
applicationPassword =
|
|
6582
|
+
applicationPassword = fs20.readFileSync(opts.appPasswordFile, "utf-8").trim();
|
|
6005
6583
|
} catch (e) {
|
|
6006
6584
|
const msg = describeError(e);
|
|
6007
6585
|
throw new CliError({
|
|
@@ -6057,10 +6635,10 @@ async function trafficConnectCloudRun(project, opts) {
|
|
|
6057
6635
|
details: { project }
|
|
6058
6636
|
});
|
|
6059
6637
|
}
|
|
6060
|
-
const
|
|
6638
|
+
const fs20 = await import("fs");
|
|
6061
6639
|
let keyJson;
|
|
6062
6640
|
try {
|
|
6063
|
-
keyJson =
|
|
6641
|
+
keyJson = fs20.readFileSync(opts.serviceAccountKey, "utf-8");
|
|
6064
6642
|
JSON.parse(keyJson);
|
|
6065
6643
|
} catch (e) {
|
|
6066
6644
|
const msg = describeError(e);
|
|
@@ -6120,9 +6698,9 @@ async function trafficConnectVercel(project, opts) {
|
|
|
6120
6698
|
}
|
|
6121
6699
|
let token = opts.token?.trim() ?? "";
|
|
6122
6700
|
if (!token && opts.tokenFile) {
|
|
6123
|
-
const
|
|
6701
|
+
const fs20 = await import("fs");
|
|
6124
6702
|
try {
|
|
6125
|
-
token =
|
|
6703
|
+
token = fs20.readFileSync(opts.tokenFile, "utf-8").trim();
|
|
6126
6704
|
} catch (e) {
|
|
6127
6705
|
const msg = describeError(e);
|
|
6128
6706
|
throw new CliError({
|
|
@@ -8570,7 +9148,7 @@ var USERS_CLI_COMMANDS = [
|
|
|
8570
9148
|
];
|
|
8571
9149
|
|
|
8572
9150
|
// src/commands/keyword.ts
|
|
8573
|
-
import
|
|
9151
|
+
import fs7 from "fs";
|
|
8574
9152
|
function getClient14() {
|
|
8575
9153
|
return createApiClient();
|
|
8576
9154
|
}
|
|
@@ -8638,7 +9216,7 @@ async function listKeywords(project, format) {
|
|
|
8638
9216
|
}
|
|
8639
9217
|
}
|
|
8640
9218
|
async function importKeywords(project, filePath, format) {
|
|
8641
|
-
if (!
|
|
9219
|
+
if (!fs7.existsSync(filePath)) {
|
|
8642
9220
|
throw new CliError({
|
|
8643
9221
|
code: "KEYWORD_IMPORT_FILE_NOT_FOUND",
|
|
8644
9222
|
message: `File not found: ${filePath}`,
|
|
@@ -8649,7 +9227,7 @@ async function importKeywords(project, filePath, format) {
|
|
|
8649
9227
|
}
|
|
8650
9228
|
});
|
|
8651
9229
|
}
|
|
8652
|
-
const content =
|
|
9230
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
8653
9231
|
const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8654
9232
|
if (keywords.length === 0) {
|
|
8655
9233
|
if (isMachineFormat(format)) {
|
|
@@ -8850,7 +9428,7 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
8850
9428
|
];
|
|
8851
9429
|
|
|
8852
9430
|
// src/commands/query.ts
|
|
8853
|
-
import
|
|
9431
|
+
import fs8 from "fs";
|
|
8854
9432
|
function getClient15() {
|
|
8855
9433
|
return createApiClient();
|
|
8856
9434
|
}
|
|
@@ -8941,7 +9519,7 @@ async function listQueries(project, format) {
|
|
|
8941
9519
|
}
|
|
8942
9520
|
}
|
|
8943
9521
|
async function importQueries(project, filePath, format) {
|
|
8944
|
-
if (!
|
|
9522
|
+
if (!fs8.existsSync(filePath)) {
|
|
8945
9523
|
throw new CliError({
|
|
8946
9524
|
code: "QUERY_IMPORT_FILE_NOT_FOUND",
|
|
8947
9525
|
message: `File not found: ${filePath}`,
|
|
@@ -8952,7 +9530,7 @@ async function importQueries(project, filePath, format) {
|
|
|
8952
9530
|
}
|
|
8953
9531
|
});
|
|
8954
9532
|
}
|
|
8955
|
-
const content =
|
|
9533
|
+
const content = fs8.readFileSync(filePath, "utf-8");
|
|
8956
9534
|
const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8957
9535
|
if (queries2.length === 0) {
|
|
8958
9536
|
if (isMachineFormat(format)) {
|
|
@@ -9154,7 +9732,7 @@ var QUERY_CLI_COMMANDS = [
|
|
|
9154
9732
|
];
|
|
9155
9733
|
|
|
9156
9734
|
// src/commands/mcp.ts
|
|
9157
|
-
import
|
|
9735
|
+
import fs9 from "fs";
|
|
9158
9736
|
import path4 from "path";
|
|
9159
9737
|
import { createRequire } from "module";
|
|
9160
9738
|
|
|
@@ -9270,8 +9848,8 @@ function renderClientSnippet(client, serverName, entry) {
|
|
|
9270
9848
|
return renderJsonSnippet(serverName, entry, client.format);
|
|
9271
9849
|
}
|
|
9272
9850
|
function readJsonConfig(configPath) {
|
|
9273
|
-
if (!
|
|
9274
|
-
const raw =
|
|
9851
|
+
if (!fs9.existsSync(configPath)) return {};
|
|
9852
|
+
const raw = fs9.readFileSync(configPath, "utf-8").trim();
|
|
9275
9853
|
if (!raw) return {};
|
|
9276
9854
|
try {
|
|
9277
9855
|
const parsed = JSON.parse(raw);
|
|
@@ -9289,14 +9867,14 @@ function readJsonConfig(configPath) {
|
|
|
9289
9867
|
}
|
|
9290
9868
|
}
|
|
9291
9869
|
function writeJsonConfig(configPath, value) {
|
|
9292
|
-
|
|
9293
|
-
|
|
9870
|
+
fs9.mkdirSync(path4.dirname(configPath), { recursive: true });
|
|
9871
|
+
fs9.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
9294
9872
|
`, "utf-8");
|
|
9295
9873
|
}
|
|
9296
9874
|
function backupConfigIfPresent(configPath) {
|
|
9297
|
-
if (!
|
|
9875
|
+
if (!fs9.existsSync(configPath)) return void 0;
|
|
9298
9876
|
const backupPath = `${configPath}.canonry.bak`;
|
|
9299
|
-
|
|
9877
|
+
fs9.copyFileSync(configPath, backupPath);
|
|
9300
9878
|
return backupPath;
|
|
9301
9879
|
}
|
|
9302
9880
|
function findClientOrThrow(id) {
|
|
@@ -9652,13 +10230,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
9652
10230
|
];
|
|
9653
10231
|
|
|
9654
10232
|
// src/commands/apply.ts
|
|
9655
|
-
import
|
|
10233
|
+
import fs10 from "fs";
|
|
9656
10234
|
import { parseAllDocuments } from "yaml";
|
|
9657
10235
|
async function applyConfigFile(filePath) {
|
|
9658
|
-
if (!
|
|
10236
|
+
if (!fs10.existsSync(filePath)) {
|
|
9659
10237
|
throw new Error(`File not found: ${filePath}`);
|
|
9660
10238
|
}
|
|
9661
|
-
const content =
|
|
10239
|
+
const content = fs10.readFileSync(filePath, "utf-8");
|
|
9662
10240
|
const docs = parseAllDocuments(content);
|
|
9663
10241
|
const client = createApiClient();
|
|
9664
10242
|
const errors = [];
|
|
@@ -10061,7 +10639,7 @@ async function loadLatestRunForExport(client, project) {
|
|
|
10061
10639
|
}
|
|
10062
10640
|
|
|
10063
10641
|
// src/commands/results-export.ts
|
|
10064
|
-
import
|
|
10642
|
+
import fs11 from "fs";
|
|
10065
10643
|
import path5 from "path";
|
|
10066
10644
|
async function exportResults(project, opts) {
|
|
10067
10645
|
const { output, ...request } = opts;
|
|
@@ -10071,8 +10649,8 @@ async function exportResults(project, opts) {
|
|
|
10071
10649
|
return;
|
|
10072
10650
|
}
|
|
10073
10651
|
const target = output ? path5.resolve(output) : path5.resolve(process.cwd(), path5.basename(artifact.filename));
|
|
10074
|
-
|
|
10075
|
-
|
|
10652
|
+
fs11.mkdirSync(path5.dirname(target), { recursive: true });
|
|
10653
|
+
fs11.writeFileSync(target, artifact.content, "utf8");
|
|
10076
10654
|
console.log(`Results export written to ${target}`);
|
|
10077
10655
|
}
|
|
10078
10656
|
|
|
@@ -10788,7 +11366,7 @@ function parseProviderModelAssignments(assignments) {
|
|
|
10788
11366
|
}
|
|
10789
11367
|
|
|
10790
11368
|
// src/commands/report.ts
|
|
10791
|
-
import
|
|
11369
|
+
import fs12 from "fs";
|
|
10792
11370
|
import path6 from "path";
|
|
10793
11371
|
function defaultOutputPath(project, audience) {
|
|
10794
11372
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -10805,10 +11383,10 @@ async function runReportCommand(project, opts = {}) {
|
|
|
10805
11383
|
const html = renderReportHtml(report, { audience });
|
|
10806
11384
|
const targetPath = opts.output ? path6.resolve(opts.output) : defaultOutputPath(project, audience);
|
|
10807
11385
|
const dir = path6.dirname(targetPath);
|
|
10808
|
-
if (!
|
|
10809
|
-
|
|
11386
|
+
if (!fs12.existsSync(dir)) {
|
|
11387
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
10810
11388
|
}
|
|
10811
|
-
|
|
11389
|
+
fs12.writeFileSync(targetPath, html, "utf-8");
|
|
10812
11390
|
console.log(`Report written to ${targetPath}`);
|
|
10813
11391
|
}
|
|
10814
11392
|
|
|
@@ -11783,11 +12361,11 @@ var SKILLS_CLI_COMMANDS = [
|
|
|
11783
12361
|
];
|
|
11784
12362
|
|
|
11785
12363
|
// src/commands/snapshot.ts
|
|
11786
|
-
import
|
|
12364
|
+
import fs14 from "fs";
|
|
11787
12365
|
import path8 from "path";
|
|
11788
12366
|
|
|
11789
12367
|
// src/snapshot-pdf.ts
|
|
11790
|
-
import
|
|
12368
|
+
import fs13 from "fs";
|
|
11791
12369
|
import path7 from "path";
|
|
11792
12370
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
11793
12371
|
var PAGE_WIDTH = 612;
|
|
@@ -12001,8 +12579,8 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
12001
12579
|
renderQueries(pdf, report);
|
|
12002
12580
|
const bytes = await doc.save();
|
|
12003
12581
|
const resolvedPath = path7.resolve(outputPath);
|
|
12004
|
-
|
|
12005
|
-
|
|
12582
|
+
fs13.mkdirSync(path7.dirname(resolvedPath), { recursive: true });
|
|
12583
|
+
fs13.writeFileSync(resolvedPath, bytes);
|
|
12006
12584
|
return resolvedPath;
|
|
12007
12585
|
}
|
|
12008
12586
|
function renderCover(pdf, report) {
|
|
@@ -12161,8 +12739,8 @@ PDF saved: ${savedPdfPath}`);
|
|
|
12161
12739
|
}
|
|
12162
12740
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
12163
12741
|
const resolvedPath = path8.resolve(outputPath);
|
|
12164
|
-
|
|
12165
|
-
|
|
12742
|
+
fs14.mkdirSync(path8.dirname(resolvedPath), { recursive: true });
|
|
12743
|
+
fs14.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
12166
12744
|
return resolvedPath;
|
|
12167
12745
|
}
|
|
12168
12746
|
function formatSnapshotMarkdown(report) {
|
|
@@ -13390,7 +13968,7 @@ async function bootstrapCommand(_opts) {
|
|
|
13390
13968
|
|
|
13391
13969
|
// src/commands/daemon.ts
|
|
13392
13970
|
import { spawn as spawn2 } from "child_process";
|
|
13393
|
-
import
|
|
13971
|
+
import fs15 from "fs";
|
|
13394
13972
|
import path10 from "path";
|
|
13395
13973
|
function getPidPath() {
|
|
13396
13974
|
return path10.join(getConfigDir(), "canonry.pid");
|
|
@@ -13433,8 +14011,8 @@ function buildServeForwardArgs(opts) {
|
|
|
13433
14011
|
async function startDaemon(opts) {
|
|
13434
14012
|
const pidPath = getPidPath();
|
|
13435
14013
|
const format = opts.format ?? "text";
|
|
13436
|
-
if (
|
|
13437
|
-
const existingPid = parseInt(
|
|
14014
|
+
if (fs15.existsSync(pidPath)) {
|
|
14015
|
+
const existingPid = parseInt(fs15.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
13438
14016
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
13439
14017
|
throw new CliError({
|
|
13440
14018
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -13445,7 +14023,7 @@ async function startDaemon(opts) {
|
|
|
13445
14023
|
}
|
|
13446
14024
|
});
|
|
13447
14025
|
}
|
|
13448
|
-
|
|
14026
|
+
fs15.unlinkSync(pidPath);
|
|
13449
14027
|
}
|
|
13450
14028
|
const cliPath = path10.resolve(new URL(import.meta.url).pathname);
|
|
13451
14029
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
@@ -13464,10 +14042,10 @@ async function startDaemon(opts) {
|
|
|
13464
14042
|
});
|
|
13465
14043
|
}
|
|
13466
14044
|
const configDir = getConfigDir();
|
|
13467
|
-
if (!
|
|
13468
|
-
|
|
14045
|
+
if (!fs15.existsSync(configDir)) {
|
|
14046
|
+
fs15.mkdirSync(configDir, { recursive: true });
|
|
13469
14047
|
}
|
|
13470
|
-
|
|
14048
|
+
fs15.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
13471
14049
|
const port = opts.port ?? "4100";
|
|
13472
14050
|
const host = opts.host ?? "127.0.0.1";
|
|
13473
14051
|
if (!isMachineFormat(format)) {
|
|
@@ -13476,7 +14054,7 @@ async function startDaemon(opts) {
|
|
|
13476
14054
|
const ready = await waitForReady(host, port);
|
|
13477
14055
|
if (!ready) {
|
|
13478
14056
|
try {
|
|
13479
|
-
|
|
14057
|
+
fs15.unlinkSync(pidPath);
|
|
13480
14058
|
} catch {
|
|
13481
14059
|
}
|
|
13482
14060
|
throw new CliError({
|
|
@@ -13508,7 +14086,7 @@ async function startDaemon(opts) {
|
|
|
13508
14086
|
}
|
|
13509
14087
|
function stopDaemon(format = "text") {
|
|
13510
14088
|
const pidPath = getPidPath();
|
|
13511
|
-
if (!
|
|
14089
|
+
if (!fs15.existsSync(pidPath)) {
|
|
13512
14090
|
if (isMachineFormat(format)) {
|
|
13513
14091
|
console.log(JSON.stringify({
|
|
13514
14092
|
stopped: false,
|
|
@@ -13519,7 +14097,7 @@ function stopDaemon(format = "text") {
|
|
|
13519
14097
|
console.log("Canonry is not running (no PID file found)");
|
|
13520
14098
|
return;
|
|
13521
14099
|
}
|
|
13522
|
-
const pid = parseInt(
|
|
14100
|
+
const pid = parseInt(fs15.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
13523
14101
|
if (isNaN(pid)) {
|
|
13524
14102
|
if (isMachineFormat(format)) {
|
|
13525
14103
|
console.log(JSON.stringify({
|
|
@@ -13530,7 +14108,7 @@ function stopDaemon(format = "text") {
|
|
|
13530
14108
|
} else {
|
|
13531
14109
|
console.error("Invalid PID file. Removing it.");
|
|
13532
14110
|
}
|
|
13533
|
-
|
|
14111
|
+
fs15.unlinkSync(pidPath);
|
|
13534
14112
|
return;
|
|
13535
14113
|
}
|
|
13536
14114
|
if (!isProcessAlive(pid)) {
|
|
@@ -13544,12 +14122,12 @@ function stopDaemon(format = "text") {
|
|
|
13544
14122
|
} else {
|
|
13545
14123
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
13546
14124
|
}
|
|
13547
|
-
|
|
14125
|
+
fs15.unlinkSync(pidPath);
|
|
13548
14126
|
return;
|
|
13549
14127
|
}
|
|
13550
14128
|
try {
|
|
13551
14129
|
process.kill(pid, "SIGTERM");
|
|
13552
|
-
|
|
14130
|
+
fs15.unlinkSync(pidPath);
|
|
13553
14131
|
if (isMachineFormat(format)) {
|
|
13554
14132
|
console.log(JSON.stringify({
|
|
13555
14133
|
stopped: true,
|
|
@@ -13573,7 +14151,7 @@ function stopDaemon(format = "text") {
|
|
|
13573
14151
|
|
|
13574
14152
|
// src/commands/init.ts
|
|
13575
14153
|
import crypto2 from "crypto";
|
|
13576
|
-
import
|
|
14154
|
+
import fs16 from "fs";
|
|
13577
14155
|
import readline2 from "readline";
|
|
13578
14156
|
import path11 from "path";
|
|
13579
14157
|
var pendingServeHandoff = false;
|
|
@@ -13611,7 +14189,7 @@ var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
|
|
|
13611
14189
|
function cwdLooksLikeProject(dir) {
|
|
13612
14190
|
const home = process.env.HOME ?? "";
|
|
13613
14191
|
if (home && path11.resolve(dir) === path11.resolve(home)) return false;
|
|
13614
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
14192
|
+
return PROJECT_MARKERS.some((marker) => fs16.existsSync(path11.join(dir, marker)));
|
|
13615
14193
|
}
|
|
13616
14194
|
var DEFAULT_AGENT_MODELS = {
|
|
13617
14195
|
anthropic: "anthropic/claude-sonnet-4-6",
|
|
@@ -13642,8 +14220,8 @@ async function initCommand(opts) {
|
|
|
13642
14220
|
return void 0;
|
|
13643
14221
|
}
|
|
13644
14222
|
const configDir = getConfigDir();
|
|
13645
|
-
if (!
|
|
13646
|
-
|
|
14223
|
+
if (!fs16.existsSync(configDir)) {
|
|
14224
|
+
fs16.mkdirSync(configDir, { recursive: true });
|
|
13647
14225
|
}
|
|
13648
14226
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
13649
14227
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -13944,7 +14522,7 @@ function encodeLegacySetupState(state) {
|
|
|
13944
14522
|
}
|
|
13945
14523
|
|
|
13946
14524
|
// src/agent-plugin.ts
|
|
13947
|
-
import
|
|
14525
|
+
import fs17 from "fs";
|
|
13948
14526
|
import path12 from "path";
|
|
13949
14527
|
var CANONRY_PLUGIN_ID = "canonry@canonry";
|
|
13950
14528
|
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
@@ -13989,7 +14567,7 @@ function isCanonryPluginId(value) {
|
|
|
13989
14567
|
}
|
|
13990
14568
|
function readJson(filePath) {
|
|
13991
14569
|
try {
|
|
13992
|
-
return JSON.parse(
|
|
14570
|
+
return JSON.parse(fs17.readFileSync(filePath, "utf8"));
|
|
13993
14571
|
} catch {
|
|
13994
14572
|
return null;
|
|
13995
14573
|
}
|
|
@@ -14008,7 +14586,7 @@ function readCodexPluginConfigured(filePath) {
|
|
|
14008
14586
|
try {
|
|
14009
14587
|
let currentPlugin = null;
|
|
14010
14588
|
let inPluginsTable = false;
|
|
14011
|
-
for (const line of
|
|
14589
|
+
for (const line of fs17.readFileSync(filePath, "utf8").split(/\r?\n/)) {
|
|
14012
14590
|
const section = /^\s*\[plugins\.(?:"([^"]+)"|'([^']+)'|(\S+))\]\s*(?:#.*)?$/.exec(line);
|
|
14013
14591
|
if (section) {
|
|
14014
14592
|
const captures = section.slice(1, 4);
|
|
@@ -14041,7 +14619,7 @@ function readCodexPluginConfigured(filePath) {
|
|
|
14041
14619
|
}
|
|
14042
14620
|
}
|
|
14043
14621
|
function verifiedPluginVersion(root, client) {
|
|
14044
|
-
if (client === "codex" &&
|
|
14622
|
+
if (client === "codex" && fs17.existsSync(path12.join(root, "plugin.json"))) {
|
|
14045
14623
|
const manifest2 = readJson(path12.join(root, "plugin.json"));
|
|
14046
14624
|
if (manifest2 && typeof manifest2 === "object") {
|
|
14047
14625
|
const plugin2 = manifest2;
|
|
@@ -14055,7 +14633,7 @@ function verifiedPluginVersion(root, client) {
|
|
|
14055
14633
|
if (portableMcp.$schema !== AGENT_PLUGINS_MCP_SCHEMA || portableMcp.mcpServers?.canonry?.type !== "stdio" || portableMcp.mcpServers.canonry.command !== "canonry-mcp") {
|
|
14056
14634
|
return null;
|
|
14057
14635
|
}
|
|
14058
|
-
return REQUIRED_SKILLS.every((name) =>
|
|
14636
|
+
return REQUIRED_SKILLS.every((name) => fs17.existsSync(path12.join(root, "skills", name, "SKILL.md"))) ? plugin2.version : null;
|
|
14059
14637
|
}
|
|
14060
14638
|
if (typeof plugin2.$schema === "string" && plugin2.$schema.startsWith("https://agent-plugins.org/schemas/")) {
|
|
14061
14639
|
return null;
|
|
@@ -14073,7 +14651,7 @@ function verifiedPluginVersion(root, client) {
|
|
|
14073
14651
|
if (!mcp || typeof mcp !== "object") return null;
|
|
14074
14652
|
const canonryServer = mcp.mcpServers?.canonry;
|
|
14075
14653
|
if (canonryServer?.command !== "canonry-mcp") return null;
|
|
14076
|
-
return REQUIRED_SKILLS.every((name) =>
|
|
14654
|
+
return REQUIRED_SKILLS.every((name) => fs17.existsSync(path12.join(root, "skills", name, "SKILL.md"))) ? plugin.version : null;
|
|
14077
14655
|
}
|
|
14078
14656
|
function readClaudeUserInstallPaths(claudeConfigDir) {
|
|
14079
14657
|
const parsed = readJson(path12.join(claudeConfigDir, "plugins", "installed_plugins.json"));
|
|
@@ -14090,7 +14668,7 @@ function readClaudeUserInstallPaths(claudeConfigDir) {
|
|
|
14090
14668
|
}
|
|
14091
14669
|
function listDirectories(dir) {
|
|
14092
14670
|
try {
|
|
14093
|
-
return
|
|
14671
|
+
return fs17.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path12.join(dir, entry.name));
|
|
14094
14672
|
} catch {
|
|
14095
14673
|
return [];
|
|
14096
14674
|
}
|
|
@@ -15749,7 +16327,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
|
15749
16327
|
];
|
|
15750
16328
|
|
|
15751
16329
|
// src/cli-commands/wordpress.ts
|
|
15752
|
-
import
|
|
16330
|
+
import fs18 from "fs";
|
|
15753
16331
|
|
|
15754
16332
|
// src/commands/wordpress.ts
|
|
15755
16333
|
function getClient28() {
|
|
@@ -15988,12 +16566,12 @@ async function wordpressSetMeta(project, body) {
|
|
|
15988
16566
|
printPageDetail(result);
|
|
15989
16567
|
}
|
|
15990
16568
|
async function wordpressBulkSetMeta(project, opts) {
|
|
15991
|
-
const
|
|
16569
|
+
const fs20 = await import("fs/promises");
|
|
15992
16570
|
const path13 = await import("path");
|
|
15993
16571
|
const filePath = path13.resolve(opts.from);
|
|
15994
16572
|
let raw;
|
|
15995
16573
|
try {
|
|
15996
|
-
raw = await
|
|
16574
|
+
raw = await fs20.readFile(filePath, "utf8");
|
|
15997
16575
|
} catch {
|
|
15998
16576
|
throw new CliError({
|
|
15999
16577
|
code: "FILE_READ_ERROR",
|
|
@@ -16090,13 +16668,13 @@ async function wordpressSetSchema(project, body) {
|
|
|
16090
16668
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
16091
16669
|
}
|
|
16092
16670
|
async function wordpressSchemaDeploy(project, opts) {
|
|
16093
|
-
const
|
|
16671
|
+
const fs20 = await import("fs/promises");
|
|
16094
16672
|
const path13 = await import("path");
|
|
16095
16673
|
const yaml = await loadYamlModule();
|
|
16096
16674
|
const filePath = path13.resolve(opts.profile);
|
|
16097
16675
|
let raw;
|
|
16098
16676
|
try {
|
|
16099
|
-
raw = await
|
|
16677
|
+
raw = await fs20.readFile(filePath, "utf8");
|
|
16100
16678
|
} catch {
|
|
16101
16679
|
throw new CliError({
|
|
16102
16680
|
code: "FILE_READ_ERROR",
|
|
@@ -16201,13 +16779,13 @@ async function wordpressOnboard(project, opts) {
|
|
|
16201
16779
|
}
|
|
16202
16780
|
let profileData;
|
|
16203
16781
|
if (opts.profile) {
|
|
16204
|
-
const
|
|
16782
|
+
const fs20 = await import("fs/promises");
|
|
16205
16783
|
const path13 = await import("path");
|
|
16206
16784
|
const yaml = await loadYamlModule();
|
|
16207
16785
|
const filePath = path13.resolve(opts.profile);
|
|
16208
16786
|
let raw;
|
|
16209
16787
|
try {
|
|
16210
|
-
raw = await
|
|
16788
|
+
raw = await fs20.readFile(filePath, "utf8");
|
|
16211
16789
|
} catch {
|
|
16212
16790
|
throw new CliError({
|
|
16213
16791
|
code: "FILE_READ_ERROR",
|
|
@@ -16356,7 +16934,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
16356
16934
|
}
|
|
16357
16935
|
if (contentFile) {
|
|
16358
16936
|
try {
|
|
16359
|
-
return
|
|
16937
|
+
return fs18.readFileSync(contentFile, "utf-8");
|
|
16360
16938
|
} catch (error) {
|
|
16361
16939
|
const message = describeError(error);
|
|
16362
16940
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|
|
@@ -17323,16 +17901,16 @@ Usage: ${usage}`, {
|
|
|
17323
17901
|
|
|
17324
17902
|
// src/commands/measurement-plan.ts
|
|
17325
17903
|
import crypto3 from "crypto";
|
|
17326
|
-
import
|
|
17904
|
+
import fs19 from "fs";
|
|
17327
17905
|
import { parse } from "yaml";
|
|
17328
17906
|
import { z as z2 } from "zod";
|
|
17329
17907
|
function readPlan(source) {
|
|
17330
|
-
const content = source === "-" ?
|
|
17908
|
+
const content = source === "-" ? fs19.readFileSync(0, "utf8") : fs19.readFileSync(source, "utf8");
|
|
17331
17909
|
const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
|
|
17332
17910
|
return measurementPlanInputSchema.parse(parsed);
|
|
17333
17911
|
}
|
|
17334
17912
|
function readDiscoveryRule(source) {
|
|
17335
|
-
const content = source === "-" ?
|
|
17913
|
+
const content = source === "-" ? fs19.readFileSync(0, "utf8") : fs19.readFileSync(source, "utf8");
|
|
17336
17914
|
const parsed = source.endsWith(".json") ? JSON.parse(content) : parse(content);
|
|
17337
17915
|
return measurementDiscoveryRuleSchema.parse(parsed);
|
|
17338
17916
|
}
|
|
@@ -17381,7 +17959,7 @@ var advancedDeactivateInputSchema = z2.object({
|
|
|
17381
17959
|
}).strict();
|
|
17382
17960
|
function readAdvancedMeasurementInput(source) {
|
|
17383
17961
|
if (source === void 0) return {};
|
|
17384
|
-
const content = source === "-" ?
|
|
17962
|
+
const content = source === "-" ? fs19.readFileSync(0, "utf8") : fs19.readFileSync(source, "utf8");
|
|
17385
17963
|
return JSON.parse(content);
|
|
17386
17964
|
}
|
|
17387
17965
|
var advancedMeasurementCollectionKeys = {
|
|
@@ -17563,7 +18141,7 @@ async function replaceMeasurementPlanAssignments(project, opts) {
|
|
|
17563
18141
|
console.log(JSON.stringify({ preview, result }, null, 2));
|
|
17564
18142
|
}
|
|
17565
18143
|
function readGroupMembershipCsv(source) {
|
|
17566
|
-
return source === "-" ?
|
|
18144
|
+
return source === "-" ? fs19.readFileSync(0, "utf8") : fs19.readFileSync(source, "utf8");
|
|
17567
18145
|
}
|
|
17568
18146
|
async function previewMeasurementPlanGroups(project, source) {
|
|
17569
18147
|
const preview = await createApiClient().previewMeasurementDraftGroupMembership(project, {
|
|
@@ -17994,6 +18572,7 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
17994
18572
|
...ADS_CLI_COMMANDS,
|
|
17995
18573
|
...GA_CLI_COMMANDS,
|
|
17996
18574
|
...GBP_CLI_COMMANDS,
|
|
18575
|
+
...createGoogleMarketingCliCommands(createApiClient),
|
|
17997
18576
|
...TRAFFIC_CLI_COMMANDS,
|
|
17998
18577
|
...INTELLIGENCE_CLI_COMMANDS,
|
|
17999
18578
|
...VISIBILITY_STATS_CLI_COMMANDS,
|