@canonry/canonry 4.117.1 → 4.118.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/assets/agent-workspace/skills/canonry/references/canonry-cli.md +74 -1
- package/assets/assets/AuditHistoryPanel-Yh7VEe4P.js +1 -0
- package/assets/assets/{BacklinksPage-Bkafm10m.js → BacklinksPage-BmO77kMs.js} +1 -1
- package/assets/assets/{ChartPrimitives-NV_GgqFn.js → ChartPrimitives-H0ICVpw_.js} +1 -1
- package/assets/assets/HistoryPage-DkLV_iRc.js +1 -0
- package/assets/assets/ProjectPage-R3odr_eA.js +7 -0
- package/assets/assets/{RunRow-df0d24S6.js → RunRow-BDH9agxQ.js} +1 -1
- package/assets/assets/RunsPage-D9YsEeT3.js +1 -0
- package/assets/assets/{SettingsPage-BKw6B6cd.js → SettingsPage-o5as3Ixw.js} +1 -1
- package/assets/assets/{TrafficPage-CzpiYHKj.js → TrafficPage-BCK203aQ.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-CC5nuqM1.js → TrafficSourceDetailPage-DsVMAZvS.js} +1 -1
- package/assets/assets/{arrow-left-CbQcW2pL.js → arrow-left-B7ZR6VC9.js} +1 -1
- package/assets/assets/{extract-error-message-CvqIZ-le.js → extract-error-message-DeYDUpew.js} +1 -1
- package/assets/assets/index-Bot6YiD6.css +1 -0
- package/assets/assets/index-QCFQv0xh.js +210 -0
- package/assets/assets/{trash-2-3J2u0woR.js → trash-2-xxHTqWbF.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-BMBHUFMI.js → chunk-75UBTCKS.js} +540 -16
- package/dist/{chunk-V4SW7SVX.js → chunk-CMZIPFNQ.js} +1598 -486
- package/dist/{chunk-NY7SC4ES.js → chunk-HGNY5GL4.js} +384 -15
- package/dist/{chunk-IAJ5TQ4S.js → chunk-KEZWLP4O.js} +1385 -1145
- package/dist/cli.js +390 -113
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-C5YLASIP.js → intelligence-service-FWPXMAVK.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +7 -7
- package/assets/assets/ProjectPage-0-NnRxys.js +0 -7
- package/assets/assets/RunsPage-CU6-4YTM.js +0 -1
- package/assets/assets/index-B4R1-8hR.css +0 -1
- package/assets/assets/index-LjcWHaNZ.js +0 -210
package/dist/cli.js
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
setTelemetrySource,
|
|
30
30
|
showFirstRunNotice,
|
|
31
31
|
trackEvent
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-HGNY5GL4.js";
|
|
33
33
|
import {
|
|
34
34
|
CliError,
|
|
35
35
|
EXIT_SYSTEM_ERROR,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
saveConfig,
|
|
47
47
|
saveConfigPatch,
|
|
48
48
|
usageError
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-75UBTCKS.js";
|
|
50
50
|
import {
|
|
51
51
|
apiKeys,
|
|
52
52
|
createClient,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
projects,
|
|
55
55
|
queries,
|
|
56
56
|
renderReportHtml
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-CMZIPFNQ.js";
|
|
58
58
|
import {
|
|
59
59
|
BacklinkSources,
|
|
60
60
|
CcReleaseSyncStatuses,
|
|
@@ -65,6 +65,14 @@ import {
|
|
|
65
65
|
REPORT_PERIOD_OPTIONS,
|
|
66
66
|
RunStatuses,
|
|
67
67
|
TrafficEventKinds,
|
|
68
|
+
adsAdCreateRequestSchema,
|
|
69
|
+
adsAdGroupCreateRequestSchema,
|
|
70
|
+
adsAdGroupUpdateRequestSchema,
|
|
71
|
+
adsAdUpdateRequestSchema,
|
|
72
|
+
adsCampaignCreateRequestSchema,
|
|
73
|
+
adsCampaignUpdateRequestSchema,
|
|
74
|
+
adsImageUploadRequestSchema,
|
|
75
|
+
adsPauseRequestSchema,
|
|
68
76
|
backlinkSourceSchema,
|
|
69
77
|
discoveryBucketSchema,
|
|
70
78
|
discoveryCompetitorTypeSchema,
|
|
@@ -80,7 +88,7 @@ import {
|
|
|
80
88
|
providerQuotaPolicySchema,
|
|
81
89
|
resolveProviderInput,
|
|
82
90
|
winnabilityClassSchema
|
|
83
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-KEZWLP4O.js";
|
|
84
92
|
|
|
85
93
|
// src/cli.ts
|
|
86
94
|
import { pathToFileURL } from "url";
|
|
@@ -126,9 +134,9 @@ import { parseArgs } from "util";
|
|
|
126
134
|
function commandId(spec) {
|
|
127
135
|
return spec.path.join(".");
|
|
128
136
|
}
|
|
129
|
-
function matchesPath(args,
|
|
130
|
-
if (args.length <
|
|
131
|
-
return
|
|
137
|
+
function matchesPath(args, path11) {
|
|
138
|
+
if (args.length < path11.length) return false;
|
|
139
|
+
return path11.every((segment, index) => args[index] === segment);
|
|
132
140
|
}
|
|
133
141
|
function withGlobalOptions(options) {
|
|
134
142
|
const base = options ? { ...options } : {};
|
|
@@ -2713,9 +2721,46 @@ var DOCTOR_CLI_COMMANDS = [
|
|
|
2713
2721
|
];
|
|
2714
2722
|
|
|
2715
2723
|
// src/commands/ads.ts
|
|
2724
|
+
import fs3 from "fs";
|
|
2716
2725
|
function getClient5() {
|
|
2717
2726
|
return createApiClient();
|
|
2718
2727
|
}
|
|
2728
|
+
function readRequest(inputPath, schema) {
|
|
2729
|
+
if (!inputPath) {
|
|
2730
|
+
throw new CliError({
|
|
2731
|
+
code: "ADS_INPUT_REQUIRED",
|
|
2732
|
+
message: "A JSON input file is required",
|
|
2733
|
+
displayMessage: "Error: --input <json-file> is required (use --input - for stdin)"
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
try {
|
|
2737
|
+
const raw = fs3.readFileSync(inputPath === "-" ? 0 : inputPath, "utf8");
|
|
2738
|
+
return schema.parse(JSON.parse(raw));
|
|
2739
|
+
} catch (err) {
|
|
2740
|
+
if (err instanceof CliError) throw err;
|
|
2741
|
+
throw new CliError({
|
|
2742
|
+
code: "ADS_INPUT_INVALID",
|
|
2743
|
+
message: err instanceof Error ? err.message : String(err),
|
|
2744
|
+
displayMessage: `Error: invalid ads JSON input (${err instanceof Error ? err.message : String(err)})`,
|
|
2745
|
+
details: { inputPath }
|
|
2746
|
+
});
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
function printOperation(result, format) {
|
|
2750
|
+
if (isMachineFormat(format)) {
|
|
2751
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
const operation = result.operation;
|
|
2755
|
+
console.log(`${result.replayed ? "Replayed" : "Recorded"} ${operation.kind}: ${operation.state}`);
|
|
2756
|
+
console.log(`Operation: ${operation.operationKey}`);
|
|
2757
|
+
if (operation.entityId) console.log(`Entity: ${operation.entityType ?? "unknown"} ${operation.entityId}`);
|
|
2758
|
+
if (operation.upstreamUpdatedAt != null) console.log(`Updated: ${operation.upstreamUpdatedAt}`);
|
|
2759
|
+
if (operation.errorCode) console.log(`Error: ${operation.errorCode}: ${operation.errorMessage ?? ""}`);
|
|
2760
|
+
if (operation.state === "unknown") {
|
|
2761
|
+
console.log("Do not retry with a new operation key. Reconcile this outcome with a human first.");
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2719
2764
|
function describeConnection(status) {
|
|
2720
2765
|
const lines = [];
|
|
2721
2766
|
lines.push(`Connected: ${status.connected ? "yes" : "no"}`);
|
|
@@ -2768,6 +2813,49 @@ async function adsStatus(project, opts) {
|
|
|
2768
2813
|
console.log("Connect with: canonry ads connect " + project + " --api-key <sdk-key>");
|
|
2769
2814
|
}
|
|
2770
2815
|
}
|
|
2816
|
+
async function adsOperationGet(project, opts) {
|
|
2817
|
+
printOperation(await getClient5().getAdsOperation(project, opts.operationKey), opts.format);
|
|
2818
|
+
}
|
|
2819
|
+
async function adsImageUpload(project, opts) {
|
|
2820
|
+
const request = readRequest(opts.input, adsImageUploadRequestSchema);
|
|
2821
|
+
printOperation(await getClient5().uploadAdsImage(project, request), opts.format);
|
|
2822
|
+
}
|
|
2823
|
+
async function adsCampaignCreate(project, opts) {
|
|
2824
|
+
const request = readRequest(opts.input, adsCampaignCreateRequestSchema);
|
|
2825
|
+
printOperation(await getClient5().createAdsCampaign(project, request), opts.format);
|
|
2826
|
+
}
|
|
2827
|
+
async function adsCampaignUpdate(project, campaignId, opts) {
|
|
2828
|
+
const request = readRequest(opts.input, adsCampaignUpdateRequestSchema);
|
|
2829
|
+
printOperation(await getClient5().updateAdsCampaign(project, campaignId, request), opts.format);
|
|
2830
|
+
}
|
|
2831
|
+
async function adsCampaignPause(project, campaignId, opts) {
|
|
2832
|
+
const request = readRequest(opts.input, adsPauseRequestSchema);
|
|
2833
|
+
printOperation(await getClient5().pauseAdsCampaign(project, campaignId, request), opts.format);
|
|
2834
|
+
}
|
|
2835
|
+
async function adsAdGroupCreate(project, opts) {
|
|
2836
|
+
const request = readRequest(opts.input, adsAdGroupCreateRequestSchema);
|
|
2837
|
+
printOperation(await getClient5().createAdsAdGroup(project, request), opts.format);
|
|
2838
|
+
}
|
|
2839
|
+
async function adsAdGroupUpdate(project, adGroupId, opts) {
|
|
2840
|
+
const request = readRequest(opts.input, adsAdGroupUpdateRequestSchema);
|
|
2841
|
+
printOperation(await getClient5().updateAdsAdGroup(project, adGroupId, request), opts.format);
|
|
2842
|
+
}
|
|
2843
|
+
async function adsAdGroupPause(project, adGroupId, opts) {
|
|
2844
|
+
const request = readRequest(opts.input, adsPauseRequestSchema);
|
|
2845
|
+
printOperation(await getClient5().pauseAdsAdGroup(project, adGroupId, request), opts.format);
|
|
2846
|
+
}
|
|
2847
|
+
async function adsAdCreate(project, opts) {
|
|
2848
|
+
const request = readRequest(opts.input, adsAdCreateRequestSchema);
|
|
2849
|
+
printOperation(await getClient5().createAdsAd(project, request), opts.format);
|
|
2850
|
+
}
|
|
2851
|
+
async function adsAdUpdate(project, adId, opts) {
|
|
2852
|
+
const request = readRequest(opts.input, adsAdUpdateRequestSchema);
|
|
2853
|
+
printOperation(await getClient5().updateAdsAd(project, adId, request), opts.format);
|
|
2854
|
+
}
|
|
2855
|
+
async function adsAdPause(project, adId, opts) {
|
|
2856
|
+
const request = readRequest(opts.input, adsPauseRequestSchema);
|
|
2857
|
+
printOperation(await getClient5().pauseAdsAd(project, adId, request), opts.format);
|
|
2858
|
+
}
|
|
2771
2859
|
async function adsSync(project, opts) {
|
|
2772
2860
|
const client = getClient5();
|
|
2773
2861
|
const result = await client.triggerAdsSync(project);
|
|
@@ -2885,6 +2973,122 @@ var ADS_CLI_COMMANDS = [
|
|
|
2885
2973
|
await adsStatus(project, { format: input.format });
|
|
2886
2974
|
}
|
|
2887
2975
|
},
|
|
2976
|
+
{
|
|
2977
|
+
path: ["ads", "operation"],
|
|
2978
|
+
usage: "canonry ads operation <project> <operation-key> [--format json]",
|
|
2979
|
+
run: async (input) => {
|
|
2980
|
+
const usage = "canonry ads operation <project> <operation-key> [--format json]";
|
|
2981
|
+
const project = requireProject(input, "ads.operation", usage);
|
|
2982
|
+
const operationKey = requirePositional(input, 1, {
|
|
2983
|
+
command: "ads.operation",
|
|
2984
|
+
usage,
|
|
2985
|
+
message: "operation key is required"
|
|
2986
|
+
});
|
|
2987
|
+
await adsOperationGet(project, { operationKey, format: input.format });
|
|
2988
|
+
}
|
|
2989
|
+
},
|
|
2990
|
+
{
|
|
2991
|
+
path: ["ads", "image", "upload"],
|
|
2992
|
+
usage: "canonry ads image upload <project> --input <json-file|-> [--format json]",
|
|
2993
|
+
options: { input: stringOption() },
|
|
2994
|
+
run: async (input) => {
|
|
2995
|
+
const project = requireProject(input, "ads.image.upload", "canonry ads image upload <project> --input <json-file|-> [--format json]");
|
|
2996
|
+
await adsImageUpload(project, { input: getString(input.values, "input"), format: input.format });
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
{
|
|
3000
|
+
path: ["ads", "campaign", "create"],
|
|
3001
|
+
usage: "canonry ads campaign create <project> --input <json-file|-> [--format json]",
|
|
3002
|
+
options: { input: stringOption() },
|
|
3003
|
+
run: async (input) => {
|
|
3004
|
+
const project = requireProject(input, "ads.campaign.create", "canonry ads campaign create <project> --input <json-file|-> [--format json]");
|
|
3005
|
+
await adsCampaignCreate(project, { input: getString(input.values, "input"), format: input.format });
|
|
3006
|
+
}
|
|
3007
|
+
},
|
|
3008
|
+
{
|
|
3009
|
+
path: ["ads", "campaign", "update"],
|
|
3010
|
+
usage: "canonry ads campaign update <project> <campaign-id> --input <json-file|-> [--format json]",
|
|
3011
|
+
options: { input: stringOption() },
|
|
3012
|
+
run: async (input) => {
|
|
3013
|
+
const usage = "canonry ads campaign update <project> <campaign-id> --input <json-file|-> [--format json]";
|
|
3014
|
+
const project = requireProject(input, "ads.campaign.update", usage);
|
|
3015
|
+
const id = requirePositional(input, 1, { command: "ads.campaign.update", usage, message: "campaign id is required" });
|
|
3016
|
+
await adsCampaignUpdate(project, id, { input: getString(input.values, "input"), format: input.format });
|
|
3017
|
+
}
|
|
3018
|
+
},
|
|
3019
|
+
{
|
|
3020
|
+
path: ["ads", "campaign", "pause"],
|
|
3021
|
+
usage: "canonry ads campaign pause <project> <campaign-id> --input <json-file|-> [--format json]",
|
|
3022
|
+
options: { input: stringOption() },
|
|
3023
|
+
run: async (input) => {
|
|
3024
|
+
const usage = "canonry ads campaign pause <project> <campaign-id> --input <json-file|-> [--format json]";
|
|
3025
|
+
const project = requireProject(input, "ads.campaign.pause", usage);
|
|
3026
|
+
const id = requirePositional(input, 1, { command: "ads.campaign.pause", usage, message: "campaign id is required" });
|
|
3027
|
+
await adsCampaignPause(project, id, { input: getString(input.values, "input"), format: input.format });
|
|
3028
|
+
}
|
|
3029
|
+
},
|
|
3030
|
+
{
|
|
3031
|
+
path: ["ads", "ad-group", "create"],
|
|
3032
|
+
usage: "canonry ads ad-group create <project> --input <json-file|-> [--format json]",
|
|
3033
|
+
options: { input: stringOption() },
|
|
3034
|
+
run: async (input) => {
|
|
3035
|
+
const project = requireProject(input, "ads.ad-group.create", "canonry ads ad-group create <project> --input <json-file|-> [--format json]");
|
|
3036
|
+
await adsAdGroupCreate(project, { input: getString(input.values, "input"), format: input.format });
|
|
3037
|
+
}
|
|
3038
|
+
},
|
|
3039
|
+
{
|
|
3040
|
+
path: ["ads", "ad-group", "update"],
|
|
3041
|
+
usage: "canonry ads ad-group update <project> <ad-group-id> --input <json-file|-> [--format json]",
|
|
3042
|
+
options: { input: stringOption() },
|
|
3043
|
+
run: async (input) => {
|
|
3044
|
+
const usage = "canonry ads ad-group update <project> <ad-group-id> --input <json-file|-> [--format json]";
|
|
3045
|
+
const project = requireProject(input, "ads.ad-group.update", usage);
|
|
3046
|
+
const id = requirePositional(input, 1, { command: "ads.ad-group.update", usage, message: "ad group id is required" });
|
|
3047
|
+
await adsAdGroupUpdate(project, id, { input: getString(input.values, "input"), format: input.format });
|
|
3048
|
+
}
|
|
3049
|
+
},
|
|
3050
|
+
{
|
|
3051
|
+
path: ["ads", "ad-group", "pause"],
|
|
3052
|
+
usage: "canonry ads ad-group pause <project> <ad-group-id> --input <json-file|-> [--format json]",
|
|
3053
|
+
options: { input: stringOption() },
|
|
3054
|
+
run: async (input) => {
|
|
3055
|
+
const usage = "canonry ads ad-group pause <project> <ad-group-id> --input <json-file|-> [--format json]";
|
|
3056
|
+
const project = requireProject(input, "ads.ad-group.pause", usage);
|
|
3057
|
+
const id = requirePositional(input, 1, { command: "ads.ad-group.pause", usage, message: "ad group id is required" });
|
|
3058
|
+
await adsAdGroupPause(project, id, { input: getString(input.values, "input"), format: input.format });
|
|
3059
|
+
}
|
|
3060
|
+
},
|
|
3061
|
+
{
|
|
3062
|
+
path: ["ads", "ad", "create"],
|
|
3063
|
+
usage: "canonry ads ad create <project> --input <json-file|-> [--format json]",
|
|
3064
|
+
options: { input: stringOption() },
|
|
3065
|
+
run: async (input) => {
|
|
3066
|
+
const project = requireProject(input, "ads.ad.create", "canonry ads ad create <project> --input <json-file|-> [--format json]");
|
|
3067
|
+
await adsAdCreate(project, { input: getString(input.values, "input"), format: input.format });
|
|
3068
|
+
}
|
|
3069
|
+
},
|
|
3070
|
+
{
|
|
3071
|
+
path: ["ads", "ad", "update"],
|
|
3072
|
+
usage: "canonry ads ad update <project> <ad-id> --input <json-file|-> [--format json]",
|
|
3073
|
+
options: { input: stringOption() },
|
|
3074
|
+
run: async (input) => {
|
|
3075
|
+
const usage = "canonry ads ad update <project> <ad-id> --input <json-file|-> [--format json]";
|
|
3076
|
+
const project = requireProject(input, "ads.ad.update", usage);
|
|
3077
|
+
const id = requirePositional(input, 1, { command: "ads.ad.update", usage, message: "ad id is required" });
|
|
3078
|
+
await adsAdUpdate(project, id, { input: getString(input.values, "input"), format: input.format });
|
|
3079
|
+
}
|
|
3080
|
+
},
|
|
3081
|
+
{
|
|
3082
|
+
path: ["ads", "ad", "pause"],
|
|
3083
|
+
usage: "canonry ads ad pause <project> <ad-id> --input <json-file|-> [--format json]",
|
|
3084
|
+
options: { input: stringOption() },
|
|
3085
|
+
run: async (input) => {
|
|
3086
|
+
const usage = "canonry ads ad pause <project> <ad-id> --input <json-file|-> [--format json]";
|
|
3087
|
+
const project = requireProject(input, "ads.ad.pause", usage);
|
|
3088
|
+
const id = requirePositional(input, 1, { command: "ads.ad.pause", usage, message: "ad id is required" });
|
|
3089
|
+
await adsAdPause(project, id, { input: getString(input.values, "input"), format: input.format });
|
|
3090
|
+
}
|
|
3091
|
+
},
|
|
2888
3092
|
{
|
|
2889
3093
|
path: ["ads", "sync"],
|
|
2890
3094
|
usage: "canonry ads sync <project> [--format json]",
|
|
@@ -2948,9 +3152,9 @@ async function gaConnect(project, opts) {
|
|
|
2948
3152
|
propertyId: opts.propertyId
|
|
2949
3153
|
};
|
|
2950
3154
|
if (opts.keyFile) {
|
|
2951
|
-
const
|
|
3155
|
+
const fs15 = await import("fs");
|
|
2952
3156
|
try {
|
|
2953
|
-
const content =
|
|
3157
|
+
const content = fs15.readFileSync(opts.keyFile, "utf-8");
|
|
2954
3158
|
JSON.parse(content);
|
|
2955
3159
|
body.keyJson = content;
|
|
2956
3160
|
} catch (e) {
|
|
@@ -4202,9 +4406,9 @@ async function getCommand(opts) {
|
|
|
4202
4406
|
console.log(JSON.stringify(leaf, null, 2));
|
|
4203
4407
|
}
|
|
4204
4408
|
}
|
|
4205
|
-
function walkPath(value,
|
|
4206
|
-
if (!
|
|
4207
|
-
const segments =
|
|
4409
|
+
function walkPath(value, path11) {
|
|
4410
|
+
if (!path11 || path11 === ".") return value;
|
|
4411
|
+
const segments = path11.split(".").flatMap((part) => {
|
|
4208
4412
|
const tokens = [];
|
|
4209
4413
|
let i = 0;
|
|
4210
4414
|
const bracketStart = part.indexOf("[");
|
|
@@ -4252,13 +4456,13 @@ var GET_CLI_COMMANDS = [
|
|
|
4252
4456
|
},
|
|
4253
4457
|
run: async (input) => {
|
|
4254
4458
|
const project = requireProject(input, "get", USAGE2);
|
|
4255
|
-
const
|
|
4459
|
+
const path11 = requirePositional(input, 1, {
|
|
4256
4460
|
command: "get",
|
|
4257
4461
|
usage: USAGE2,
|
|
4258
4462
|
message: 'path is required (e.g. "scores.mentionShare.value")'
|
|
4259
4463
|
});
|
|
4260
4464
|
const from = getString(input.values, "from");
|
|
4261
|
-
await getCommand({ project, path:
|
|
4465
|
+
await getCommand({ project, path: path11, from, format: input.format });
|
|
4262
4466
|
}
|
|
4263
4467
|
}
|
|
4264
4468
|
];
|
|
@@ -4297,9 +4501,9 @@ async function trafficConnectWordpress(project, opts) {
|
|
|
4297
4501
|
}
|
|
4298
4502
|
let applicationPassword = opts.appPassword?.trim() ?? "";
|
|
4299
4503
|
if (!applicationPassword && opts.appPasswordFile) {
|
|
4300
|
-
const
|
|
4504
|
+
const fs15 = await import("fs");
|
|
4301
4505
|
try {
|
|
4302
|
-
applicationPassword =
|
|
4506
|
+
applicationPassword = fs15.readFileSync(opts.appPasswordFile, "utf-8").trim();
|
|
4303
4507
|
} catch (e) {
|
|
4304
4508
|
const msg = e instanceof Error ? e.message : String(e);
|
|
4305
4509
|
throw new CliError({
|
|
@@ -4355,10 +4559,10 @@ async function trafficConnectCloudRun(project, opts) {
|
|
|
4355
4559
|
details: { project }
|
|
4356
4560
|
});
|
|
4357
4561
|
}
|
|
4358
|
-
const
|
|
4562
|
+
const fs15 = await import("fs");
|
|
4359
4563
|
let keyJson;
|
|
4360
4564
|
try {
|
|
4361
|
-
keyJson =
|
|
4565
|
+
keyJson = fs15.readFileSync(opts.serviceAccountKey, "utf-8");
|
|
4362
4566
|
JSON.parse(keyJson);
|
|
4363
4567
|
} catch (e) {
|
|
4364
4568
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -4418,9 +4622,9 @@ async function trafficConnectVercel(project, opts) {
|
|
|
4418
4622
|
}
|
|
4419
4623
|
let token = opts.token?.trim() ?? "";
|
|
4420
4624
|
if (!token && opts.tokenFile) {
|
|
4421
|
-
const
|
|
4625
|
+
const fs15 = await import("fs");
|
|
4422
4626
|
try {
|
|
4423
|
-
token =
|
|
4627
|
+
token = fs15.readFileSync(opts.tokenFile, "utf-8").trim();
|
|
4424
4628
|
} catch (e) {
|
|
4425
4629
|
const msg = e instanceof Error ? e.message : String(e);
|
|
4426
4630
|
throw new CliError({
|
|
@@ -6238,7 +6442,7 @@ var KEYS_CLI_COMMANDS = [
|
|
|
6238
6442
|
];
|
|
6239
6443
|
|
|
6240
6444
|
// src/commands/keyword.ts
|
|
6241
|
-
import
|
|
6445
|
+
import fs4 from "fs";
|
|
6242
6446
|
function getClient12() {
|
|
6243
6447
|
return createApiClient();
|
|
6244
6448
|
}
|
|
@@ -6306,7 +6510,7 @@ async function listKeywords(project, format) {
|
|
|
6306
6510
|
}
|
|
6307
6511
|
}
|
|
6308
6512
|
async function importKeywords(project, filePath, format) {
|
|
6309
|
-
if (!
|
|
6513
|
+
if (!fs4.existsSync(filePath)) {
|
|
6310
6514
|
throw new CliError({
|
|
6311
6515
|
code: "KEYWORD_IMPORT_FILE_NOT_FOUND",
|
|
6312
6516
|
message: `File not found: ${filePath}`,
|
|
@@ -6317,7 +6521,7 @@ async function importKeywords(project, filePath, format) {
|
|
|
6317
6521
|
}
|
|
6318
6522
|
});
|
|
6319
6523
|
}
|
|
6320
|
-
const content =
|
|
6524
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
6321
6525
|
const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
6322
6526
|
if (keywords.length === 0) {
|
|
6323
6527
|
if (isMachineFormat(format)) {
|
|
@@ -6518,7 +6722,7 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
6518
6722
|
];
|
|
6519
6723
|
|
|
6520
6724
|
// src/commands/query.ts
|
|
6521
|
-
import
|
|
6725
|
+
import fs5 from "fs";
|
|
6522
6726
|
function getClient13() {
|
|
6523
6727
|
return createApiClient();
|
|
6524
6728
|
}
|
|
@@ -6609,7 +6813,7 @@ async function listQueries(project, format) {
|
|
|
6609
6813
|
}
|
|
6610
6814
|
}
|
|
6611
6815
|
async function importQueries(project, filePath, format) {
|
|
6612
|
-
if (!
|
|
6816
|
+
if (!fs5.existsSync(filePath)) {
|
|
6613
6817
|
throw new CliError({
|
|
6614
6818
|
code: "QUERY_IMPORT_FILE_NOT_FOUND",
|
|
6615
6819
|
message: `File not found: ${filePath}`,
|
|
@@ -6620,7 +6824,7 @@ async function importQueries(project, filePath, format) {
|
|
|
6620
6824
|
}
|
|
6621
6825
|
});
|
|
6622
6826
|
}
|
|
6623
|
-
const content =
|
|
6827
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
6624
6828
|
const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
6625
6829
|
if (queries2.length === 0) {
|
|
6626
6830
|
if (isMachineFormat(format)) {
|
|
@@ -6822,7 +7026,7 @@ var QUERY_CLI_COMMANDS = [
|
|
|
6822
7026
|
];
|
|
6823
7027
|
|
|
6824
7028
|
// src/commands/mcp.ts
|
|
6825
|
-
import
|
|
7029
|
+
import fs6 from "fs";
|
|
6826
7030
|
import path3 from "path";
|
|
6827
7031
|
import { createRequire } from "module";
|
|
6828
7032
|
|
|
@@ -6938,8 +7142,8 @@ function renderClientSnippet(client, serverName, entry) {
|
|
|
6938
7142
|
return renderJsonSnippet(serverName, entry, client.format);
|
|
6939
7143
|
}
|
|
6940
7144
|
function readJsonConfig(configPath) {
|
|
6941
|
-
if (!
|
|
6942
|
-
const raw =
|
|
7145
|
+
if (!fs6.existsSync(configPath)) return {};
|
|
7146
|
+
const raw = fs6.readFileSync(configPath, "utf-8").trim();
|
|
6943
7147
|
if (!raw) return {};
|
|
6944
7148
|
try {
|
|
6945
7149
|
const parsed = JSON.parse(raw);
|
|
@@ -6957,14 +7161,14 @@ function readJsonConfig(configPath) {
|
|
|
6957
7161
|
}
|
|
6958
7162
|
}
|
|
6959
7163
|
function writeJsonConfig(configPath, value) {
|
|
6960
|
-
|
|
6961
|
-
|
|
7164
|
+
fs6.mkdirSync(path3.dirname(configPath), { recursive: true });
|
|
7165
|
+
fs6.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
6962
7166
|
`, "utf-8");
|
|
6963
7167
|
}
|
|
6964
7168
|
function backupConfigIfPresent(configPath) {
|
|
6965
|
-
if (!
|
|
7169
|
+
if (!fs6.existsSync(configPath)) return void 0;
|
|
6966
7170
|
const backupPath = `${configPath}.canonry.bak`;
|
|
6967
|
-
|
|
7171
|
+
fs6.copyFileSync(configPath, backupPath);
|
|
6968
7172
|
return backupPath;
|
|
6969
7173
|
}
|
|
6970
7174
|
function findClientOrThrow(id) {
|
|
@@ -7318,13 +7522,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
7318
7522
|
];
|
|
7319
7523
|
|
|
7320
7524
|
// src/commands/apply.ts
|
|
7321
|
-
import
|
|
7525
|
+
import fs7 from "fs";
|
|
7322
7526
|
import { parseAllDocuments } from "yaml";
|
|
7323
7527
|
async function applyConfigFile(filePath) {
|
|
7324
|
-
if (!
|
|
7528
|
+
if (!fs7.existsSync(filePath)) {
|
|
7325
7529
|
throw new Error(`File not found: ${filePath}`);
|
|
7326
7530
|
}
|
|
7327
|
-
const content =
|
|
7531
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
7328
7532
|
const docs = parseAllDocuments(content);
|
|
7329
7533
|
const client = createApiClient();
|
|
7330
7534
|
const errors = [];
|
|
@@ -7641,43 +7845,68 @@ async function loadLatestRunForExport(client, project) {
|
|
|
7641
7845
|
return client.getRun(latestRun.id);
|
|
7642
7846
|
}
|
|
7643
7847
|
|
|
7848
|
+
// src/commands/results-export.ts
|
|
7849
|
+
import fs8 from "fs";
|
|
7850
|
+
import path4 from "path";
|
|
7851
|
+
async function exportResults(project, opts) {
|
|
7852
|
+
const { output, ...request } = opts;
|
|
7853
|
+
const artifact = await createApiClient().downloadResultsExport(project, request);
|
|
7854
|
+
if (output === "-") {
|
|
7855
|
+
process.stdout.write(artifact.content);
|
|
7856
|
+
return;
|
|
7857
|
+
}
|
|
7858
|
+
const target = output ? path4.resolve(output) : path4.resolve(process.cwd(), path4.basename(artifact.filename));
|
|
7859
|
+
fs8.mkdirSync(path4.dirname(target), { recursive: true });
|
|
7860
|
+
fs8.writeFileSync(target, artifact.content, "utf8");
|
|
7861
|
+
console.log(`Results export written to ${target}`);
|
|
7862
|
+
}
|
|
7863
|
+
|
|
7644
7864
|
// src/commands/history.ts
|
|
7645
7865
|
function getClient18() {
|
|
7646
7866
|
return createApiClient();
|
|
7647
7867
|
}
|
|
7648
|
-
|
|
7868
|
+
function originLabel(entry) {
|
|
7869
|
+
const userAgent = entry.userAgent?.toLowerCase() ?? "";
|
|
7870
|
+
if (userAgent.includes("canonry-mcp")) return "mcp";
|
|
7871
|
+
if (userAgent.includes("canonry-cli")) return "cli";
|
|
7872
|
+
if (userAgent.includes("mozilla/")) return "dashboard";
|
|
7873
|
+
return entry.actor;
|
|
7874
|
+
}
|
|
7875
|
+
async function showHistory(project, format, opts = {}) {
|
|
7649
7876
|
const client = getClient18();
|
|
7650
7877
|
try {
|
|
7651
|
-
const entries = await client.getHistory(project);
|
|
7878
|
+
const entries = project ? await client.getHistory(project, opts) : await client.getGlobalHistory(opts);
|
|
7652
7879
|
if (format === "json") {
|
|
7653
7880
|
console.log(JSON.stringify(entries, null, 2));
|
|
7654
7881
|
return;
|
|
7655
7882
|
}
|
|
7656
7883
|
if (format === "jsonl") {
|
|
7657
|
-
emitJsonl(entries.map((entry) => ({ project, ...entry })));
|
|
7884
|
+
emitJsonl(entries.map((entry) => ({ project: project ?? null, ...entry })));
|
|
7658
7885
|
return;
|
|
7659
7886
|
}
|
|
7660
7887
|
if (entries.length === 0) {
|
|
7661
|
-
console.log(`No audit history for "${project}".`);
|
|
7888
|
+
console.log(project ? `No audit history for "${project}".` : "No instance audit history.");
|
|
7662
7889
|
return;
|
|
7663
7890
|
}
|
|
7664
|
-
console.log(`Audit history for "${project}" (${entries.length}):
|
|
7891
|
+
console.log(`${project ? `Audit history for "${project}"` : "Instance audit history"} (${entries.length}):
|
|
7665
7892
|
`);
|
|
7666
|
-
console.log(" TIMESTAMP ACTION ENTITY TYPE
|
|
7667
|
-
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500");
|
|
7893
|
+
console.log(" TIMESTAMP ACTION ENTITY TYPE ORIGIN");
|
|
7894
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7668
7895
|
for (const entry of entries) {
|
|
7669
7896
|
console.log(
|
|
7670
|
-
` ${entry.createdAt.padEnd(23)} ${entry.action.padEnd(18)} ${entry.entityType.padEnd(11)} ${entry
|
|
7897
|
+
` ${entry.createdAt.padEnd(23)} ${entry.action.padEnd(18)} ${entry.entityType.padEnd(11)} ${originLabel(entry)}`
|
|
7671
7898
|
);
|
|
7899
|
+
if (entry.actorSession) console.log(` session: ${entry.actorSession}`);
|
|
7900
|
+
if (entry.diff != null) console.log(` diff: ${JSON.stringify(entry.diff)}`);
|
|
7672
7901
|
}
|
|
7673
7902
|
} catch (err) {
|
|
7674
7903
|
const message = err instanceof Error ? err.message : String(err);
|
|
7675
7904
|
throw new CliError({
|
|
7676
7905
|
code: "HISTORY_FETCH_FAILED",
|
|
7677
|
-
message: `Failed to fetch history for project "${project}"
|
|
7906
|
+
message: project ? `Failed to fetch history for project "${project}"` : "Failed to fetch instance history",
|
|
7678
7907
|
displayMessage: `Failed to fetch history: ${message}`,
|
|
7679
7908
|
details: {
|
|
7680
|
-
project,
|
|
7909
|
+
project: project ?? null,
|
|
7681
7910
|
cause: message
|
|
7682
7911
|
}
|
|
7683
7912
|
});
|
|
@@ -7746,7 +7975,35 @@ async function getLatestRunSummary(client, project) {
|
|
|
7746
7975
|
}
|
|
7747
7976
|
|
|
7748
7977
|
// src/cli-commands/operator.ts
|
|
7978
|
+
var RESULTS_EXPORT_USAGE = "canonry results export <project> [--format json|csv] [--since <ISO>] [--until <ISO>] [--include-probes] [--output <path>|-]";
|
|
7979
|
+
function parseResultsExportFormat(value) {
|
|
7980
|
+
if (value === void 0 || value === "json") return "json";
|
|
7981
|
+
if (value === "csv") return "csv";
|
|
7982
|
+
throw usageError(`Error: --format must be "json" or "csv"
|
|
7983
|
+
|
|
7984
|
+
Usage: ${RESULTS_EXPORT_USAGE}`);
|
|
7985
|
+
}
|
|
7749
7986
|
var OPERATOR_CLI_COMMANDS = [
|
|
7987
|
+
{
|
|
7988
|
+
path: ["results", "export"],
|
|
7989
|
+
usage: RESULTS_EXPORT_USAGE,
|
|
7990
|
+
options: {
|
|
7991
|
+
since: stringOption(),
|
|
7992
|
+
until: stringOption(),
|
|
7993
|
+
"include-probes": { type: "boolean", default: false },
|
|
7994
|
+
output: { type: "string", short: "o" }
|
|
7995
|
+
},
|
|
7996
|
+
run: async (input) => {
|
|
7997
|
+
const project = requireProject(input, "results export", RESULTS_EXPORT_USAGE);
|
|
7998
|
+
await exportResults(project, {
|
|
7999
|
+
format: parseResultsExportFormat(getString(input.values, "format")),
|
|
8000
|
+
since: getString(input.values, "since"),
|
|
8001
|
+
until: getString(input.values, "until"),
|
|
8002
|
+
includeProbes: getBoolean(input.values, "include-probes"),
|
|
8003
|
+
output: getString(input.values, "output")
|
|
8004
|
+
});
|
|
8005
|
+
}
|
|
8006
|
+
},
|
|
7750
8007
|
{
|
|
7751
8008
|
path: ["status"],
|
|
7752
8009
|
usage: "canonry status <project> [--format json]",
|
|
@@ -7765,10 +8022,25 @@ var OPERATOR_CLI_COMMANDS = [
|
|
|
7765
8022
|
},
|
|
7766
8023
|
{
|
|
7767
8024
|
path: ["history"],
|
|
7768
|
-
usage: "canonry history <project> [--format json]",
|
|
8025
|
+
usage: "canonry history <project> [--limit <n>] [--since <ISO>] [--action <action>] [--actor <actor>] [--entity-type <type>] [--format json|jsonl]\n canonry history --all [same filters]",
|
|
8026
|
+
options: {
|
|
8027
|
+
all: { type: "boolean", default: false },
|
|
8028
|
+
limit: stringOption(),
|
|
8029
|
+
since: stringOption(),
|
|
8030
|
+
action: stringOption(),
|
|
8031
|
+
actor: stringOption(),
|
|
8032
|
+
"entity-type": stringOption()
|
|
8033
|
+
},
|
|
7769
8034
|
run: async (input) => {
|
|
7770
|
-
const
|
|
7771
|
-
|
|
8035
|
+
const usage = "canonry history <project> [--limit <n>] [--since <ISO>] [--action <action>] [--actor <actor>] [--entity-type <type>] [--format json|jsonl]\n canonry history --all [same filters]";
|
|
8036
|
+
const project = getBoolean(input.values, "all") ? void 0 : requireProject(input, "history", usage);
|
|
8037
|
+
await showHistory(project, input.format, {
|
|
8038
|
+
limit: parseIntegerOption(input, "limit", { command: "history", usage, message: "--limit must be an integer" }),
|
|
8039
|
+
since: getString(input.values, "since"),
|
|
8040
|
+
action: getString(input.values, "action"),
|
|
8041
|
+
actor: getString(input.values, "actor"),
|
|
8042
|
+
entityType: getString(input.values, "entity-type")
|
|
8043
|
+
});
|
|
7772
8044
|
}
|
|
7773
8045
|
},
|
|
7774
8046
|
{
|
|
@@ -8239,11 +8511,11 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
8239
8511
|
];
|
|
8240
8512
|
|
|
8241
8513
|
// src/commands/report.ts
|
|
8242
|
-
import
|
|
8243
|
-
import
|
|
8514
|
+
import fs9 from "fs";
|
|
8515
|
+
import path5 from "path";
|
|
8244
8516
|
function defaultOutputPath(project, audience) {
|
|
8245
8517
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8246
|
-
return
|
|
8518
|
+
return path5.resolve(process.cwd(), `canonry-report-${project}-${audience}-${date}.html`);
|
|
8247
8519
|
}
|
|
8248
8520
|
async function runReportCommand(project, opts = {}) {
|
|
8249
8521
|
const client = createApiClient();
|
|
@@ -8254,12 +8526,12 @@ async function runReportCommand(project, opts = {}) {
|
|
|
8254
8526
|
return;
|
|
8255
8527
|
}
|
|
8256
8528
|
const html = renderReportHtml(report, { audience });
|
|
8257
|
-
const targetPath = opts.output ?
|
|
8258
|
-
const dir =
|
|
8259
|
-
if (!
|
|
8260
|
-
|
|
8529
|
+
const targetPath = opts.output ? path5.resolve(opts.output) : defaultOutputPath(project, audience);
|
|
8530
|
+
const dir = path5.dirname(targetPath);
|
|
8531
|
+
if (!fs9.existsSync(dir)) {
|
|
8532
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
8261
8533
|
}
|
|
8262
|
-
|
|
8534
|
+
fs9.writeFileSync(targetPath, html, "utf-8");
|
|
8263
8535
|
console.log(`Report written to ${targetPath}`);
|
|
8264
8536
|
}
|
|
8265
8537
|
|
|
@@ -9124,12 +9396,12 @@ var SKILLS_CLI_COMMANDS = [
|
|
|
9124
9396
|
];
|
|
9125
9397
|
|
|
9126
9398
|
// src/commands/snapshot.ts
|
|
9127
|
-
import
|
|
9128
|
-
import
|
|
9399
|
+
import fs11 from "fs";
|
|
9400
|
+
import path7 from "path";
|
|
9129
9401
|
|
|
9130
9402
|
// src/snapshot-pdf.ts
|
|
9131
|
-
import
|
|
9132
|
-
import
|
|
9403
|
+
import fs10 from "fs";
|
|
9404
|
+
import path6 from "path";
|
|
9133
9405
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
9134
9406
|
var PAGE_WIDTH = 612;
|
|
9135
9407
|
var PAGE_HEIGHT = 792;
|
|
@@ -9341,9 +9613,9 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
9341
9613
|
renderCompetitors(pdf, report);
|
|
9342
9614
|
renderQueries(pdf, report);
|
|
9343
9615
|
const bytes = await doc.save();
|
|
9344
|
-
const resolvedPath =
|
|
9345
|
-
|
|
9346
|
-
|
|
9616
|
+
const resolvedPath = path6.resolve(outputPath);
|
|
9617
|
+
fs10.mkdirSync(path6.dirname(resolvedPath), { recursive: true });
|
|
9618
|
+
fs10.writeFileSync(resolvedPath, bytes);
|
|
9347
9619
|
return resolvedPath;
|
|
9348
9620
|
}
|
|
9349
9621
|
function renderCover(pdf, report) {
|
|
@@ -9501,9 +9773,9 @@ Markdown saved: ${savedMdPath}`);
|
|
|
9501
9773
|
PDF saved: ${savedPdfPath}`);
|
|
9502
9774
|
}
|
|
9503
9775
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
9504
|
-
const resolvedPath =
|
|
9505
|
-
|
|
9506
|
-
|
|
9776
|
+
const resolvedPath = path7.resolve(outputPath);
|
|
9777
|
+
fs11.mkdirSync(path7.dirname(resolvedPath), { recursive: true });
|
|
9778
|
+
fs11.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
9507
9779
|
return resolvedPath;
|
|
9508
9780
|
}
|
|
9509
9781
|
function formatSnapshotMarkdown(report) {
|
|
@@ -10486,7 +10758,7 @@ var CONTENT_CLI_COMMANDS = [
|
|
|
10486
10758
|
|
|
10487
10759
|
// src/commands/bootstrap.ts
|
|
10488
10760
|
import crypto from "crypto";
|
|
10489
|
-
import
|
|
10761
|
+
import path8 from "path";
|
|
10490
10762
|
import { eq } from "drizzle-orm";
|
|
10491
10763
|
|
|
10492
10764
|
// ../config/src/index.ts
|
|
@@ -10643,7 +10915,7 @@ async function bootstrapCommand(_opts) {
|
|
|
10643
10915
|
);
|
|
10644
10916
|
}
|
|
10645
10917
|
const configDir = getConfigDir();
|
|
10646
|
-
const databasePath = env.databasePath ||
|
|
10918
|
+
const databasePath = env.databasePath || path8.join(configDir, "data.db");
|
|
10647
10919
|
const existing = configExists();
|
|
10648
10920
|
const existingConfig = existing ? loadConfig() : void 0;
|
|
10649
10921
|
let rawApiKey;
|
|
@@ -10713,10 +10985,10 @@ async function bootstrapCommand(_opts) {
|
|
|
10713
10985
|
|
|
10714
10986
|
// src/commands/daemon.ts
|
|
10715
10987
|
import { spawn } from "child_process";
|
|
10716
|
-
import
|
|
10717
|
-
import
|
|
10988
|
+
import fs12 from "fs";
|
|
10989
|
+
import path9 from "path";
|
|
10718
10990
|
function getPidPath() {
|
|
10719
|
-
return
|
|
10991
|
+
return path9.join(getConfigDir(), "canonry.pid");
|
|
10720
10992
|
}
|
|
10721
10993
|
function isProcessAlive(pid) {
|
|
10722
10994
|
try {
|
|
@@ -10756,8 +11028,8 @@ function buildServeForwardArgs(opts) {
|
|
|
10756
11028
|
async function startDaemon(opts) {
|
|
10757
11029
|
const pidPath = getPidPath();
|
|
10758
11030
|
const format = opts.format ?? "text";
|
|
10759
|
-
if (
|
|
10760
|
-
const existingPid = parseInt(
|
|
11031
|
+
if (fs12.existsSync(pidPath)) {
|
|
11032
|
+
const existingPid = parseInt(fs12.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
10761
11033
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
10762
11034
|
throw new CliError({
|
|
10763
11035
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -10768,9 +11040,9 @@ async function startDaemon(opts) {
|
|
|
10768
11040
|
}
|
|
10769
11041
|
});
|
|
10770
11042
|
}
|
|
10771
|
-
|
|
11043
|
+
fs12.unlinkSync(pidPath);
|
|
10772
11044
|
}
|
|
10773
|
-
const cliPath =
|
|
11045
|
+
const cliPath = path9.resolve(new URL(import.meta.url).pathname);
|
|
10774
11046
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
10775
11047
|
const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
|
|
10776
11048
|
args.push(...buildServeForwardArgs(opts));
|
|
@@ -10787,10 +11059,10 @@ async function startDaemon(opts) {
|
|
|
10787
11059
|
});
|
|
10788
11060
|
}
|
|
10789
11061
|
const configDir = getConfigDir();
|
|
10790
|
-
if (!
|
|
10791
|
-
|
|
11062
|
+
if (!fs12.existsSync(configDir)) {
|
|
11063
|
+
fs12.mkdirSync(configDir, { recursive: true });
|
|
10792
11064
|
}
|
|
10793
|
-
|
|
11065
|
+
fs12.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
10794
11066
|
const port = opts.port ?? "4100";
|
|
10795
11067
|
const host = opts.host ?? "127.0.0.1";
|
|
10796
11068
|
if (!isMachineFormat(format)) {
|
|
@@ -10799,7 +11071,7 @@ async function startDaemon(opts) {
|
|
|
10799
11071
|
const ready = await waitForReady(host, port);
|
|
10800
11072
|
if (!ready) {
|
|
10801
11073
|
try {
|
|
10802
|
-
|
|
11074
|
+
fs12.unlinkSync(pidPath);
|
|
10803
11075
|
} catch {
|
|
10804
11076
|
}
|
|
10805
11077
|
throw new CliError({
|
|
@@ -10831,7 +11103,7 @@ async function startDaemon(opts) {
|
|
|
10831
11103
|
}
|
|
10832
11104
|
function stopDaemon(format = "text") {
|
|
10833
11105
|
const pidPath = getPidPath();
|
|
10834
|
-
if (!
|
|
11106
|
+
if (!fs12.existsSync(pidPath)) {
|
|
10835
11107
|
if (isMachineFormat(format)) {
|
|
10836
11108
|
console.log(JSON.stringify({
|
|
10837
11109
|
stopped: false,
|
|
@@ -10842,7 +11114,7 @@ function stopDaemon(format = "text") {
|
|
|
10842
11114
|
console.log("Canonry is not running (no PID file found)");
|
|
10843
11115
|
return;
|
|
10844
11116
|
}
|
|
10845
|
-
const pid = parseInt(
|
|
11117
|
+
const pid = parseInt(fs12.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
10846
11118
|
if (isNaN(pid)) {
|
|
10847
11119
|
if (isMachineFormat(format)) {
|
|
10848
11120
|
console.log(JSON.stringify({
|
|
@@ -10853,7 +11125,7 @@ function stopDaemon(format = "text") {
|
|
|
10853
11125
|
} else {
|
|
10854
11126
|
console.error("Invalid PID file. Removing it.");
|
|
10855
11127
|
}
|
|
10856
|
-
|
|
11128
|
+
fs12.unlinkSync(pidPath);
|
|
10857
11129
|
return;
|
|
10858
11130
|
}
|
|
10859
11131
|
if (!isProcessAlive(pid)) {
|
|
@@ -10867,12 +11139,12 @@ function stopDaemon(format = "text") {
|
|
|
10867
11139
|
} else {
|
|
10868
11140
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
10869
11141
|
}
|
|
10870
|
-
|
|
11142
|
+
fs12.unlinkSync(pidPath);
|
|
10871
11143
|
return;
|
|
10872
11144
|
}
|
|
10873
11145
|
try {
|
|
10874
11146
|
process.kill(pid, "SIGTERM");
|
|
10875
|
-
|
|
11147
|
+
fs12.unlinkSync(pidPath);
|
|
10876
11148
|
if (isMachineFormat(format)) {
|
|
10877
11149
|
console.log(JSON.stringify({
|
|
10878
11150
|
stopped: true,
|
|
@@ -10896,9 +11168,9 @@ function stopDaemon(format = "text") {
|
|
|
10896
11168
|
|
|
10897
11169
|
// src/commands/init.ts
|
|
10898
11170
|
import crypto2 from "crypto";
|
|
10899
|
-
import
|
|
11171
|
+
import fs13 from "fs";
|
|
10900
11172
|
import readline from "readline";
|
|
10901
|
-
import
|
|
11173
|
+
import path10 from "path";
|
|
10902
11174
|
function prompt(question) {
|
|
10903
11175
|
const rl = readline.createInterface({
|
|
10904
11176
|
input: process.stdin,
|
|
@@ -10919,8 +11191,8 @@ var DEFAULT_QUOTA = {
|
|
|
10919
11191
|
var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
|
|
10920
11192
|
function cwdLooksLikeProject(dir) {
|
|
10921
11193
|
const home = process.env.HOME ?? "";
|
|
10922
|
-
if (home &&
|
|
10923
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
11194
|
+
if (home && path10.resolve(dir) === path10.resolve(home)) return false;
|
|
11195
|
+
return PROJECT_MARKERS.some((marker) => fs13.existsSync(path10.join(dir, marker)));
|
|
10924
11196
|
}
|
|
10925
11197
|
var DEFAULT_AGENT_MODELS = {
|
|
10926
11198
|
anthropic: "anthropic/claude-sonnet-4-6",
|
|
@@ -10951,8 +11223,8 @@ async function initCommand(opts) {
|
|
|
10951
11223
|
return void 0;
|
|
10952
11224
|
}
|
|
10953
11225
|
const configDir = getConfigDir();
|
|
10954
|
-
if (!
|
|
10955
|
-
|
|
11226
|
+
if (!fs13.existsSync(configDir)) {
|
|
11227
|
+
fs13.mkdirSync(configDir, { recursive: true });
|
|
10956
11228
|
}
|
|
10957
11229
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
10958
11230
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -11067,7 +11339,7 @@ async function initCommand(opts) {
|
|
|
11067
11339
|
const rawApiKey = `cnry_${crypto2.randomBytes(16).toString("hex")}`;
|
|
11068
11340
|
const keyHash = crypto2.createHash("sha256").update(rawApiKey).digest("hex");
|
|
11069
11341
|
const keyPrefix = rawApiKey.slice(0, 9);
|
|
11070
|
-
const databasePath =
|
|
11342
|
+
const databasePath = path10.join(configDir, "data.db");
|
|
11071
11343
|
const db = createClient(databasePath);
|
|
11072
11344
|
migrate(db);
|
|
11073
11345
|
db.insert(apiKeys).values({
|
|
@@ -11619,7 +11891,7 @@ function getClient25() {
|
|
|
11619
11891
|
}
|
|
11620
11892
|
async function technicalAeoScore(project, opts) {
|
|
11621
11893
|
const client = getClient25();
|
|
11622
|
-
const score = await client.getTechnicalAeoScore(project);
|
|
11894
|
+
const score = await client.getTechnicalAeoScore(project, { runId: opts.runId });
|
|
11623
11895
|
if (isMachineFormat(opts.format)) {
|
|
11624
11896
|
console.log(JSON.stringify(score, null, 2));
|
|
11625
11897
|
return;
|
|
@@ -11656,7 +11928,7 @@ async function technicalAeoScore(project, opts) {
|
|
|
11656
11928
|
async function technicalAeoPages(project, opts) {
|
|
11657
11929
|
const client = getClient25();
|
|
11658
11930
|
const status = opts.status === "success" || opts.status === "error" ? opts.status : void 0;
|
|
11659
|
-
const res = await client.getTechnicalAeoPages(project, { status, sort: opts.sort, limit: opts.limit });
|
|
11931
|
+
const res = await client.getTechnicalAeoPages(project, { runId: opts.runId, status, sort: opts.sort, limit: opts.limit });
|
|
11660
11932
|
if (opts.format === "jsonl") {
|
|
11661
11933
|
emitJsonl(res.pages.map((p) => ({ project, runId: res.runId, ...p })));
|
|
11662
11934
|
return;
|
|
@@ -11740,28 +12012,33 @@ async function technicalAeoRun(project, opts) {
|
|
|
11740
12012
|
var TECHNICAL_AEO_CLI_COMMANDS = [
|
|
11741
12013
|
{
|
|
11742
12014
|
path: ["technical-aeo", "score"],
|
|
11743
|
-
usage: "canonry technical-aeo score <project> [--format json]",
|
|
12015
|
+
usage: "canonry technical-aeo score <project> [--run-id <id>] [--format json]",
|
|
12016
|
+
options: {
|
|
12017
|
+
"run-id": stringOption()
|
|
12018
|
+
},
|
|
11744
12019
|
run: async (input) => {
|
|
11745
12020
|
const project = requireProject(
|
|
11746
12021
|
input,
|
|
11747
12022
|
"technical-aeo.score",
|
|
11748
|
-
"canonry technical-aeo score <project> [--format json]"
|
|
12023
|
+
"canonry technical-aeo score <project> [--run-id <id>] [--format json]"
|
|
11749
12024
|
);
|
|
11750
|
-
await technicalAeoScore(project, { format: input.format });
|
|
12025
|
+
await technicalAeoScore(project, { runId: getString(input.values, "run-id"), format: input.format });
|
|
11751
12026
|
}
|
|
11752
12027
|
},
|
|
11753
12028
|
{
|
|
11754
12029
|
path: ["technical-aeo", "pages"],
|
|
11755
|
-
usage: "canonry technical-aeo pages <project> [--status success|error] [--sort score-asc|score-desc|url] [--limit <n>] [--format json|jsonl]",
|
|
12030
|
+
usage: "canonry technical-aeo pages <project> [--run-id <id>] [--status success|error] [--sort score-asc|score-desc|url] [--limit <n>] [--format json|jsonl]",
|
|
11756
12031
|
options: {
|
|
12032
|
+
"run-id": stringOption(),
|
|
11757
12033
|
status: stringOption(),
|
|
11758
12034
|
sort: stringOption(),
|
|
11759
12035
|
limit: stringOption()
|
|
11760
12036
|
},
|
|
11761
12037
|
run: async (input) => {
|
|
11762
|
-
const usage = "canonry technical-aeo pages <project> [--status success|error] [--sort score-asc|score-desc|url] [--limit <n>] [--format json|jsonl]";
|
|
12038
|
+
const usage = "canonry technical-aeo pages <project> [--run-id <id>] [--status success|error] [--sort score-asc|score-desc|url] [--limit <n>] [--format json|jsonl]";
|
|
11763
12039
|
const project = requireProject(input, "technical-aeo.pages", usage);
|
|
11764
12040
|
await technicalAeoPages(project, {
|
|
12041
|
+
runId: getString(input.values, "run-id"),
|
|
11765
12042
|
status: getString(input.values, "status"),
|
|
11766
12043
|
sort: getString(input.values, "sort"),
|
|
11767
12044
|
limit: parseIntegerOption(input, "limit", {
|
|
@@ -12053,7 +12330,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
|
12053
12330
|
];
|
|
12054
12331
|
|
|
12055
12332
|
// src/cli-commands/wordpress.ts
|
|
12056
|
-
import
|
|
12333
|
+
import fs14 from "fs";
|
|
12057
12334
|
|
|
12058
12335
|
// src/commands/wordpress.ts
|
|
12059
12336
|
function getClient26() {
|
|
@@ -12292,12 +12569,12 @@ async function wordpressSetMeta(project, body) {
|
|
|
12292
12569
|
printPageDetail(result);
|
|
12293
12570
|
}
|
|
12294
12571
|
async function wordpressBulkSetMeta(project, opts) {
|
|
12295
|
-
const
|
|
12296
|
-
const
|
|
12297
|
-
const filePath =
|
|
12572
|
+
const fs15 = await import("fs/promises");
|
|
12573
|
+
const path11 = await import("path");
|
|
12574
|
+
const filePath = path11.resolve(opts.from);
|
|
12298
12575
|
let raw;
|
|
12299
12576
|
try {
|
|
12300
|
-
raw = await
|
|
12577
|
+
raw = await fs15.readFile(filePath, "utf8");
|
|
12301
12578
|
} catch {
|
|
12302
12579
|
throw new CliError({
|
|
12303
12580
|
code: "FILE_READ_ERROR",
|
|
@@ -12394,13 +12671,13 @@ async function wordpressSetSchema(project, body) {
|
|
|
12394
12671
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
12395
12672
|
}
|
|
12396
12673
|
async function wordpressSchemaDeploy(project, opts) {
|
|
12397
|
-
const
|
|
12398
|
-
const
|
|
12674
|
+
const fs15 = await import("fs/promises");
|
|
12675
|
+
const path11 = await import("path");
|
|
12399
12676
|
const yaml = await loadYamlModule();
|
|
12400
|
-
const filePath =
|
|
12677
|
+
const filePath = path11.resolve(opts.profile);
|
|
12401
12678
|
let raw;
|
|
12402
12679
|
try {
|
|
12403
|
-
raw = await
|
|
12680
|
+
raw = await fs15.readFile(filePath, "utf8");
|
|
12404
12681
|
} catch {
|
|
12405
12682
|
throw new CliError({
|
|
12406
12683
|
code: "FILE_READ_ERROR",
|
|
@@ -12505,13 +12782,13 @@ async function wordpressOnboard(project, opts) {
|
|
|
12505
12782
|
}
|
|
12506
12783
|
let profileData;
|
|
12507
12784
|
if (opts.profile) {
|
|
12508
|
-
const
|
|
12509
|
-
const
|
|
12785
|
+
const fs15 = await import("fs/promises");
|
|
12786
|
+
const path11 = await import("path");
|
|
12510
12787
|
const yaml = await loadYamlModule();
|
|
12511
|
-
const filePath =
|
|
12788
|
+
const filePath = path11.resolve(opts.profile);
|
|
12512
12789
|
let raw;
|
|
12513
12790
|
try {
|
|
12514
|
-
raw = await
|
|
12791
|
+
raw = await fs15.readFile(filePath, "utf8");
|
|
12515
12792
|
} catch {
|
|
12516
12793
|
throw new CliError({
|
|
12517
12794
|
code: "FILE_READ_ERROR",
|
|
@@ -12660,7 +12937,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
12660
12937
|
}
|
|
12661
12938
|
if (contentFile) {
|
|
12662
12939
|
try {
|
|
12663
|
-
return
|
|
12940
|
+
return fs14.readFileSync(contentFile, "utf-8");
|
|
12664
12941
|
} catch (error) {
|
|
12665
12942
|
const message = error instanceof Error ? error.message : String(error);
|
|
12666
12943
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|