@canonry/canonry 7.22.0 → 7.24.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 +14 -0
- package/assets/assets/{AuditHistoryPanel-J8AR3x5F.js → AuditHistoryPanel-DKKnX8IT.js} +1 -1
- package/assets/assets/{BacklinksPage-CRDPutGA.js → BacklinksPage-DNbur8am.js} +1 -1
- package/assets/assets/{HistoryPage-C5taVW3t.js → HistoryPage-DahtHlpM.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-txucmLuz.js → MeasurementPropertyPage-BoNDtLfp.js} +1 -1
- package/assets/assets/{ProjectPage-C4FaBoWI.js → ProjectPage--ZlpQduH.js} +1 -1
- package/assets/assets/{RunsPage-D-3XKUhh.js → RunsPage-DKB2CHTM.js} +1 -1
- package/assets/assets/{SettingsPage-Cq_SJRj_.js → SettingsPage-lnmMZzEj.js} +1 -1
- package/assets/assets/{SiteHealthSection-Cn_IZVO1.js → SiteHealthSection-BBjucRed.js} +3 -3
- package/assets/assets/{TrafficPage-BMdFZs3X.js → TrafficPage-DNyTmPLd.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BmrIOc-2.js → TrafficSourceDetailPage-D1zKZHSh.js} +1 -1
- package/assets/assets/{extract-error-message-HlQy5L7O.js → extract-error-message-v0b8P-wc.js} +1 -1
- package/assets/assets/index-CfaBRiBG.js +86 -0
- package/assets/assets/{react-sigma_core.esm.min-CogAr1i4.js → react-sigma_core.esm.min-BZSJoRrV.js} +1 -1
- package/assets/assets/{v2-overview-adapter-tps7TUxq.js → v2-overview-adapter-DXAl-O_h.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-222NAFTY.js → chunk-7Q7QCBJ3.js} +2 -2
- package/dist/{chunk-5IXQAOVK.js → chunk-DS2ZKB3T.js} +15 -6
- package/dist/{chunk-MRKV43TV.js → chunk-IM2BFAAT.js} +565 -206
- package/dist/{chunk-NDQOCFJQ.js → chunk-JJBVYL45.js} +39 -4
- package/dist/{chunk-46JZR2IV.js → chunk-O5UMRQVN.js} +1303 -504
- package/dist/{chunk-6Z2LFFRT.js → chunk-SG3MPCDL.js} +5731 -4596
- package/dist/{chunk-6H2BC5EY.js → chunk-YCPTP2NC.js} +3 -3
- package/dist/cli.js +371 -143
- package/dist/{demo-server-32PU7BM6.js → demo-server-C7UGXXN7.js} +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-256DQBVR.js → intelligence-service-37TX4YV7.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +13 -13
- package/assets/assets/index-BJcjB5XW.js +0 -86
package/dist/cli.js
CHANGED
|
@@ -14,13 +14,16 @@ import {
|
|
|
14
14
|
getOrCreateAnonymousId,
|
|
15
15
|
getPrintedUpdateAvailable,
|
|
16
16
|
getTelemetryStatus,
|
|
17
|
+
installAttribution,
|
|
17
18
|
isAeroToolProfile,
|
|
18
19
|
isFirstRun,
|
|
19
20
|
isLoopbackBindHost,
|
|
20
21
|
isTelemetryEnabled,
|
|
21
22
|
listAgentProviders,
|
|
22
23
|
notePrintedUpdateAvailable,
|
|
24
|
+
outcomeFailure,
|
|
23
25
|
readCachedUpdateAvailable,
|
|
26
|
+
recordInstallRef,
|
|
24
27
|
registeredProviderNames,
|
|
25
28
|
reparseStoredResult,
|
|
26
29
|
reparseStoredResult2,
|
|
@@ -34,13 +37,16 @@ import {
|
|
|
34
37
|
showFirstRunNotice,
|
|
35
38
|
trackCliCommandFinished,
|
|
36
39
|
trackEvent,
|
|
40
|
+
trackFeatureCompleted,
|
|
41
|
+
trackIntegrationConnection,
|
|
37
42
|
waitForServerRuntimeStartup
|
|
38
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-SG3MPCDL.js";
|
|
39
44
|
import {
|
|
40
45
|
autoSyncSkills,
|
|
41
46
|
formatAutoSyncNotice
|
|
42
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-YCPTP2NC.js";
|
|
43
48
|
import {
|
|
49
|
+
clearDashboardPassword,
|
|
44
50
|
configExists,
|
|
45
51
|
createApiClient,
|
|
46
52
|
emitInstallSummary,
|
|
@@ -57,14 +63,16 @@ import {
|
|
|
57
63
|
saveConfigPatch,
|
|
58
64
|
shouldPrintServeSkillsNudge,
|
|
59
65
|
withBootstrapProviderDefaults
|
|
60
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-JJBVYL45.js";
|
|
61
67
|
import {
|
|
62
68
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
63
69
|
trustedProxiesProblem,
|
|
64
70
|
trustedProxyProblem
|
|
65
71
|
} from "./chunk-RB2F4D3Z.js";
|
|
66
|
-
import "./chunk-
|
|
72
|
+
import "./chunk-7Q7QCBJ3.js";
|
|
67
73
|
import {
|
|
74
|
+
CANONRY_DISCORD_URL,
|
|
75
|
+
CANONRY_ISSUES_URL,
|
|
68
76
|
CliError,
|
|
69
77
|
EXIT_SYSTEM_ERROR,
|
|
70
78
|
EXIT_USER_ERROR,
|
|
@@ -75,13 +83,14 @@ import {
|
|
|
75
83
|
runMeasurementDraftAction,
|
|
76
84
|
systemError,
|
|
77
85
|
usageError
|
|
78
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-DS2ZKB3T.js";
|
|
79
87
|
import {
|
|
80
88
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
81
89
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
82
90
|
CLOUDFLARE_WRANGLER_GENERATED_MARKER,
|
|
83
91
|
DEFAULT_BOT_LIST,
|
|
84
92
|
aiUserFetchEventsHourly,
|
|
93
|
+
anyUsersExist,
|
|
85
94
|
apiKeys,
|
|
86
95
|
auditLog,
|
|
87
96
|
backfillProjectAnswerMentions,
|
|
@@ -107,7 +116,7 @@ import {
|
|
|
107
116
|
rawEventSamples,
|
|
108
117
|
readMarketCompetitorNames,
|
|
109
118
|
runs
|
|
110
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-O5UMRQVN.js";
|
|
111
120
|
import {
|
|
112
121
|
AdsDeliverySnapshotStatuses,
|
|
113
122
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -126,6 +135,8 @@ import {
|
|
|
126
135
|
GaMoverChangeBases,
|
|
127
136
|
MeasurementEvidenceShapes,
|
|
128
137
|
OUTSTANDING_PROVIDER_BATCH_STATUSES,
|
|
138
|
+
OutcomeReasonCodes,
|
|
139
|
+
OutcomeTriggers,
|
|
129
140
|
ProviderBatchStatuses,
|
|
130
141
|
ProviderNames,
|
|
131
142
|
ProviderReloadErrorReasons,
|
|
@@ -164,6 +175,7 @@ import {
|
|
|
164
175
|
buildModelChangeNotice,
|
|
165
176
|
canonicalizeGtmAccountId,
|
|
166
177
|
canonicalizeGtmResourceSelection,
|
|
178
|
+
classifyOutcomeError,
|
|
167
179
|
competitorAutoAliasModeSchema,
|
|
168
180
|
competitorLandscapeQuerySchema,
|
|
169
181
|
computeCompetitorOverlap,
|
|
@@ -241,7 +253,7 @@ import {
|
|
|
241
253
|
visibilityCompareSelectionSchema,
|
|
242
254
|
visibilityReportRequestSchema,
|
|
243
255
|
winnabilityClassSchema
|
|
244
|
-
} from "./chunk-
|
|
256
|
+
} from "./chunk-IM2BFAAT.js";
|
|
245
257
|
|
|
246
258
|
// src/cli.ts
|
|
247
259
|
import { pathToFileURL } from "url";
|
|
@@ -290,9 +302,9 @@ Usage: ${spec.usage}
|
|
|
290
302
|
if (spec.help) console.log(`${spec.help}
|
|
291
303
|
`);
|
|
292
304
|
}
|
|
293
|
-
function matchesPath(args,
|
|
294
|
-
if (args.length <
|
|
295
|
-
return
|
|
305
|
+
function matchesPath(args, path13) {
|
|
306
|
+
if (args.length < path13.length) return false;
|
|
307
|
+
return path13.every((segment, index) => args[index] === segment);
|
|
296
308
|
}
|
|
297
309
|
function withGlobalOptions(options) {
|
|
298
310
|
const base = options ? { ...options } : {};
|
|
@@ -787,7 +799,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
787
799
|
async function demoCommand(options) {
|
|
788
800
|
const { host, port } = parseDemoListenOptions(options);
|
|
789
801
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
790
|
-
const { createDemoServer } = await import("./demo-server-
|
|
802
|
+
const { createDemoServer } = await import("./demo-server-C7UGXXN7.js");
|
|
791
803
|
const app = await createDemoServer({ trustProxy });
|
|
792
804
|
let stopping = false;
|
|
793
805
|
const stop = () => {
|
|
@@ -1201,7 +1213,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
|
|
|
1201
1213
|
}
|
|
1202
1214
|
}
|
|
1203
1215
|
async function backfillInsightsCommand(project2, opts) {
|
|
1204
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
1216
|
+
const { IntelligenceService } = await import("./intelligence-service-37TX4YV7.js");
|
|
1205
1217
|
const config = loadConfig();
|
|
1206
1218
|
const db = createClient(config.database);
|
|
1207
1219
|
migrate(db);
|
|
@@ -2824,6 +2836,11 @@ var BING_CLI_COMMANDS = [
|
|
|
2824
2836
|
}
|
|
2825
2837
|
];
|
|
2826
2838
|
|
|
2839
|
+
// src/cli-connection-telemetry.ts
|
|
2840
|
+
function trackCliConnection(properties) {
|
|
2841
|
+
trackIntegrationConnection({ ...properties, surface: "cli", agent: cliRuntimeContext().agent });
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2827
2844
|
// src/commands/cdp.ts
|
|
2828
2845
|
function getClient3() {
|
|
2829
2846
|
return createApiClient();
|
|
@@ -2837,7 +2854,13 @@ async function cdpConnect(opts) {
|
|
|
2837
2854
|
host,
|
|
2838
2855
|
port
|
|
2839
2856
|
};
|
|
2840
|
-
|
|
2857
|
+
try {
|
|
2858
|
+
saveConfigPatch(config);
|
|
2859
|
+
} catch (err) {
|
|
2860
|
+
trackCliConnection({ integration: "cdp", action: "connect", status: "failed", ...outcomeFailure(err) });
|
|
2861
|
+
throw err;
|
|
2862
|
+
}
|
|
2863
|
+
trackCliConnection({ integration: "cdp", action: "connect", status: "succeeded" });
|
|
2841
2864
|
if (isMachineFormat(opts.format)) {
|
|
2842
2865
|
console.log(JSON.stringify({
|
|
2843
2866
|
host,
|
|
@@ -3015,6 +3038,80 @@ var CDP_CLI_COMMANDS = [
|
|
|
3015
3038
|
}
|
|
3016
3039
|
];
|
|
3017
3040
|
|
|
3041
|
+
// src/commands/dashboard.ts
|
|
3042
|
+
import fs2 from "fs";
|
|
3043
|
+
function namedAccountsInUse() {
|
|
3044
|
+
const database = loadConfigRaw()?.database;
|
|
3045
|
+
if (typeof database !== "string" || !fs2.existsSync(database)) return false;
|
|
3046
|
+
try {
|
|
3047
|
+
const db = createClient(database);
|
|
3048
|
+
try {
|
|
3049
|
+
return anyUsersExist(db);
|
|
3050
|
+
} finally {
|
|
3051
|
+
db.$client.close();
|
|
3052
|
+
}
|
|
3053
|
+
} catch {
|
|
3054
|
+
return false;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
function nextStepsFor(cleared, namedAccounts) {
|
|
3058
|
+
if (namedAccounts) {
|
|
3059
|
+
return [
|
|
3060
|
+
"This install signs in with named accounts, so the shared dashboard password is not used and clearing it does not change who can sign in.",
|
|
3061
|
+
'To restore an account, run "canonry user list", then "canonry user delete <name>" and "canonry user create".'
|
|
3062
|
+
];
|
|
3063
|
+
}
|
|
3064
|
+
if (!cleared) {
|
|
3065
|
+
return ["If the dashboard still asks for a password, restart the server: it keeps the password it started with."];
|
|
3066
|
+
}
|
|
3067
|
+
return [
|
|
3068
|
+
"Restart the server to apply the reset. Until then it still accepts the old password.",
|
|
3069
|
+
// First-run setup on a loopback bind takes the password from any process
|
|
3070
|
+
// that can open a loopback connection (docs/deployment.md).
|
|
3071
|
+
"Then open the dashboard and create the new password right away. Until one is set, a server that listens only on this machine accepts it from any local connection, so stop any port forwarder (ssh -R, ngrok tcp, tailscale serve --tcp) first."
|
|
3072
|
+
];
|
|
3073
|
+
}
|
|
3074
|
+
async function resetDashboardPassword(opts) {
|
|
3075
|
+
const { cleared, configPath } = clearDashboardPassword();
|
|
3076
|
+
const namedAccounts = namedAccountsInUse();
|
|
3077
|
+
const nextSteps = nextStepsFor(cleared, namedAccounts);
|
|
3078
|
+
if (isMachineFormat(opts.format)) {
|
|
3079
|
+
console.log(JSON.stringify({
|
|
3080
|
+
reset: cleared,
|
|
3081
|
+
configPath,
|
|
3082
|
+
restartRequired: cleared && !namedAccounts,
|
|
3083
|
+
namedAccounts,
|
|
3084
|
+
nextSteps
|
|
3085
|
+
}, null, 2));
|
|
3086
|
+
return;
|
|
3087
|
+
}
|
|
3088
|
+
console.log(cleared ? `Dashboard password cleared from ${configPath}.` : `No dashboard password is set in ${configPath}; nothing to reset.`);
|
|
3089
|
+
for (const step of nextSteps) console.log(step);
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
// src/cli-commands/dashboard.ts
|
|
3093
|
+
var DASHBOARD_CLI_COMMANDS = [
|
|
3094
|
+
{
|
|
3095
|
+
path: ["dashboard", "reset-password"],
|
|
3096
|
+
usage: "canonry dashboard reset-password [--format json]",
|
|
3097
|
+
help: "Clears the dashboard password from config.yaml, so the dashboard asks for a new one after a restart.\nLocal only: it edits the config file under CANONRY_CONFIG_DIR and does not call the server.",
|
|
3098
|
+
run: async (input) => {
|
|
3099
|
+
await resetDashboardPassword({ format: input.format });
|
|
3100
|
+
}
|
|
3101
|
+
},
|
|
3102
|
+
{
|
|
3103
|
+
path: ["dashboard"],
|
|
3104
|
+
usage: "canonry dashboard <reset-password>",
|
|
3105
|
+
run: async (input) => {
|
|
3106
|
+
unknownSubcommand(input.positionals[0], {
|
|
3107
|
+
command: "dashboard",
|
|
3108
|
+
usage: "canonry dashboard <reset-password>",
|
|
3109
|
+
available: ["reset-password"]
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
];
|
|
3114
|
+
|
|
3018
3115
|
// src/commands/discover.ts
|
|
3019
3116
|
var TERMINAL_DISCOVERY_STATUSES = /* @__PURE__ */ new Set([
|
|
3020
3117
|
"completed",
|
|
@@ -3360,7 +3457,7 @@ async function pollSession(client, project2, sessionId, quiet = false) {
|
|
|
3360
3457
|
}
|
|
3361
3458
|
|
|
3362
3459
|
// src/commands/discover-eval.ts
|
|
3363
|
-
import
|
|
3460
|
+
import fs3 from "fs";
|
|
3364
3461
|
import path from "path";
|
|
3365
3462
|
|
|
3366
3463
|
// src/discovery-eval.ts
|
|
@@ -3589,7 +3686,7 @@ async function discoverEvalWithClient(client, opts) {
|
|
|
3589
3686
|
const baselinePath = path.resolve(opts.baseline ?? DEFAULT_BASELINE_PATH);
|
|
3590
3687
|
if (opts.updateBaseline) {
|
|
3591
3688
|
const baseline2 = { capturedAt: (/* @__PURE__ */ new Date()).toISOString(), scorecards };
|
|
3592
|
-
|
|
3689
|
+
fs3.writeFileSync(baselinePath, JSON.stringify(baseline2, null, 2) + "\n");
|
|
3593
3690
|
if (opts.format === "json" || opts.format === "jsonl") {
|
|
3594
3691
|
console.log(JSON.stringify({ scorecards, baselineWritten: baselinePath }, null, 2));
|
|
3595
3692
|
} else {
|
|
@@ -3598,14 +3695,14 @@ async function discoverEvalWithClient(client, opts) {
|
|
|
3598
3695
|
}
|
|
3599
3696
|
return;
|
|
3600
3697
|
}
|
|
3601
|
-
if (!
|
|
3698
|
+
if (!fs3.existsSync(baselinePath)) {
|
|
3602
3699
|
throw new CliError({
|
|
3603
3700
|
code: "EVAL_NO_BASELINE",
|
|
3604
3701
|
message: `no baseline at ${baselinePath}; run with --update-baseline to capture one`,
|
|
3605
3702
|
exitCode: EXIT_USER_ERROR
|
|
3606
3703
|
});
|
|
3607
3704
|
}
|
|
3608
|
-
const baseline = JSON.parse(
|
|
3705
|
+
const baseline = JSON.parse(fs3.readFileSync(baselinePath, "utf8"));
|
|
3609
3706
|
const verdict = compareToBaseline(scorecards, baseline);
|
|
3610
3707
|
if (opts.format === "json" || opts.format === "jsonl") {
|
|
3611
3708
|
console.log(JSON.stringify({ scorecards, verdict, baseline: { capturedAt: baseline.capturedAt } }, null, 2));
|
|
@@ -4437,7 +4534,7 @@ var DOCTOR_CLI_COMMANDS = [
|
|
|
4437
4534
|
];
|
|
4438
4535
|
|
|
4439
4536
|
// src/commands/ads.ts
|
|
4440
|
-
import
|
|
4537
|
+
import fs4 from "fs";
|
|
4441
4538
|
function getClient6() {
|
|
4442
4539
|
return createApiClient();
|
|
4443
4540
|
}
|
|
@@ -4450,7 +4547,7 @@ function readRequest(inputPath, schema) {
|
|
|
4450
4547
|
});
|
|
4451
4548
|
}
|
|
4452
4549
|
try {
|
|
4453
|
-
const raw =
|
|
4550
|
+
const raw = fs4.readFileSync(inputPath === "-" ? 0 : inputPath, "utf8");
|
|
4454
4551
|
return schema.parse(JSON.parse(raw));
|
|
4455
4552
|
} catch (err) {
|
|
4456
4553
|
if (err instanceof CliError) throw err;
|
|
@@ -5326,9 +5423,9 @@ async function gaConnect(project2, opts) {
|
|
|
5326
5423
|
propertyId: opts.propertyId
|
|
5327
5424
|
};
|
|
5328
5425
|
if (opts.keyFile) {
|
|
5329
|
-
const
|
|
5426
|
+
const fs21 = await import("fs");
|
|
5330
5427
|
try {
|
|
5331
|
-
const content =
|
|
5428
|
+
const content = fs21.readFileSync(opts.keyFile, "utf-8");
|
|
5332
5429
|
JSON.parse(content);
|
|
5333
5430
|
body.keyJson = content;
|
|
5334
5431
|
} catch (e) {
|
|
@@ -6916,7 +7013,7 @@ var GBP_CLI_COMMANDS = [
|
|
|
6916
7013
|
];
|
|
6917
7014
|
|
|
6918
7015
|
// src/commands/google-marketing.ts
|
|
6919
|
-
import
|
|
7016
|
+
import fs5 from "fs";
|
|
6920
7017
|
function printMachine(value, format) {
|
|
6921
7018
|
if (!isMachineFormat(format)) return false;
|
|
6922
7019
|
console.log(JSON.stringify(value, null, 2));
|
|
@@ -6957,7 +7054,7 @@ function readConversionTrackingContractInput(inputPath) {
|
|
|
6957
7054
|
});
|
|
6958
7055
|
}
|
|
6959
7056
|
try {
|
|
6960
|
-
const raw =
|
|
7057
|
+
const raw = fs5.readFileSync(inputPath === "-" ? 0 : inputPath, "utf8");
|
|
6961
7058
|
return conversionTrackingContractWriteRequestSchema.parse(JSON.parse(raw));
|
|
6962
7059
|
} catch (err) {
|
|
6963
7060
|
const message = describeError(err);
|
|
@@ -7609,9 +7706,9 @@ async function getCommand(opts) {
|
|
|
7609
7706
|
console.log(JSON.stringify(leaf, null, 2));
|
|
7610
7707
|
}
|
|
7611
7708
|
}
|
|
7612
|
-
function walkPath(value,
|
|
7613
|
-
if (!
|
|
7614
|
-
const segments =
|
|
7709
|
+
function walkPath(value, path13) {
|
|
7710
|
+
if (!path13 || path13 === ".") return value;
|
|
7711
|
+
const segments = path13.split(".").flatMap((part) => {
|
|
7615
7712
|
const tokens = [];
|
|
7616
7713
|
let i = 0;
|
|
7617
7714
|
const bracketStart = part.indexOf("[");
|
|
@@ -7659,24 +7756,24 @@ var GET_CLI_COMMANDS = [
|
|
|
7659
7756
|
},
|
|
7660
7757
|
run: async (input) => {
|
|
7661
7758
|
const project2 = requireProject(input, "get", USAGE2);
|
|
7662
|
-
const
|
|
7759
|
+
const path13 = requirePositional(input, 1, {
|
|
7663
7760
|
command: "get",
|
|
7664
7761
|
usage: USAGE2,
|
|
7665
7762
|
message: 'path is required (e.g. "scores.mentionShare.value")'
|
|
7666
7763
|
});
|
|
7667
7764
|
const from = getString(input.values, "from");
|
|
7668
|
-
await getCommand({ project: project2, path:
|
|
7765
|
+
await getCommand({ project: project2, path: path13, from, format: input.format });
|
|
7669
7766
|
}
|
|
7670
7767
|
}
|
|
7671
7768
|
];
|
|
7672
7769
|
|
|
7673
7770
|
// src/commands/traffic.ts
|
|
7674
|
-
import
|
|
7771
|
+
import fs7 from "fs";
|
|
7675
7772
|
|
|
7676
7773
|
// src/cloudflare-worker-deploy.ts
|
|
7677
7774
|
import { spawn } from "child_process";
|
|
7678
7775
|
import { randomUUID } from "crypto";
|
|
7679
|
-
import
|
|
7776
|
+
import fs6 from "fs";
|
|
7680
7777
|
import os from "os";
|
|
7681
7778
|
import path2 from "path";
|
|
7682
7779
|
import { stripVTControlCharacters } from "util";
|
|
@@ -7694,7 +7791,7 @@ function projectSlug(project2) {
|
|
|
7694
7791
|
}
|
|
7695
7792
|
function lstatIfPresent(filePath) {
|
|
7696
7793
|
try {
|
|
7697
|
-
return
|
|
7794
|
+
return fs6.lstatSync(filePath);
|
|
7698
7795
|
} catch (error) {
|
|
7699
7796
|
if (error.code === "ENOENT") return null;
|
|
7700
7797
|
throw error;
|
|
@@ -7712,7 +7809,7 @@ function prepareCloudflareWorkerOutputDirectory(outputDirectory) {
|
|
|
7712
7809
|
throw new Error(`output directory is not a regular directory: ${resolved}`);
|
|
7713
7810
|
}
|
|
7714
7811
|
} else {
|
|
7715
|
-
|
|
7812
|
+
fs6.mkdirSync(resolved, { recursive: true, mode: 448 });
|
|
7716
7813
|
}
|
|
7717
7814
|
const artifacts = {
|
|
7718
7815
|
outputDirectory: resolved,
|
|
@@ -7725,7 +7822,7 @@ function prepareCloudflareWorkerOutputDirectory(outputDirectory) {
|
|
|
7725
7822
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
7726
7823
|
throw new Error(`artifact path is not a regular file: ${artifactPath}`);
|
|
7727
7824
|
}
|
|
7728
|
-
const contents =
|
|
7825
|
+
const contents = fs6.readFileSync(artifactPath, "utf-8");
|
|
7729
7826
|
if (!isRecognizablyCanonryGenerated(artifactPath, contents)) {
|
|
7730
7827
|
throw new Error(`refusing to overwrite an operator-owned artifact: ${artifactPath}`);
|
|
7731
7828
|
}
|
|
@@ -7738,7 +7835,7 @@ function readRegularArtifact(filePath) {
|
|
|
7738
7835
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
7739
7836
|
throw new Error(`artifact path is not a regular file: ${filePath}`);
|
|
7740
7837
|
}
|
|
7741
|
-
return
|
|
7838
|
+
return fs6.readFileSync(filePath, "utf-8");
|
|
7742
7839
|
}
|
|
7743
7840
|
function isRecognizablyCanonryGenerated(filePath, contents) {
|
|
7744
7841
|
if (path2.basename(filePath) === "worker.js") {
|
|
@@ -7755,22 +7852,22 @@ function writePrivateTemporaryFile(filePath, contents) {
|
|
|
7755
7852
|
path2.dirname(filePath),
|
|
7756
7853
|
`.${path2.basename(filePath)}.${randomUUID()}.tmp`
|
|
7757
7854
|
);
|
|
7758
|
-
const fd =
|
|
7855
|
+
const fd = fs6.openSync(temporaryPath, "wx", 384);
|
|
7759
7856
|
let closed = false;
|
|
7760
7857
|
try {
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7858
|
+
fs6.writeFileSync(fd, contents, "utf-8");
|
|
7859
|
+
fs6.fsyncSync(fd);
|
|
7860
|
+
fs6.closeSync(fd);
|
|
7764
7861
|
closed = true;
|
|
7765
7862
|
} catch (error) {
|
|
7766
7863
|
if (!closed) {
|
|
7767
7864
|
try {
|
|
7768
|
-
|
|
7865
|
+
fs6.closeSync(fd);
|
|
7769
7866
|
} catch {
|
|
7770
7867
|
}
|
|
7771
7868
|
}
|
|
7772
7869
|
try {
|
|
7773
|
-
|
|
7870
|
+
fs6.unlinkSync(temporaryPath);
|
|
7774
7871
|
} catch {
|
|
7775
7872
|
}
|
|
7776
7873
|
throw error;
|
|
@@ -7804,10 +7901,10 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
7804
7901
|
throw new Error(`artifact changed during update: ${change.filePath}`);
|
|
7805
7902
|
}
|
|
7806
7903
|
if (change.previous === null) {
|
|
7807
|
-
|
|
7808
|
-
|
|
7904
|
+
fs6.linkSync(change.temporaryPath, change.filePath);
|
|
7905
|
+
fs6.unlinkSync(change.temporaryPath);
|
|
7809
7906
|
} else {
|
|
7810
|
-
|
|
7907
|
+
fs6.renameSync(change.temporaryPath, change.filePath);
|
|
7811
7908
|
}
|
|
7812
7909
|
applied.push(change);
|
|
7813
7910
|
}
|
|
@@ -7816,10 +7913,10 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
7816
7913
|
try {
|
|
7817
7914
|
if (readRegularArtifact(change.filePath) !== change.contents) continue;
|
|
7818
7915
|
if (change.previous === null) {
|
|
7819
|
-
|
|
7916
|
+
fs6.unlinkSync(change.filePath);
|
|
7820
7917
|
} else {
|
|
7821
7918
|
const restorePath = writePrivateTemporaryFile(change.filePath, change.previous);
|
|
7822
|
-
|
|
7919
|
+
fs6.renameSync(restorePath, change.filePath);
|
|
7823
7920
|
}
|
|
7824
7921
|
} catch {
|
|
7825
7922
|
}
|
|
@@ -7828,7 +7925,7 @@ function writeCloudflareWorkerArtifacts(artifacts, contents) {
|
|
|
7828
7925
|
} finally {
|
|
7829
7926
|
for (const change of pending) {
|
|
7830
7927
|
try {
|
|
7831
|
-
if (
|
|
7928
|
+
if (fs6.existsSync(change.temporaryPath)) fs6.unlinkSync(change.temporaryPath);
|
|
7832
7929
|
} catch {
|
|
7833
7930
|
}
|
|
7834
7931
|
}
|
|
@@ -7914,7 +8011,7 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
7914
8011
|
if (missing.length > 0) {
|
|
7915
8012
|
throw new Error(`Wrangler deploy does not support required flags: ${missing.join(", ")}`);
|
|
7916
8013
|
}
|
|
7917
|
-
const tempDirectory =
|
|
8014
|
+
const tempDirectory = fs6.mkdtempSync(path2.join(
|
|
7918
8015
|
opts.tempRoot ?? os.tmpdir(),
|
|
7919
8016
|
"canonry-cloudflare-wrangler-preflight-"
|
|
7920
8017
|
));
|
|
@@ -7922,13 +8019,13 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
7922
8019
|
const wranglerTomlPath = path2.join(tempDirectory, "wrangler.toml");
|
|
7923
8020
|
const secretsPath = path2.join(tempDirectory, "secrets.json");
|
|
7924
8021
|
try {
|
|
7925
|
-
|
|
7926
|
-
|
|
8022
|
+
fs6.chmodSync(tempDirectory, 448);
|
|
8023
|
+
fs6.writeFileSync(workerScriptPath, generateWorkerScript({
|
|
7927
8024
|
deliveryMode,
|
|
7928
8025
|
workerVersion: "preflight",
|
|
7929
8026
|
botList: DEFAULT_BOT_LIST
|
|
7930
8027
|
}), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
7931
|
-
|
|
8028
|
+
fs6.writeFileSync(wranglerTomlPath, generateWranglerToml(
|
|
7932
8029
|
deliveryMode === "queue-pull" ? {
|
|
7933
8030
|
deliveryMode,
|
|
7934
8031
|
sourceId: "preflight",
|
|
@@ -7944,7 +8041,7 @@ async function preflightCloudflareWrangler(opts = {}) {
|
|
|
7944
8041
|
}
|
|
7945
8042
|
), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
7946
8043
|
if (deliveryMode === "direct-push") {
|
|
7947
|
-
|
|
8044
|
+
fs6.writeFileSync(secretsPath, JSON.stringify({
|
|
7948
8045
|
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]: "preflight-bearer",
|
|
7949
8046
|
[CLOUDFLARE_WORKER_BINDINGS.hmacSecret]: "preflight-hmac"
|
|
7950
8047
|
}), { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
@@ -7972,7 +8069,7 @@ ${wranglerDiagnostic(validationOutput)}`
|
|
|
7972
8069
|
);
|
|
7973
8070
|
}
|
|
7974
8071
|
} finally {
|
|
7975
|
-
|
|
8072
|
+
fs6.rmSync(tempDirectory, { recursive: true, force: true });
|
|
7976
8073
|
}
|
|
7977
8074
|
}
|
|
7978
8075
|
async function deployCloudflareWorker(opts) {
|
|
@@ -7988,11 +8085,11 @@ async function deployCloudflareWorker(opts) {
|
|
|
7988
8085
|
}
|
|
7989
8086
|
if (!opts.secrets) throw new Error("Direct-push Worker deploy requires bearer and HMAC secrets");
|
|
7990
8087
|
const secrets = opts.secrets;
|
|
7991
|
-
const tempDirectory =
|
|
8088
|
+
const tempDirectory = fs6.mkdtempSync(path2.join(opts.tempRoot ?? os.tmpdir(), "canonry-cloudflare-secrets-"));
|
|
7992
8089
|
const secretsPath = path2.join(tempDirectory, "secrets.json");
|
|
7993
8090
|
try {
|
|
7994
|
-
|
|
7995
|
-
|
|
8091
|
+
fs6.chmodSync(tempDirectory, 448);
|
|
8092
|
+
fs6.writeFileSync(
|
|
7996
8093
|
secretsPath,
|
|
7997
8094
|
JSON.stringify({
|
|
7998
8095
|
[CLOUDFLARE_WORKER_BINDINGS.bearerToken]: secrets.bearerToken,
|
|
@@ -8000,7 +8097,7 @@ async function deployCloudflareWorker(opts) {
|
|
|
8000
8097
|
}),
|
|
8001
8098
|
{ encoding: "utf-8", flag: "wx", mode: 384 }
|
|
8002
8099
|
);
|
|
8003
|
-
|
|
8100
|
+
fs6.chmodSync(secretsPath, 384);
|
|
8004
8101
|
const runner = opts.run ?? runWrangler;
|
|
8005
8102
|
await runner(
|
|
8006
8103
|
"wrangler",
|
|
@@ -8016,9 +8113,9 @@ async function deployCloudflareWorker(opts) {
|
|
|
8016
8113
|
);
|
|
8017
8114
|
} finally {
|
|
8018
8115
|
try {
|
|
8019
|
-
if (
|
|
8116
|
+
if (fs6.existsSync(secretsPath)) fs6.unlinkSync(secretsPath);
|
|
8020
8117
|
} finally {
|
|
8021
|
-
|
|
8118
|
+
fs6.rmSync(tempDirectory, { recursive: true, force: true });
|
|
8022
8119
|
}
|
|
8023
8120
|
}
|
|
8024
8121
|
}
|
|
@@ -8048,11 +8145,11 @@ function requireCloudflareQueueOption(project2, value, option) {
|
|
|
8048
8145
|
}
|
|
8049
8146
|
function readCloudflareQueueApiToken(project2, tokenFile) {
|
|
8050
8147
|
try {
|
|
8051
|
-
const stat =
|
|
8148
|
+
const stat = fs7.lstatSync(tokenFile);
|
|
8052
8149
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
8053
8150
|
throw new Error("not a regular file");
|
|
8054
8151
|
}
|
|
8055
|
-
const apiToken =
|
|
8152
|
+
const apiToken = fs7.readFileSync(tokenFile, "utf-8").trim();
|
|
8056
8153
|
if (!apiToken) throw new Error("file is empty");
|
|
8057
8154
|
return apiToken;
|
|
8058
8155
|
} catch (error) {
|
|
@@ -8334,9 +8431,9 @@ async function trafficConnectWordpress(project2, opts) {
|
|
|
8334
8431
|
}
|
|
8335
8432
|
let applicationPassword = opts.appPassword?.trim() ?? "";
|
|
8336
8433
|
if (!applicationPassword && opts.appPasswordFile) {
|
|
8337
|
-
const
|
|
8434
|
+
const fs21 = await import("fs");
|
|
8338
8435
|
try {
|
|
8339
|
-
applicationPassword =
|
|
8436
|
+
applicationPassword = fs21.readFileSync(opts.appPasswordFile, "utf-8").trim();
|
|
8340
8437
|
} catch (e) {
|
|
8341
8438
|
const msg = describeError(e);
|
|
8342
8439
|
throw new CliError({
|
|
@@ -8392,10 +8489,10 @@ async function trafficConnectCloudRun(project2, opts) {
|
|
|
8392
8489
|
details: { project: project2 }
|
|
8393
8490
|
});
|
|
8394
8491
|
}
|
|
8395
|
-
const
|
|
8492
|
+
const fs21 = await import("fs");
|
|
8396
8493
|
let keyJson;
|
|
8397
8494
|
try {
|
|
8398
|
-
keyJson =
|
|
8495
|
+
keyJson = fs21.readFileSync(opts.serviceAccountKey, "utf-8");
|
|
8399
8496
|
JSON.parse(keyJson);
|
|
8400
8497
|
} catch (e) {
|
|
8401
8498
|
const msg = describeError(e);
|
|
@@ -8455,9 +8552,9 @@ async function trafficConnectVercel(project2, opts) {
|
|
|
8455
8552
|
}
|
|
8456
8553
|
let token = opts.token?.trim() ?? "";
|
|
8457
8554
|
if (!token && opts.tokenFile) {
|
|
8458
|
-
const
|
|
8555
|
+
const fs21 = await import("fs");
|
|
8459
8556
|
try {
|
|
8460
|
-
token =
|
|
8557
|
+
token = fs21.readFileSync(opts.tokenFile, "utf-8").trim();
|
|
8461
8558
|
} catch (e) {
|
|
8462
8559
|
const msg = describeError(e);
|
|
8463
8560
|
throw new CliError({
|
|
@@ -11504,7 +11601,7 @@ var USERS_CLI_COMMANDS = [
|
|
|
11504
11601
|
];
|
|
11505
11602
|
|
|
11506
11603
|
// src/commands/keyword.ts
|
|
11507
|
-
import
|
|
11604
|
+
import fs8 from "fs";
|
|
11508
11605
|
function getClient14() {
|
|
11509
11606
|
return createApiClient();
|
|
11510
11607
|
}
|
|
@@ -11572,7 +11669,7 @@ async function listKeywords(project2, format) {
|
|
|
11572
11669
|
}
|
|
11573
11670
|
}
|
|
11574
11671
|
async function importKeywords(project2, filePath, format) {
|
|
11575
|
-
if (!
|
|
11672
|
+
if (!fs8.existsSync(filePath)) {
|
|
11576
11673
|
throw new CliError({
|
|
11577
11674
|
code: "KEYWORD_IMPORT_FILE_NOT_FOUND",
|
|
11578
11675
|
message: `File not found: ${filePath}`,
|
|
@@ -11583,7 +11680,7 @@ async function importKeywords(project2, filePath, format) {
|
|
|
11583
11680
|
}
|
|
11584
11681
|
});
|
|
11585
11682
|
}
|
|
11586
|
-
const content =
|
|
11683
|
+
const content = fs8.readFileSync(filePath, "utf-8");
|
|
11587
11684
|
const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
11588
11685
|
if (keywords.length === 0) {
|
|
11589
11686
|
if (isMachineFormat(format)) {
|
|
@@ -11784,7 +11881,7 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
11784
11881
|
];
|
|
11785
11882
|
|
|
11786
11883
|
// src/commands/query.ts
|
|
11787
|
-
import
|
|
11884
|
+
import fs9 from "fs";
|
|
11788
11885
|
function getClient15() {
|
|
11789
11886
|
return createApiClient();
|
|
11790
11887
|
}
|
|
@@ -11875,7 +11972,7 @@ async function listQueries(project2, format) {
|
|
|
11875
11972
|
}
|
|
11876
11973
|
}
|
|
11877
11974
|
async function importQueries(project2, filePath, format) {
|
|
11878
|
-
if (!
|
|
11975
|
+
if (!fs9.existsSync(filePath)) {
|
|
11879
11976
|
throw new CliError({
|
|
11880
11977
|
code: "QUERY_IMPORT_FILE_NOT_FOUND",
|
|
11881
11978
|
message: `File not found: ${filePath}`,
|
|
@@ -11886,7 +11983,7 @@ async function importQueries(project2, filePath, format) {
|
|
|
11886
11983
|
}
|
|
11887
11984
|
});
|
|
11888
11985
|
}
|
|
11889
|
-
const content =
|
|
11986
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
11890
11987
|
const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
11891
11988
|
if (queries2.length === 0) {
|
|
11892
11989
|
if (isMachineFormat(format)) {
|
|
@@ -11950,16 +12047,16 @@ Saved ${result.queries.length} ${result.queries.length === 1 ? "query" : "querie
|
|
|
11950
12047
|
|
|
11951
12048
|
// src/commands/measurement-plan.ts
|
|
11952
12049
|
import crypto from "crypto";
|
|
11953
|
-
import
|
|
12050
|
+
import fs10 from "fs";
|
|
11954
12051
|
import { parse as parse2 } from "yaml";
|
|
11955
12052
|
import { z as z2 } from "zod";
|
|
11956
12053
|
function readPlan(source) {
|
|
11957
|
-
const content = source === "-" ?
|
|
12054
|
+
const content = source === "-" ? fs10.readFileSync(0, "utf8") : fs10.readFileSync(source, "utf8");
|
|
11958
12055
|
const parsed = source.endsWith(".json") ? JSON.parse(content) : parse2(content);
|
|
11959
12056
|
return measurementPlanInputSchema.parse(parsed);
|
|
11960
12057
|
}
|
|
11961
12058
|
function readDiscoveryRule(source) {
|
|
11962
|
-
const content = source === "-" ?
|
|
12059
|
+
const content = source === "-" ? fs10.readFileSync(0, "utf8") : fs10.readFileSync(source, "utf8");
|
|
11963
12060
|
const parsed = source.endsWith(".json") ? JSON.parse(content) : parse2(content);
|
|
11964
12061
|
return measurementDiscoveryRuleSchema.parse(parsed);
|
|
11965
12062
|
}
|
|
@@ -12012,7 +12109,7 @@ var advancedDeactivateInputSchema = z2.object({
|
|
|
12012
12109
|
}).strict();
|
|
12013
12110
|
function readAdvancedMeasurementInput(source) {
|
|
12014
12111
|
if (source === void 0) return {};
|
|
12015
|
-
const content = source === "-" ?
|
|
12112
|
+
const content = source === "-" ? fs10.readFileSync(0, "utf8") : fs10.readFileSync(source, "utf8");
|
|
12016
12113
|
return JSON.parse(content);
|
|
12017
12114
|
}
|
|
12018
12115
|
var advancedMeasurementCollectionKeys = {
|
|
@@ -12211,7 +12308,7 @@ async function replaceMeasurementPlanAssignments(project2, opts) {
|
|
|
12211
12308
|
console.log(JSON.stringify({ preview, result }, null, 2));
|
|
12212
12309
|
}
|
|
12213
12310
|
function readGroupMembershipCsv(source) {
|
|
12214
|
-
return source === "-" ?
|
|
12311
|
+
return source === "-" ? fs10.readFileSync(0, "utf8") : fs10.readFileSync(source, "utf8");
|
|
12215
12312
|
}
|
|
12216
12313
|
async function previewMeasurementPlanGroups(project2, source) {
|
|
12217
12314
|
const preview = await createApiClient().previewMeasurementDraftGroupMembership(project2, {
|
|
@@ -12562,7 +12659,7 @@ var QUERY_CLI_COMMANDS = [
|
|
|
12562
12659
|
];
|
|
12563
12660
|
|
|
12564
12661
|
// src/commands/mcp.ts
|
|
12565
|
-
import
|
|
12662
|
+
import fs11 from "fs";
|
|
12566
12663
|
import path4 from "path";
|
|
12567
12664
|
import { createRequire } from "module";
|
|
12568
12665
|
|
|
@@ -12678,8 +12775,8 @@ function renderClientSnippet(client, serverName, entry) {
|
|
|
12678
12775
|
return renderJsonSnippet(serverName, entry, client.format);
|
|
12679
12776
|
}
|
|
12680
12777
|
function readJsonConfig(configPath) {
|
|
12681
|
-
if (!
|
|
12682
|
-
const raw =
|
|
12778
|
+
if (!fs11.existsSync(configPath)) return {};
|
|
12779
|
+
const raw = fs11.readFileSync(configPath, "utf-8").trim();
|
|
12683
12780
|
if (!raw) return {};
|
|
12684
12781
|
try {
|
|
12685
12782
|
const parsed = JSON.parse(raw);
|
|
@@ -12697,14 +12794,14 @@ function readJsonConfig(configPath) {
|
|
|
12697
12794
|
}
|
|
12698
12795
|
}
|
|
12699
12796
|
function writeJsonConfig(configPath, value) {
|
|
12700
|
-
|
|
12701
|
-
|
|
12797
|
+
fs11.mkdirSync(path4.dirname(configPath), { recursive: true });
|
|
12798
|
+
fs11.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
12702
12799
|
`, "utf-8");
|
|
12703
12800
|
}
|
|
12704
12801
|
function backupConfigIfPresent(configPath) {
|
|
12705
|
-
if (!
|
|
12802
|
+
if (!fs11.existsSync(configPath)) return void 0;
|
|
12706
12803
|
const backupPath = `${configPath}.canonry.bak`;
|
|
12707
|
-
|
|
12804
|
+
fs11.copyFileSync(configPath, backupPath);
|
|
12708
12805
|
return backupPath;
|
|
12709
12806
|
}
|
|
12710
12807
|
function findClientOrThrow(id) {
|
|
@@ -13067,13 +13164,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
13067
13164
|
];
|
|
13068
13165
|
|
|
13069
13166
|
// src/commands/apply.ts
|
|
13070
|
-
import
|
|
13167
|
+
import fs12 from "fs";
|
|
13071
13168
|
import { parseAllDocuments } from "yaml";
|
|
13072
13169
|
async function applyConfigFile(filePath) {
|
|
13073
|
-
if (!
|
|
13170
|
+
if (!fs12.existsSync(filePath)) {
|
|
13074
13171
|
throw new Error(`File not found: ${filePath}`);
|
|
13075
13172
|
}
|
|
13076
|
-
const content =
|
|
13173
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
13077
13174
|
const docs = parseAllDocuments(content);
|
|
13078
13175
|
const client = createApiClient();
|
|
13079
13176
|
const errors = [];
|
|
@@ -13539,7 +13636,7 @@ async function loadLatestRunForExport(client, project2) {
|
|
|
13539
13636
|
}
|
|
13540
13637
|
|
|
13541
13638
|
// src/commands/results-export.ts
|
|
13542
|
-
import
|
|
13639
|
+
import fs13 from "fs";
|
|
13543
13640
|
import path5 from "path";
|
|
13544
13641
|
async function exportResults(project2, opts) {
|
|
13545
13642
|
const { output, ...request } = opts;
|
|
@@ -13549,8 +13646,8 @@ async function exportResults(project2, opts) {
|
|
|
13549
13646
|
return;
|
|
13550
13647
|
}
|
|
13551
13648
|
const target = output ? path5.resolve(output) : path5.resolve(process.cwd(), path5.basename(artifact.filename));
|
|
13552
|
-
|
|
13553
|
-
|
|
13649
|
+
fs13.mkdirSync(path5.dirname(target), { recursive: true });
|
|
13650
|
+
fs13.writeFileSync(target, artifact.content, "utf8");
|
|
13554
13651
|
console.log(`Results export written to ${target}`);
|
|
13555
13652
|
}
|
|
13556
13653
|
|
|
@@ -15852,11 +15949,11 @@ var SKILLS_CLI_COMMANDS = [
|
|
|
15852
15949
|
];
|
|
15853
15950
|
|
|
15854
15951
|
// src/commands/snapshot.ts
|
|
15855
|
-
import
|
|
15952
|
+
import fs15 from "fs";
|
|
15856
15953
|
import path7 from "path";
|
|
15857
15954
|
|
|
15858
15955
|
// src/snapshot-pdf.ts
|
|
15859
|
-
import
|
|
15956
|
+
import fs14 from "fs";
|
|
15860
15957
|
import path6 from "path";
|
|
15861
15958
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
15862
15959
|
var PAGE_WIDTH = 612;
|
|
@@ -16070,8 +16167,8 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
16070
16167
|
renderQueries(pdf, report);
|
|
16071
16168
|
const bytes = await doc.save();
|
|
16072
16169
|
const resolvedPath = path6.resolve(outputPath);
|
|
16073
|
-
|
|
16074
|
-
|
|
16170
|
+
fs14.mkdirSync(path6.dirname(resolvedPath), { recursive: true });
|
|
16171
|
+
fs14.writeFileSync(resolvedPath, bytes);
|
|
16075
16172
|
return resolvedPath;
|
|
16076
16173
|
}
|
|
16077
16174
|
function renderCover(pdf, report) {
|
|
@@ -16232,8 +16329,8 @@ PDF saved: ${savedPdfPath}`);
|
|
|
16232
16329
|
}
|
|
16233
16330
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
16234
16331
|
const resolvedPath = path7.resolve(outputPath);
|
|
16235
|
-
|
|
16236
|
-
|
|
16332
|
+
fs15.mkdirSync(path7.dirname(resolvedPath), { recursive: true });
|
|
16333
|
+
fs15.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
16237
16334
|
return resolvedPath;
|
|
16238
16335
|
}
|
|
16239
16336
|
function formatSnapshotMarkdown(report) {
|
|
@@ -17472,7 +17569,17 @@ async function bootstrapCommand(opts) {
|
|
|
17472
17569
|
};
|
|
17473
17570
|
const providersChanged = !isDeepStrictEqual(persistedValue(existingRaw?.providers ?? {}), persistedValue(mergedProviders));
|
|
17474
17571
|
const configChanged = !existingRaw || existingRaw.apiUrl !== apiUrl || existingRaw.database !== databasePath || existingRaw.apiKey !== rawApiKey || providersChanged || !isDeepStrictEqual(persistedValue(existingRaw.google), persistedValue(mergedGoogle));
|
|
17475
|
-
|
|
17572
|
+
const providerConnections = Object.keys(env.providers).filter((name) => env.providers[name] && !isDeepStrictEqual(persistedValue(existingRaw?.providers?.[name]), persistedValue(mergedProviders[name]))).map((name) => ({ integration: "provider", provider: name, action: existingRaw?.providers?.[name] ? "reauth" : "connect" }));
|
|
17573
|
+
if (configChanged) {
|
|
17574
|
+
try {
|
|
17575
|
+
saveConfig(nextConfig);
|
|
17576
|
+
} catch (err) {
|
|
17577
|
+
for (const connection of providerConnections) trackCliConnection({ ...connection, status: "failed", ...outcomeFailure(err) });
|
|
17578
|
+
throw err;
|
|
17579
|
+
}
|
|
17580
|
+
}
|
|
17581
|
+
if (isTelemetryEnabled()) recordInstallRef(opts?.ref);
|
|
17582
|
+
for (const connection of providerConnections) trackCliConnection({ ...connection, status: "succeeded" });
|
|
17476
17583
|
const status = !existing ? "created" : configChanged || keyChanged ? "updated" : "unchanged";
|
|
17477
17584
|
const providerFree = registeredProviderNames(nextConfig).length === 0;
|
|
17478
17585
|
const serverUrl = loadConfig().apiUrl;
|
|
@@ -17567,9 +17674,24 @@ async function bootstrapCommand(opts) {
|
|
|
17567
17674
|
if (reloadFailure) throw reloadFailure;
|
|
17568
17675
|
}
|
|
17569
17676
|
|
|
17677
|
+
// src/commands/support.ts
|
|
17678
|
+
var FEEDBACK_COMMAND = 'canonry feedback "<what happened>"';
|
|
17679
|
+
function supportCommand(format) {
|
|
17680
|
+
if (isMachineFormat(format)) {
|
|
17681
|
+
console.log(JSON.stringify({ discord: CANONRY_DISCORD_URL, issues: CANONRY_ISSUES_URL, feedbackCommand: FEEDBACK_COMMAND }, null, 2));
|
|
17682
|
+
return;
|
|
17683
|
+
}
|
|
17684
|
+
console.log([
|
|
17685
|
+
"Get help with Canonry:",
|
|
17686
|
+
` Discord: ${CANONRY_DISCORD_URL}`,
|
|
17687
|
+
` Issues: ${CANONRY_ISSUES_URL}`,
|
|
17688
|
+
` From here: ${FEEDBACK_COMMAND}`
|
|
17689
|
+
].join("\n"));
|
|
17690
|
+
}
|
|
17691
|
+
|
|
17570
17692
|
// src/commands/daemon.ts
|
|
17571
17693
|
import { spawn as spawn2 } from "child_process";
|
|
17572
|
-
import
|
|
17694
|
+
import fs16 from "fs";
|
|
17573
17695
|
import path9 from "path";
|
|
17574
17696
|
|
|
17575
17697
|
// src/operator-url.ts
|
|
@@ -17640,8 +17762,8 @@ function buildServeForwardArgs(opts) {
|
|
|
17640
17762
|
async function startDaemon(opts) {
|
|
17641
17763
|
const pidPath = getPidPath();
|
|
17642
17764
|
const format = opts.format ?? "text";
|
|
17643
|
-
if (
|
|
17644
|
-
const existingPid = parseInt(
|
|
17765
|
+
if (fs16.existsSync(pidPath)) {
|
|
17766
|
+
const existingPid = parseInt(fs16.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
17645
17767
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
17646
17768
|
throw new CliError({
|
|
17647
17769
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -17652,7 +17774,7 @@ async function startDaemon(opts) {
|
|
|
17652
17774
|
}
|
|
17653
17775
|
});
|
|
17654
17776
|
}
|
|
17655
|
-
|
|
17777
|
+
fs16.unlinkSync(pidPath);
|
|
17656
17778
|
}
|
|
17657
17779
|
const config = loadConfig();
|
|
17658
17780
|
const endpoint = resolveDaemonEndpoint(opts, process.env, config.port);
|
|
@@ -17675,10 +17797,10 @@ async function startDaemon(opts) {
|
|
|
17675
17797
|
});
|
|
17676
17798
|
}
|
|
17677
17799
|
const configDir = getConfigDir();
|
|
17678
|
-
if (!
|
|
17679
|
-
|
|
17800
|
+
if (!fs16.existsSync(configDir)) {
|
|
17801
|
+
fs16.mkdirSync(configDir, { recursive: true });
|
|
17680
17802
|
}
|
|
17681
|
-
|
|
17803
|
+
fs16.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
17682
17804
|
if (!isMachineFormat(format)) {
|
|
17683
17805
|
process.stderr.write("Waiting for server to start...");
|
|
17684
17806
|
}
|
|
@@ -17689,7 +17811,7 @@ async function startDaemon(opts) {
|
|
|
17689
17811
|
} catch {
|
|
17690
17812
|
}
|
|
17691
17813
|
try {
|
|
17692
|
-
|
|
17814
|
+
fs16.unlinkSync(pidPath);
|
|
17693
17815
|
} catch {
|
|
17694
17816
|
}
|
|
17695
17817
|
throw new CliError({
|
|
@@ -17721,7 +17843,7 @@ async function startDaemon(opts) {
|
|
|
17721
17843
|
}
|
|
17722
17844
|
function stopDaemon(format = "text") {
|
|
17723
17845
|
const pidPath = getPidPath();
|
|
17724
|
-
if (!
|
|
17846
|
+
if (!fs16.existsSync(pidPath)) {
|
|
17725
17847
|
if (isMachineFormat(format)) {
|
|
17726
17848
|
console.log(JSON.stringify({
|
|
17727
17849
|
stopped: false,
|
|
@@ -17732,7 +17854,7 @@ function stopDaemon(format = "text") {
|
|
|
17732
17854
|
console.log("Canonry is not running (no PID file found)");
|
|
17733
17855
|
return;
|
|
17734
17856
|
}
|
|
17735
|
-
const pid = parseInt(
|
|
17857
|
+
const pid = parseInt(fs16.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
17736
17858
|
if (isNaN(pid)) {
|
|
17737
17859
|
if (isMachineFormat(format)) {
|
|
17738
17860
|
console.log(JSON.stringify({
|
|
@@ -17743,7 +17865,7 @@ function stopDaemon(format = "text") {
|
|
|
17743
17865
|
} else {
|
|
17744
17866
|
console.error("Invalid PID file. Removing it.");
|
|
17745
17867
|
}
|
|
17746
|
-
|
|
17868
|
+
fs16.unlinkSync(pidPath);
|
|
17747
17869
|
return;
|
|
17748
17870
|
}
|
|
17749
17871
|
if (!isProcessAlive(pid)) {
|
|
@@ -17757,12 +17879,12 @@ function stopDaemon(format = "text") {
|
|
|
17757
17879
|
} else {
|
|
17758
17880
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
17759
17881
|
}
|
|
17760
|
-
|
|
17882
|
+
fs16.unlinkSync(pidPath);
|
|
17761
17883
|
return;
|
|
17762
17884
|
}
|
|
17763
17885
|
try {
|
|
17764
17886
|
process.kill(pid, "SIGTERM");
|
|
17765
|
-
|
|
17887
|
+
fs16.unlinkSync(pidPath);
|
|
17766
17888
|
if (isMachineFormat(format)) {
|
|
17767
17889
|
console.log(JSON.stringify({
|
|
17768
17890
|
stopped: true,
|
|
@@ -17786,7 +17908,7 @@ function stopDaemon(format = "text") {
|
|
|
17786
17908
|
|
|
17787
17909
|
// src/commands/init.ts
|
|
17788
17910
|
import crypto3 from "crypto";
|
|
17789
|
-
import
|
|
17911
|
+
import fs17 from "fs";
|
|
17790
17912
|
import readline2 from "readline";
|
|
17791
17913
|
import path10 from "path";
|
|
17792
17914
|
var pendingServeHandoff = false;
|
|
@@ -17824,7 +17946,7 @@ var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
|
|
|
17824
17946
|
function cwdLooksLikeProject(dir) {
|
|
17825
17947
|
const home = process.env.HOME ?? "";
|
|
17826
17948
|
if (home && path10.resolve(dir) === path10.resolve(home)) return false;
|
|
17827
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
17949
|
+
return PROJECT_MARKERS.some((marker) => fs17.existsSync(path10.join(dir, marker)));
|
|
17828
17950
|
}
|
|
17829
17951
|
var DEFAULT_AGENT_MODELS = {
|
|
17830
17952
|
anthropic: "anthropic/claude-sonnet-4-6",
|
|
@@ -17855,8 +17977,8 @@ async function initCommand(opts) {
|
|
|
17855
17977
|
return void 0;
|
|
17856
17978
|
}
|
|
17857
17979
|
const configDir = getConfigDir();
|
|
17858
|
-
if (!
|
|
17859
|
-
|
|
17980
|
+
if (!fs17.existsSync(configDir)) {
|
|
17981
|
+
fs17.mkdirSync(configDir, { recursive: true });
|
|
17860
17982
|
}
|
|
17861
17983
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
17862
17984
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -18104,6 +18226,7 @@ ${mcpTip}`);
|
|
|
18104
18226
|
}
|
|
18105
18227
|
if (isTelemetryEnabled()) {
|
|
18106
18228
|
const postInitSetupState = buildSetupState();
|
|
18229
|
+
recordInstallRef(opts?.ref);
|
|
18107
18230
|
trackEvent("cli.init", {
|
|
18108
18231
|
providerCount: providerNames.length,
|
|
18109
18232
|
providers: providerNames,
|
|
@@ -18126,8 +18249,12 @@ ${mcpTip}`);
|
|
|
18126
18249
|
hasAgent: !!agentLLM
|
|
18127
18250
|
}),
|
|
18128
18251
|
skillsInstalled: !!skillsSummary,
|
|
18252
|
+
...installAttribution(),
|
|
18129
18253
|
...cliRuntimeContext()
|
|
18130
18254
|
});
|
|
18255
|
+
for (const provider of Object.keys(providers)) {
|
|
18256
|
+
trackCliConnection({ integration: "provider", provider, action: "connect", status: "succeeded" });
|
|
18257
|
+
}
|
|
18131
18258
|
}
|
|
18132
18259
|
if (!isMachineFormat(format) && process.stdin.isTTY && process.stdout.isTTY) {
|
|
18133
18260
|
const answer = await prompt("\nStart the dashboard now? [Y/n]: ");
|
|
@@ -18208,7 +18335,7 @@ async function repairPathsOnce(db, name, repair) {
|
|
|
18208
18335
|
}
|
|
18209
18336
|
|
|
18210
18337
|
// src/agent-plugin.ts
|
|
18211
|
-
import
|
|
18338
|
+
import fs18 from "fs";
|
|
18212
18339
|
import path11 from "path";
|
|
18213
18340
|
var CANONRY_PLUGIN_ID = "canonry@canonry";
|
|
18214
18341
|
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
@@ -18253,7 +18380,7 @@ function isCanonryPluginId(value) {
|
|
|
18253
18380
|
}
|
|
18254
18381
|
function readJson(filePath) {
|
|
18255
18382
|
try {
|
|
18256
|
-
return JSON.parse(
|
|
18383
|
+
return JSON.parse(fs18.readFileSync(filePath, "utf8"));
|
|
18257
18384
|
} catch {
|
|
18258
18385
|
return null;
|
|
18259
18386
|
}
|
|
@@ -18272,7 +18399,7 @@ function readCodexPluginConfigured(filePath) {
|
|
|
18272
18399
|
try {
|
|
18273
18400
|
let currentPlugin = null;
|
|
18274
18401
|
let inPluginsTable = false;
|
|
18275
|
-
for (const line of
|
|
18402
|
+
for (const line of fs18.readFileSync(filePath, "utf8").split(/\r?\n/)) {
|
|
18276
18403
|
const section = /^\s*\[plugins\.(?:"([^"]+)"|'([^']+)'|(\S+))\]\s*(?:#.*)?$/.exec(line);
|
|
18277
18404
|
if (section) {
|
|
18278
18405
|
const captures = section.slice(1, 4);
|
|
@@ -18305,7 +18432,7 @@ function readCodexPluginConfigured(filePath) {
|
|
|
18305
18432
|
}
|
|
18306
18433
|
}
|
|
18307
18434
|
function verifiedPluginVersion(root, client) {
|
|
18308
|
-
if (client === "codex" &&
|
|
18435
|
+
if (client === "codex" && fs18.existsSync(path11.join(root, "plugin.json"))) {
|
|
18309
18436
|
const manifest2 = readJson(path11.join(root, "plugin.json"));
|
|
18310
18437
|
if (manifest2 && typeof manifest2 === "object") {
|
|
18311
18438
|
const plugin2 = manifest2;
|
|
@@ -18319,7 +18446,7 @@ function verifiedPluginVersion(root, client) {
|
|
|
18319
18446
|
if (portableMcp.$schema !== AGENT_PLUGINS_MCP_SCHEMA || portableMcp.mcpServers?.canonry?.type !== "stdio" || portableMcp.mcpServers.canonry.command !== "canonry-mcp") {
|
|
18320
18447
|
return null;
|
|
18321
18448
|
}
|
|
18322
|
-
return REQUIRED_SKILLS.every((name) =>
|
|
18449
|
+
return REQUIRED_SKILLS.every((name) => fs18.existsSync(path11.join(root, "skills", name, "SKILL.md"))) ? plugin2.version : null;
|
|
18323
18450
|
}
|
|
18324
18451
|
if (typeof plugin2.$schema === "string" && plugin2.$schema.startsWith("https://agent-plugins.org/schemas/")) {
|
|
18325
18452
|
return null;
|
|
@@ -18337,7 +18464,7 @@ function verifiedPluginVersion(root, client) {
|
|
|
18337
18464
|
if (!mcp || typeof mcp !== "object") return null;
|
|
18338
18465
|
const canonryServer = mcp.mcpServers?.canonry;
|
|
18339
18466
|
if (canonryServer?.command !== "canonry-mcp") return null;
|
|
18340
|
-
return REQUIRED_SKILLS.every((name) =>
|
|
18467
|
+
return REQUIRED_SKILLS.every((name) => fs18.existsSync(path11.join(root, "skills", name, "SKILL.md"))) ? plugin.version : null;
|
|
18341
18468
|
}
|
|
18342
18469
|
function readClaudeUserInstallPaths(claudeConfigDir) {
|
|
18343
18470
|
const parsed = readJson(path11.join(claudeConfigDir, "plugins", "installed_plugins.json"));
|
|
@@ -18354,7 +18481,7 @@ function readClaudeUserInstallPaths(claudeConfigDir) {
|
|
|
18354
18481
|
}
|
|
18355
18482
|
function listDirectories(dir) {
|
|
18356
18483
|
try {
|
|
18357
|
-
return
|
|
18484
|
+
return fs18.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path11.join(dir, entry.name));
|
|
18358
18485
|
} catch {
|
|
18359
18486
|
return [];
|
|
18360
18487
|
}
|
|
@@ -18401,6 +18528,80 @@ function detectCanonryAgentPlugin(opts = {}) {
|
|
|
18401
18528
|
return { configuredClients, verifiedClients, verifiedClientVersions };
|
|
18402
18529
|
}
|
|
18403
18530
|
|
|
18531
|
+
// src/server-crash-telemetry.ts
|
|
18532
|
+
import fs19 from "fs";
|
|
18533
|
+
import path12 from "path";
|
|
18534
|
+
var CRASH_MARKER = "crash-telemetry.json";
|
|
18535
|
+
var MAX_MARKER_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
18536
|
+
function telemetryAllowed() {
|
|
18537
|
+
try {
|
|
18538
|
+
return isTelemetryEnabled();
|
|
18539
|
+
} catch {
|
|
18540
|
+
return false;
|
|
18541
|
+
}
|
|
18542
|
+
}
|
|
18543
|
+
function markerPath(configDir) {
|
|
18544
|
+
return path12.join(configDir, CRASH_MARKER);
|
|
18545
|
+
}
|
|
18546
|
+
function trackServerStartFailure(err, reasonCode) {
|
|
18547
|
+
try {
|
|
18548
|
+
const classified = classifyOutcomeError(err);
|
|
18549
|
+
const code = err?.code;
|
|
18550
|
+
const reason = reasonCode ?? (code === "EADDRINUSE" ? OutcomeReasonCodes.PORT_IN_USE : classified.reasonCode);
|
|
18551
|
+
trackFeatureCompleted({
|
|
18552
|
+
feature: "server",
|
|
18553
|
+
operation: "start",
|
|
18554
|
+
status: "failed",
|
|
18555
|
+
trigger: OutcomeTriggers.startup,
|
|
18556
|
+
reasonCode: reason,
|
|
18557
|
+
...classified.errorName ? { errorName: classified.errorName } : {}
|
|
18558
|
+
});
|
|
18559
|
+
} catch {
|
|
18560
|
+
}
|
|
18561
|
+
}
|
|
18562
|
+
var watched = /* @__PURE__ */ new WeakSet();
|
|
18563
|
+
function watchServerCrashes(configDir = getConfigDir(), proc = process, now = Date.now) {
|
|
18564
|
+
if (watched.has(proc)) return;
|
|
18565
|
+
watched.add(proc);
|
|
18566
|
+
proc.on("uncaughtExceptionMonitor", (err, origin) => {
|
|
18567
|
+
if (!telemetryAllowed()) return;
|
|
18568
|
+
try {
|
|
18569
|
+
const { errorName } = classifyOutcomeError(err);
|
|
18570
|
+
fs19.writeFileSync(markerPath(configDir), JSON.stringify({
|
|
18571
|
+
origin: origin === "unhandledRejection" ? "unhandledRejection" : "uncaughtException",
|
|
18572
|
+
at: now(),
|
|
18573
|
+
...errorName ? { errorName } : {}
|
|
18574
|
+
}));
|
|
18575
|
+
} catch {
|
|
18576
|
+
}
|
|
18577
|
+
});
|
|
18578
|
+
}
|
|
18579
|
+
function reportPreviousServerCrash(configDir = getConfigDir(), now = Date.now) {
|
|
18580
|
+
if (!telemetryAllowed()) return;
|
|
18581
|
+
const file = markerPath(configDir);
|
|
18582
|
+
let marker;
|
|
18583
|
+
try {
|
|
18584
|
+
marker = JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
18585
|
+
} catch {
|
|
18586
|
+
return;
|
|
18587
|
+
}
|
|
18588
|
+
try {
|
|
18589
|
+
fs19.rmSync(file, { force: true });
|
|
18590
|
+
} catch {
|
|
18591
|
+
return;
|
|
18592
|
+
}
|
|
18593
|
+
if (typeof marker.at !== "number" || now() - marker.at > MAX_MARKER_AGE_MS) return;
|
|
18594
|
+
const errorName = typeof marker.errorName === "string" && /^[A-Z_$][\w$]{0,39}$/i.test(marker.errorName) ? marker.errorName : void 0;
|
|
18595
|
+
trackFeatureCompleted({
|
|
18596
|
+
feature: "server",
|
|
18597
|
+
operation: "crash",
|
|
18598
|
+
status: "failed",
|
|
18599
|
+
trigger: OutcomeTriggers.startup,
|
|
18600
|
+
reasonCode: marker.origin === "unhandledRejection" ? OutcomeReasonCodes.UNHANDLED_REJECTION : OutcomeReasonCodes.UNCAUGHT_EXCEPTION,
|
|
18601
|
+
...errorName ? { errorName } : {}
|
|
18602
|
+
});
|
|
18603
|
+
}
|
|
18604
|
+
|
|
18404
18605
|
// src/commands/serve.ts
|
|
18405
18606
|
function readServeOpenState(db) {
|
|
18406
18607
|
try {
|
|
@@ -18449,7 +18650,12 @@ async function serveCommand(format = "text") {
|
|
|
18449
18650
|
const host = process.env.CANONRY_HOST ?? "127.0.0.1";
|
|
18450
18651
|
config.port = port;
|
|
18451
18652
|
const db = createClient(config.database);
|
|
18452
|
-
|
|
18653
|
+
try {
|
|
18654
|
+
migrate(db);
|
|
18655
|
+
} catch (err) {
|
|
18656
|
+
trackServerStartFailure(err, "MIGRATION_FAILED");
|
|
18657
|
+
throw err;
|
|
18658
|
+
}
|
|
18453
18659
|
try {
|
|
18454
18660
|
const result = await repairNormalizedPathsOnStartup(db);
|
|
18455
18661
|
if (result && result.updated > 0 && format === "text") {
|
|
@@ -18526,10 +18732,13 @@ Canonry server running at ${url}`);
|
|
|
18526
18732
|
}, null, 2));
|
|
18527
18733
|
}
|
|
18528
18734
|
setTelemetrySource("cli-server");
|
|
18735
|
+
watchServerCrashes();
|
|
18736
|
+
reportPreviousServerCrash();
|
|
18529
18737
|
const providerNames = registeredProviderNames(config);
|
|
18530
18738
|
trackEvent("serve.started", {
|
|
18531
18739
|
providerCount: providerNames.length,
|
|
18532
18740
|
providers: providerNames,
|
|
18741
|
+
...installAttribution(),
|
|
18533
18742
|
// Who launched the server: an agent-started install is its own funnel.
|
|
18534
18743
|
...cliRuntimeContext()
|
|
18535
18744
|
});
|
|
@@ -18540,6 +18749,7 @@ Canonry server running at ${url}`);
|
|
|
18540
18749
|
`);
|
|
18541
18750
|
return;
|
|
18542
18751
|
}
|
|
18752
|
+
trackServerStartFailure(err);
|
|
18543
18753
|
try {
|
|
18544
18754
|
await closeWithIdleSweep(app);
|
|
18545
18755
|
} catch (closeErr) {
|
|
@@ -18732,10 +18942,11 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
18732
18942
|
},
|
|
18733
18943
|
{
|
|
18734
18944
|
path: ["init"],
|
|
18735
|
-
usage: "canonry init [--force] [--gemini-key <key>] [--openai-key <key>] [--claude-key <key>] [--perplexity-key <key>] [--muse-key <key>] [--local-url <url>] [--local-model <name>] [--local-key <key>] [--google-client-id <id>] [--google-client-secret <key>] [--skip-skills] [--skip-mcp] [--skills-dir <path>] [--format json]",
|
|
18945
|
+
usage: "canonry init [--force] [--ref <tag>] [--gemini-key <key>] [--openai-key <key>] [--claude-key <key>] [--perplexity-key <key>] [--muse-key <key>] [--local-url <url>] [--local-model <name>] [--local-key <key>] [--google-client-id <id>] [--google-client-secret <key>] [--skip-skills] [--skip-mcp] [--skills-dir <path>] [--format json]",
|
|
18736
18946
|
help: 'Optional interactive provider and OAuth setup. First-run Page Health does not need this: use "canonry bootstrap", then "canonry serve". At least one provider is required here. --format json needs provider flags or environment variables.',
|
|
18737
18947
|
options: {
|
|
18738
18948
|
force: { type: "boolean", short: "f", default: false },
|
|
18949
|
+
ref: stringOption(),
|
|
18739
18950
|
"gemini-key": stringOption(),
|
|
18740
18951
|
"openai-key": stringOption(),
|
|
18741
18952
|
"claude-key": stringOption(),
|
|
@@ -18754,6 +18965,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
18754
18965
|
run: async (input) => {
|
|
18755
18966
|
await initCommand({
|
|
18756
18967
|
force: getBoolean(input.values, "force"),
|
|
18968
|
+
ref: getString(input.values, "ref"),
|
|
18757
18969
|
geminiKey: getString(input.values, "gemini-key"),
|
|
18758
18970
|
openaiKey: getString(input.values, "openai-key"),
|
|
18759
18971
|
claudeKey: getString(input.values, "claude-key"),
|
|
@@ -18773,17 +18985,19 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
18773
18985
|
},
|
|
18774
18986
|
{
|
|
18775
18987
|
path: ["bootstrap"],
|
|
18776
|
-
usage: "canonry bootstrap [--format json]",
|
|
18988
|
+
usage: "canonry bootstrap [--ref <tag>] [--format json]",
|
|
18777
18989
|
help: "Create or reconcile the local config, SQLite database, and default API key from supported environment variables. Provider credentials are optional. Safe to rerun: existing settings are preserved and the result reports created, updated, or unchanged. The legacy --force/-f flag is accepted but has no effect.",
|
|
18778
18990
|
options: {
|
|
18779
18991
|
// Compatibility for scripts written before bootstrap became idempotent.
|
|
18780
18992
|
// Keep this out of usage: the flag is unnecessary and has no behavior.
|
|
18781
|
-
force: { type: "boolean", short: "f", default: false }
|
|
18993
|
+
force: { type: "boolean", short: "f", default: false },
|
|
18994
|
+
ref: stringOption()
|
|
18782
18995
|
},
|
|
18783
18996
|
allowPositionals: false,
|
|
18784
18997
|
run: async (input) => {
|
|
18785
18998
|
await bootstrapCommand({
|
|
18786
|
-
format: input.format
|
|
18999
|
+
format: input.format,
|
|
19000
|
+
ref: getString(input.values, "ref")
|
|
18787
19001
|
});
|
|
18788
19002
|
}
|
|
18789
19003
|
},
|
|
@@ -18839,6 +19053,15 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
18839
19053
|
stopDaemon(input.format);
|
|
18840
19054
|
}
|
|
18841
19055
|
},
|
|
19056
|
+
{
|
|
19057
|
+
path: ["support"],
|
|
19058
|
+
usage: "canonry support [--format json]",
|
|
19059
|
+
help: "Where to get help: the Canonry Discord, the issue tracker, and canonry feedback.",
|
|
19060
|
+
allowPositionals: false,
|
|
19061
|
+
run: async (input) => {
|
|
19062
|
+
supportCommand(input.format);
|
|
19063
|
+
}
|
|
19064
|
+
},
|
|
18842
19065
|
{
|
|
18843
19066
|
path: ["feedback"],
|
|
18844
19067
|
usage: FEEDBACK_USAGE,
|
|
@@ -19851,14 +20074,14 @@ Usage: ${usage}`, {
|
|
|
19851
20074
|
}
|
|
19852
20075
|
}
|
|
19853
20076
|
];
|
|
19854
|
-
function siteHealthAlias(sourcePath,
|
|
20077
|
+
function siteHealthAlias(sourcePath, path13, usage) {
|
|
19855
20078
|
const source = TECHNICAL_AEO_CLI_COMMANDS_BASE.find(
|
|
19856
20079
|
(candidate) => candidate.path.join(" ") === sourcePath.join(" ")
|
|
19857
20080
|
);
|
|
19858
20081
|
if (!source) throw new Error(`Missing Site Health compatibility source: ${sourcePath.join(" ")}`);
|
|
19859
20082
|
return {
|
|
19860
20083
|
...source,
|
|
19861
|
-
path:
|
|
20084
|
+
path: path13,
|
|
19862
20085
|
usage,
|
|
19863
20086
|
run: async (input) => {
|
|
19864
20087
|
try {
|
|
@@ -19869,7 +20092,7 @@ function siteHealthAlias(sourcePath, path12, usage) {
|
|
|
19869
20092
|
throw usageError(`${firstLine}
|
|
19870
20093
|
Usage: ${usage}`, {
|
|
19871
20094
|
message: error.message,
|
|
19872
|
-
details: { ...error.details, command:
|
|
20095
|
+
details: { ...error.details, command: path13.join("."), usage }
|
|
19873
20096
|
});
|
|
19874
20097
|
}
|
|
19875
20098
|
}
|
|
@@ -20242,7 +20465,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
|
20242
20465
|
];
|
|
20243
20466
|
|
|
20244
20467
|
// src/cli-commands/wordpress.ts
|
|
20245
|
-
import
|
|
20468
|
+
import fs20 from "fs";
|
|
20246
20469
|
|
|
20247
20470
|
// src/commands/wordpress.ts
|
|
20248
20471
|
function getClient28() {
|
|
@@ -20481,12 +20704,12 @@ async function wordpressSetMeta(project2, body) {
|
|
|
20481
20704
|
printPageDetail(result);
|
|
20482
20705
|
}
|
|
20483
20706
|
async function wordpressBulkSetMeta(project2, opts) {
|
|
20484
|
-
const
|
|
20485
|
-
const
|
|
20486
|
-
const filePath =
|
|
20707
|
+
const fs21 = await import("fs/promises");
|
|
20708
|
+
const path13 = await import("path");
|
|
20709
|
+
const filePath = path13.resolve(opts.from);
|
|
20487
20710
|
let raw;
|
|
20488
20711
|
try {
|
|
20489
|
-
raw = await
|
|
20712
|
+
raw = await fs21.readFile(filePath, "utf8");
|
|
20490
20713
|
} catch {
|
|
20491
20714
|
throw new CliError({
|
|
20492
20715
|
code: "FILE_READ_ERROR",
|
|
@@ -20583,13 +20806,13 @@ async function wordpressSetSchema(project2, body) {
|
|
|
20583
20806
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
20584
20807
|
}
|
|
20585
20808
|
async function wordpressSchemaDeploy(project2, opts) {
|
|
20586
|
-
const
|
|
20587
|
-
const
|
|
20809
|
+
const fs21 = await import("fs/promises");
|
|
20810
|
+
const path13 = await import("path");
|
|
20588
20811
|
const yaml = await loadYamlModule();
|
|
20589
|
-
const filePath =
|
|
20812
|
+
const filePath = path13.resolve(opts.profile);
|
|
20590
20813
|
let raw;
|
|
20591
20814
|
try {
|
|
20592
|
-
raw = await
|
|
20815
|
+
raw = await fs21.readFile(filePath, "utf8");
|
|
20593
20816
|
} catch {
|
|
20594
20817
|
throw new CliError({
|
|
20595
20818
|
code: "FILE_READ_ERROR",
|
|
@@ -20694,13 +20917,13 @@ async function wordpressOnboard(project2, opts) {
|
|
|
20694
20917
|
}
|
|
20695
20918
|
let profileData;
|
|
20696
20919
|
if (opts.profile) {
|
|
20697
|
-
const
|
|
20698
|
-
const
|
|
20920
|
+
const fs21 = await import("fs/promises");
|
|
20921
|
+
const path13 = await import("path");
|
|
20699
20922
|
const yaml = await loadYamlModule();
|
|
20700
|
-
const filePath =
|
|
20923
|
+
const filePath = path13.resolve(opts.profile);
|
|
20701
20924
|
let raw;
|
|
20702
20925
|
try {
|
|
20703
|
-
raw = await
|
|
20926
|
+
raw = await fs21.readFile(filePath, "utf8");
|
|
20704
20927
|
} catch {
|
|
20705
20928
|
throw new CliError({
|
|
20706
20929
|
code: "FILE_READ_ERROR",
|
|
@@ -20849,7 +21072,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
20849
21072
|
}
|
|
20850
21073
|
if (contentFile) {
|
|
20851
21074
|
try {
|
|
20852
|
-
return
|
|
21075
|
+
return fs20.readFileSync(contentFile, "utf-8");
|
|
20853
21076
|
} catch (error) {
|
|
20854
21077
|
const message = describeError(error);
|
|
20855
21078
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|
|
@@ -21327,6 +21550,7 @@ async function agentAttach(opts) {
|
|
|
21327
21550
|
const existing = await client.listNotifications(opts.project);
|
|
21328
21551
|
const hasAgent = existing.some((n) => n.source === "agent");
|
|
21329
21552
|
if (hasAgent) {
|
|
21553
|
+
trackCliConnection({ integration: "agent_webhook", action: "connect", status: "cancelled", reasonCode: "ALREADY_CONNECTED" });
|
|
21330
21554
|
if (isMachineFormat(opts.format)) {
|
|
21331
21555
|
console.log(JSON.stringify({ status: "already-attached", project: opts.project }));
|
|
21332
21556
|
} else {
|
|
@@ -21351,6 +21575,7 @@ async function agentDetach(opts) {
|
|
|
21351
21575
|
const existing = await client.listNotifications(opts.project);
|
|
21352
21576
|
const agentNotif = existing.find((n) => n.source === "agent");
|
|
21353
21577
|
if (!agentNotif) {
|
|
21578
|
+
trackCliConnection({ integration: "agent_webhook", action: "disconnect", status: "cancelled", reasonCode: "NOT_CONNECTED" });
|
|
21354
21579
|
if (isMachineFormat(opts.format)) {
|
|
21355
21580
|
console.log(JSON.stringify({ status: "not-attached", project: opts.project }));
|
|
21356
21581
|
} else {
|
|
@@ -22165,6 +22390,7 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
22165
22390
|
...USERS_CLI_COMMANDS,
|
|
22166
22391
|
...COMPETITOR_CLI_COMMANDS,
|
|
22167
22392
|
...SETTINGS_CLI_COMMANDS,
|
|
22393
|
+
...DASHBOARD_CLI_COMMANDS,
|
|
22168
22394
|
...SKILLS_CLI_COMMANDS,
|
|
22169
22395
|
...SNAPSHOT_CLI_COMMANDS,
|
|
22170
22396
|
...RUN_CLI_COMMANDS,
|
|
@@ -22304,9 +22530,11 @@ Automation:
|
|
|
22304
22530
|
|
|
22305
22531
|
Admin:
|
|
22306
22532
|
settings Show/update provider and quota settings
|
|
22533
|
+
dashboard Reset the dashboard password
|
|
22307
22534
|
backfill Backfill answer visibility or insights
|
|
22308
22535
|
telemetry Manage anonymous telemetry
|
|
22309
22536
|
history <project> Show audit trail
|
|
22537
|
+
support Get help: Canonry Discord and issue tracker
|
|
22310
22538
|
|
|
22311
22539
|
Global options:
|
|
22312
22540
|
--format json Machine-readable output: one JSON document (all commands)
|