@ainyc/canonry 4.110.0 → 4.111.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 +1 -1
- package/assets/assets/{BacklinksPage-Duk8YbV2.js → BacklinksPage-Ccp5dJm2.js} +1 -1
- package/assets/assets/ChartPrimitives-DZI_FVyX.js +1 -0
- package/assets/assets/ProjectPage-feeXXGgl.js +7 -0
- package/assets/assets/{RunRow-DH8UMAwj.js → RunRow-CPf7aV1o.js} +1 -1
- package/assets/assets/{RunsPage-OPteH1b_.js → RunsPage-CI8AcUal.js} +1 -1
- package/assets/assets/{SettingsPage-7cspMOFv.js → SettingsPage-QI2X5EIb.js} +1 -1
- package/assets/assets/{TrafficPage-D4pcnfc8.js → TrafficPage-CcELR6n1.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-D-KbCCEK.js → TrafficSourceDetailPage-C-9rc4ly.js} +1 -1
- package/assets/assets/{arrow-left-M8KVuve8.js → arrow-left-3WT6TImA.js} +1 -1
- package/assets/assets/{extract-error-message-D2aTaSV5.js → extract-error-message-43ehRbIG.js} +1 -1
- package/assets/assets/{index-ChPgQUZ5.js → index-BpnaXO_X.js} +51 -51
- package/assets/assets/index-JD5rv_sY.css +1 -0
- package/assets/assets/{trash-2-BNVgf5NY.js → trash-2-Dk-RvBpF.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-6PHBWPPN.js → chunk-4TQOZJPF.js} +4 -4
- package/dist/{chunk-JGRVQJHX.js → chunk-CVXBE3ST.js} +16 -1
- package/dist/{chunk-X4LLTNQZ.js → chunk-Y26GYDS6.js} +1 -1
- package/dist/{chunk-YQ4KOC5Z.js → chunk-ZT7GVLS3.js} +3 -0
- package/dist/cli.js +400 -102
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-BGLF7DQW.js → intelligence-service-4MQUT3OO.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +7 -7
- package/assets/assets/ChartPrimitives-aLxtVH28.js +0 -1
- package/assets/assets/ProjectPage-Bqd0JvpC.js +0 -7
- package/assets/assets/index-CjrSrPKf.css +0 -1
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-4TQOZJPF.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-Y26GYDS6.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-CVXBE3ST.js";
|
|
58
58
|
import {
|
|
59
59
|
BacklinkSources,
|
|
60
60
|
CcReleaseSyncStatuses,
|
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
providerQuotaPolicySchema,
|
|
81
81
|
resolveProviderInput,
|
|
82
82
|
winnabilityClassSchema
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-ZT7GVLS3.js";
|
|
84
84
|
|
|
85
85
|
// src/cli.ts
|
|
86
86
|
import { pathToFileURL } from "url";
|
|
@@ -126,9 +126,9 @@ import { parseArgs } from "util";
|
|
|
126
126
|
function commandId(spec) {
|
|
127
127
|
return spec.path.join(".");
|
|
128
128
|
}
|
|
129
|
-
function matchesPath(args,
|
|
130
|
-
if (args.length <
|
|
131
|
-
return
|
|
129
|
+
function matchesPath(args, path10) {
|
|
130
|
+
if (args.length < path10.length) return false;
|
|
131
|
+
return path10.every((segment, index) => args[index] === segment);
|
|
132
132
|
}
|
|
133
133
|
function withGlobalOptions(options) {
|
|
134
134
|
const base = options ? { ...options } : {};
|
|
@@ -1973,6 +1973,272 @@ async function pollSession(client, project, sessionId, quiet = false) {
|
|
|
1973
1973
|
}
|
|
1974
1974
|
}
|
|
1975
1975
|
|
|
1976
|
+
// src/commands/discover-eval.ts
|
|
1977
|
+
import fs2 from "fs";
|
|
1978
|
+
import path from "path";
|
|
1979
|
+
|
|
1980
|
+
// src/discovery-eval.ts
|
|
1981
|
+
var DISCOVERY_EVAL_PANEL = [
|
|
1982
|
+
{
|
|
1983
|
+
slug: "eval-local-single-intent",
|
|
1984
|
+
displayName: "Summit Roof Coatings",
|
|
1985
|
+
domain: "summitroofcoatings.com",
|
|
1986
|
+
icp: "commercial roof coating contractor in Phoenix, Arizona",
|
|
1987
|
+
buyer: "commercial property managers responsible for flat-roof maintenance budgets",
|
|
1988
|
+
locations: [{ label: "phoenix", city: "Phoenix", region: "Arizona", country: "US" }]
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
slug: "eval-local-multi-intent",
|
|
1992
|
+
displayName: "Peak Comfort HVAC",
|
|
1993
|
+
domain: "peakcomforthvac.com",
|
|
1994
|
+
icp: "residential HVAC installation, repair, and maintenance company in Denver, Colorado",
|
|
1995
|
+
buyer: "homeowners with aging furnaces or AC units comparing replacement and repair options",
|
|
1996
|
+
locations: [{ label: "denver", city: "Denver", region: "Colorado", country: "US" }]
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
slug: "eval-b2b-saas",
|
|
2000
|
+
displayName: "QuoteBeam",
|
|
2001
|
+
domain: "quotebeam.io",
|
|
2002
|
+
icp: "quoting and proposal software for residential solar installers",
|
|
2003
|
+
buyer: "solar sales managers evaluating quoting tools for a 10-50 rep team",
|
|
2004
|
+
locations: []
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
slug: "eval-national-ecommerce",
|
|
2008
|
+
displayName: "Willow and Sprout",
|
|
2009
|
+
domain: "willowandsprout.com",
|
|
2010
|
+
icp: "organic cotton baby clothing brand sold online across the US",
|
|
2011
|
+
buyer: "expecting parents researching non-toxic baby essentials",
|
|
2012
|
+
locations: []
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
slug: "eval-problem-heavy-consumer",
|
|
2016
|
+
displayName: "SwiftRemit",
|
|
2017
|
+
domain: "swiftremit.app",
|
|
2018
|
+
icp: "mobile app for sending money internationally with low fees",
|
|
2019
|
+
buyer: "immigrants who send money home to family every month",
|
|
2020
|
+
locations: []
|
|
2021
|
+
}
|
|
2022
|
+
];
|
|
2023
|
+
var EVAL_CANONICAL_FLOOR = 8;
|
|
2024
|
+
var EVAL_BANDS = {
|
|
2025
|
+
/** canonicalCount must be >= baseline * this factor (and >= the floor). */
|
|
2026
|
+
canonicalCountFactor: 0.6,
|
|
2027
|
+
/** retention may drop at most this many absolute points below baseline. */
|
|
2028
|
+
retentionDrop: 0.2,
|
|
2029
|
+
/** brandShare may exceed baseline by at most this (and never exceed 0.1). */
|
|
2030
|
+
brandShareSlack: 0.05,
|
|
2031
|
+
brandShareCeiling: 0.1,
|
|
2032
|
+
/** duration must be <= baseline * factor + slack seconds. */
|
|
2033
|
+
durationFactor: 2,
|
|
2034
|
+
durationSlackSeconds: 30
|
|
2035
|
+
};
|
|
2036
|
+
function scoreSession(shape, session) {
|
|
2037
|
+
const raw = session.seedCountRaw ?? 0;
|
|
2038
|
+
const brandFiltered = session.seedBrandFilteredCount ?? 0;
|
|
2039
|
+
const preFilterTotal = raw + brandFiltered;
|
|
2040
|
+
const truncated = session.canonicalCount == null;
|
|
2041
|
+
const canonicalCount = session.canonicalCount ?? session.seedCount ?? 0;
|
|
2042
|
+
const started = session.startedAt ? Date.parse(session.startedAt) : NaN;
|
|
2043
|
+
const finished = session.finishedAt ? Date.parse(session.finishedAt) : NaN;
|
|
2044
|
+
return {
|
|
2045
|
+
shape,
|
|
2046
|
+
seedCountRaw: raw,
|
|
2047
|
+
canonicalCount,
|
|
2048
|
+
canonicalCountTruncated: truncated,
|
|
2049
|
+
retention: raw > 0 ? canonicalCount / raw : 0,
|
|
2050
|
+
brandShare: preFilterTotal > 0 ? brandFiltered / preFilterTotal : 0,
|
|
2051
|
+
groundingShare: raw > 0 ? (session.seedFromGroundingCount ?? 0) / raw : 0,
|
|
2052
|
+
bandPairFraction: session.dedupBandPairFraction ?? null,
|
|
2053
|
+
probeCount: session.probeCount ?? 0,
|
|
2054
|
+
warning: session.warning ?? null,
|
|
2055
|
+
durationSeconds: Number.isFinite(started) && Number.isFinite(finished) ? Math.round((finished - started) / 1e3) : null
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
function compareToBaseline(scorecards, baseline) {
|
|
2059
|
+
const regressions = [];
|
|
2060
|
+
const notes = [];
|
|
2061
|
+
const bySlug = new Map(scorecards.map((c) => [c.shape, c]));
|
|
2062
|
+
for (const base of baseline.scorecards) {
|
|
2063
|
+
const current = bySlug.get(base.shape);
|
|
2064
|
+
if (!current) {
|
|
2065
|
+
regressions.push(`${base.shape}: missing from this run (baseline shape not evaluated)`);
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
bySlug.delete(base.shape);
|
|
2069
|
+
if (current.canonicalCount < EVAL_CANONICAL_FLOOR) {
|
|
2070
|
+
regressions.push(
|
|
2071
|
+
`${base.shape}: canonicalCount ${current.canonicalCount} is below the absolute platform floor (${EVAL_CANONICAL_FLOOR})`
|
|
2072
|
+
);
|
|
2073
|
+
}
|
|
2074
|
+
if (current.canonicalCount < base.canonicalCount * EVAL_BANDS.canonicalCountFactor) {
|
|
2075
|
+
regressions.push(
|
|
2076
|
+
`${base.shape}: canonicalCount ${current.canonicalCount} vs baseline ${base.canonicalCount} (band: >= ${EVAL_BANDS.canonicalCountFactor}x)`
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
if (current.retention < base.retention - EVAL_BANDS.retentionDrop) {
|
|
2080
|
+
regressions.push(
|
|
2081
|
+
`${base.shape}: retention ${current.retention.toFixed(2)} vs baseline ${base.retention.toFixed(2)} (band: -${EVAL_BANDS.retentionDrop})`
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
const brandCeiling = Math.min(base.brandShare + EVAL_BANDS.brandShareSlack, EVAL_BANDS.brandShareCeiling);
|
|
2085
|
+
if (current.brandShare > brandCeiling) {
|
|
2086
|
+
regressions.push(
|
|
2087
|
+
`${base.shape}: brandShare ${current.brandShare.toFixed(2)} exceeds ${brandCeiling.toFixed(2)} (no-brand rule regressed)`
|
|
2088
|
+
);
|
|
2089
|
+
}
|
|
2090
|
+
if (current.warning) {
|
|
2091
|
+
regressions.push(`${base.shape}: collapse warning fired: ${current.warning.slice(0, 80)}`);
|
|
2092
|
+
}
|
|
2093
|
+
if (current.durationSeconds != null && base.durationSeconds != null && current.durationSeconds > base.durationSeconds * EVAL_BANDS.durationFactor + EVAL_BANDS.durationSlackSeconds) {
|
|
2094
|
+
regressions.push(
|
|
2095
|
+
`${base.shape}: duration ${current.durationSeconds}s vs baseline ${base.durationSeconds}s (band: ${EVAL_BANDS.durationFactor}x + ${EVAL_BANDS.durationSlackSeconds}s)`
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
2098
|
+
if (current.canonicalCountTruncated) {
|
|
2099
|
+
notes.push(`${base.shape}: engine predates canonical_count; using truncated seedCount (understates quality)`);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
for (const [slug] of bySlug) {
|
|
2103
|
+
notes.push(`${slug}: new shape with no baseline entry (add it via --update-baseline)`);
|
|
2104
|
+
}
|
|
2105
|
+
return { pass: regressions.length === 0, regressions, notes };
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
// src/commands/discover-eval.ts
|
|
2109
|
+
var DEFAULT_BASELINE_PATH = "canonry-discovery-eval-baseline.json";
|
|
2110
|
+
var POLL_INTERVAL_MS2 = 5e3;
|
|
2111
|
+
var SHAPE_TIMEOUT_MS = 10 * 6e4;
|
|
2112
|
+
async function runDiscoveryEvalPanel(client, shapes, opts) {
|
|
2113
|
+
const scorecards = [];
|
|
2114
|
+
const pollInterval = opts.pollIntervalMs ?? POLL_INTERVAL_MS2;
|
|
2115
|
+
const timeout = opts.shapeTimeoutMs ?? SHAPE_TIMEOUT_MS;
|
|
2116
|
+
const now = opts.now ?? Date.now;
|
|
2117
|
+
for (const shape of shapes) {
|
|
2118
|
+
await client.putProject(shape.slug, {
|
|
2119
|
+
displayName: shape.displayName,
|
|
2120
|
+
canonicalDomain: shape.domain,
|
|
2121
|
+
country: "US",
|
|
2122
|
+
language: "en",
|
|
2123
|
+
...shape.locations.length > 0 ? { locations: shape.locations, defaultLocation: shape.locations[0].label } : {}
|
|
2124
|
+
});
|
|
2125
|
+
const started = await client.triggerDiscoveryRun(shape.slug, {
|
|
2126
|
+
icpDescription: shape.icp,
|
|
2127
|
+
buyerDescription: shape.buyer,
|
|
2128
|
+
maxProbes: opts.maxProbes ?? 2,
|
|
2129
|
+
probeConcurrency: opts.probeConcurrency ?? 2,
|
|
2130
|
+
...opts.seedProviders && opts.seedProviders.length > 0 ? { seedProviders: opts.seedProviders } : {}
|
|
2131
|
+
});
|
|
2132
|
+
const sessionId = typeof started.sessionId === "string" ? started.sessionId : "";
|
|
2133
|
+
if (!sessionId) {
|
|
2134
|
+
throw new CliError({
|
|
2135
|
+
code: "EVAL_SESSION_START_FAILED",
|
|
2136
|
+
message: `${shape.slug}: discover run returned no sessionId`,
|
|
2137
|
+
exitCode: EXIT_USER_ERROR
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
const deadline = now() + timeout;
|
|
2141
|
+
let session;
|
|
2142
|
+
for (; ; ) {
|
|
2143
|
+
const rows = await client.listDiscoverySessions(shape.slug, { limit: 10 });
|
|
2144
|
+
session = rows.find((r) => r.id === sessionId);
|
|
2145
|
+
if (session?.status === "completed") break;
|
|
2146
|
+
if (session?.status === "failed") {
|
|
2147
|
+
throw new CliError({
|
|
2148
|
+
code: "EVAL_SESSION_FAILED",
|
|
2149
|
+
message: `${shape.slug}: discovery session failed`,
|
|
2150
|
+
exitCode: EXIT_USER_ERROR,
|
|
2151
|
+
details: { sessionId }
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
if (now() > deadline) {
|
|
2155
|
+
throw new CliError({
|
|
2156
|
+
code: "EVAL_SESSION_TIMEOUT",
|
|
2157
|
+
message: `${shape.slug}: session did not complete within ${Math.round(timeout / 6e4)} minutes`,
|
|
2158
|
+
exitCode: EXIT_USER_ERROR,
|
|
2159
|
+
details: { sessionId }
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
2163
|
+
}
|
|
2164
|
+
scorecards.push(scoreSession(shape.slug, session));
|
|
2165
|
+
}
|
|
2166
|
+
return scorecards;
|
|
2167
|
+
}
|
|
2168
|
+
function renderHuman(scorecards, verdict) {
|
|
2169
|
+
console.log("SHAPE RAW CANON RETENTION BRAND GROUND BAND TIME");
|
|
2170
|
+
for (const c of scorecards) {
|
|
2171
|
+
console.log(
|
|
2172
|
+
[
|
|
2173
|
+
c.shape.padEnd(30),
|
|
2174
|
+
String(c.seedCountRaw).padStart(4),
|
|
2175
|
+
String(c.canonicalCount).padStart(6) + (c.canonicalCountTruncated ? "*" : " "),
|
|
2176
|
+
c.retention.toFixed(2).padStart(9),
|
|
2177
|
+
c.brandShare.toFixed(2).padStart(6),
|
|
2178
|
+
c.groundingShare.toFixed(2).padStart(7),
|
|
2179
|
+
(c.bandPairFraction ?? 0).toFixed(2).padStart(5),
|
|
2180
|
+
c.durationSeconds == null ? " ?" : `${String(c.durationSeconds).padStart(4)}s`
|
|
2181
|
+
].join(" ")
|
|
2182
|
+
);
|
|
2183
|
+
if (c.warning) console.log(` warning: ${c.warning}`);
|
|
2184
|
+
}
|
|
2185
|
+
if (verdict) {
|
|
2186
|
+
for (const note of verdict.notes) console.log(`note: ${note}`);
|
|
2187
|
+
for (const regression of verdict.regressions) console.log(`REGRESSION: ${regression}`);
|
|
2188
|
+
console.log(verdict.pass ? "PASS: no regressions against the baseline." : "FAIL: regressions detected.");
|
|
2189
|
+
} else {
|
|
2190
|
+
console.log("No baseline compared (wrote or missing baseline).");
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
async function discoverEvalWithClient(client, opts) {
|
|
2194
|
+
const selected = opts.shapes && opts.shapes.length > 0 ? DISCOVERY_EVAL_PANEL.filter((s) => opts.shapes.includes(s.slug)) : DISCOVERY_EVAL_PANEL;
|
|
2195
|
+
if (selected.length === 0) {
|
|
2196
|
+
throw new CliError({
|
|
2197
|
+
code: "EVAL_NO_SHAPES",
|
|
2198
|
+
message: `no matching shapes; known: ${DISCOVERY_EVAL_PANEL.map((s) => s.slug).join(", ")}`,
|
|
2199
|
+
exitCode: EXIT_USER_ERROR
|
|
2200
|
+
});
|
|
2201
|
+
}
|
|
2202
|
+
const scorecards = await runDiscoveryEvalPanel(client, selected, opts);
|
|
2203
|
+
const baselinePath = path.resolve(opts.baseline ?? DEFAULT_BASELINE_PATH);
|
|
2204
|
+
if (opts.updateBaseline) {
|
|
2205
|
+
const baseline2 = { capturedAt: (/* @__PURE__ */ new Date()).toISOString(), scorecards };
|
|
2206
|
+
fs2.writeFileSync(baselinePath, JSON.stringify(baseline2, null, 2) + "\n");
|
|
2207
|
+
if (opts.format === "json" || opts.format === "jsonl") {
|
|
2208
|
+
console.log(JSON.stringify({ scorecards, baselineWritten: baselinePath }, null, 2));
|
|
2209
|
+
} else {
|
|
2210
|
+
renderHuman(scorecards, null);
|
|
2211
|
+
console.log(`Baseline written: ${baselinePath}`);
|
|
2212
|
+
}
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
if (!fs2.existsSync(baselinePath)) {
|
|
2216
|
+
throw new CliError({
|
|
2217
|
+
code: "EVAL_NO_BASELINE",
|
|
2218
|
+
message: `no baseline at ${baselinePath}; run with --update-baseline to capture one`,
|
|
2219
|
+
exitCode: EXIT_USER_ERROR
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
const baseline = JSON.parse(fs2.readFileSync(baselinePath, "utf8"));
|
|
2223
|
+
const verdict = compareToBaseline(scorecards, baseline);
|
|
2224
|
+
if (opts.format === "json" || opts.format === "jsonl") {
|
|
2225
|
+
console.log(JSON.stringify({ scorecards, verdict, baseline: { capturedAt: baseline.capturedAt } }, null, 2));
|
|
2226
|
+
} else {
|
|
2227
|
+
renderHuman(scorecards, verdict);
|
|
2228
|
+
}
|
|
2229
|
+
if (!verdict.pass) {
|
|
2230
|
+
throw new CliError({
|
|
2231
|
+
code: "EVAL_REGRESSION",
|
|
2232
|
+
message: `${verdict.regressions.length} regression${verdict.regressions.length === 1 ? "" : "s"} against the baseline`,
|
|
2233
|
+
exitCode: EXIT_USER_ERROR,
|
|
2234
|
+
details: { regressions: verdict.regressions }
|
|
2235
|
+
});
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
async function discoverEval(opts) {
|
|
2239
|
+
await discoverEvalWithClient(createApiClient(), opts);
|
|
2240
|
+
}
|
|
2241
|
+
|
|
1976
2242
|
// src/cli-commands/discover.ts
|
|
1977
2243
|
function parseFloatOption(values, key, usage) {
|
|
1978
2244
|
const raw = values[key];
|
|
@@ -2096,6 +2362,38 @@ var DISCOVER_CLI_COMMANDS = [
|
|
|
2096
2362
|
});
|
|
2097
2363
|
}
|
|
2098
2364
|
},
|
|
2365
|
+
{
|
|
2366
|
+
path: ["discover", "eval"],
|
|
2367
|
+
usage: "canonry discover eval [--baseline <path>] [--update-baseline] [--shape eval-b2b-saas ...] [--seed-provider gemini --seed-provider openai] [--max-probes 2] [--probe-concurrency 2] [--format json]",
|
|
2368
|
+
options: {
|
|
2369
|
+
baseline: stringOption(),
|
|
2370
|
+
"update-baseline": { type: "boolean", default: false },
|
|
2371
|
+
shape: multiStringOption(),
|
|
2372
|
+
"seed-provider": multiStringOption(),
|
|
2373
|
+
"max-probes": stringOption(),
|
|
2374
|
+
"probe-concurrency": stringOption()
|
|
2375
|
+
},
|
|
2376
|
+
run: async (input) => {
|
|
2377
|
+
const usage = "canonry discover eval [--baseline <path>] [--update-baseline] [--shape eval-b2b-saas ...] [--seed-provider gemini --seed-provider openai] [--max-probes 2] [--probe-concurrency 2] [--format json]";
|
|
2378
|
+
await discoverEval({
|
|
2379
|
+
baseline: getString(input.values, "baseline"),
|
|
2380
|
+
updateBaseline: getBoolean(input.values, "update-baseline"),
|
|
2381
|
+
shapes: getStringArray(input.values, "shape"),
|
|
2382
|
+
seedProviders: getStringArray(input.values, "seed-provider"),
|
|
2383
|
+
maxProbes: parseIntegerOption(input, "max-probes", {
|
|
2384
|
+
command: "discover.eval",
|
|
2385
|
+
usage,
|
|
2386
|
+
message: "--max-probes must be an integer"
|
|
2387
|
+
}),
|
|
2388
|
+
probeConcurrency: parseIntegerOption(input, "probe-concurrency", {
|
|
2389
|
+
command: "discover.eval",
|
|
2390
|
+
usage,
|
|
2391
|
+
message: "--probe-concurrency must be an integer"
|
|
2392
|
+
}),
|
|
2393
|
+
format: input.format
|
|
2394
|
+
});
|
|
2395
|
+
}
|
|
2396
|
+
},
|
|
2099
2397
|
{
|
|
2100
2398
|
path: ["discover", "seed"],
|
|
2101
2399
|
usage: 'canonry discover seed <project> [--icp "..."] [--buyer "..."] [--seed-provider gemini --seed-provider openai] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
|
|
@@ -2650,9 +2948,9 @@ async function gaConnect(project, opts) {
|
|
|
2650
2948
|
propertyId: opts.propertyId
|
|
2651
2949
|
};
|
|
2652
2950
|
if (opts.keyFile) {
|
|
2653
|
-
const
|
|
2951
|
+
const fs13 = await import("fs");
|
|
2654
2952
|
try {
|
|
2655
|
-
const content =
|
|
2953
|
+
const content = fs13.readFileSync(opts.keyFile, "utf-8");
|
|
2656
2954
|
JSON.parse(content);
|
|
2657
2955
|
body.keyJson = content;
|
|
2658
2956
|
} catch (e) {
|
|
@@ -3860,9 +4158,9 @@ async function getCommand(opts) {
|
|
|
3860
4158
|
console.log(JSON.stringify(leaf, null, 2));
|
|
3861
4159
|
}
|
|
3862
4160
|
}
|
|
3863
|
-
function walkPath(value,
|
|
3864
|
-
if (!
|
|
3865
|
-
const segments =
|
|
4161
|
+
function walkPath(value, path10) {
|
|
4162
|
+
if (!path10 || path10 === ".") return value;
|
|
4163
|
+
const segments = path10.split(".").flatMap((part) => {
|
|
3866
4164
|
const tokens = [];
|
|
3867
4165
|
let i = 0;
|
|
3868
4166
|
const bracketStart = part.indexOf("[");
|
|
@@ -3910,13 +4208,13 @@ var GET_CLI_COMMANDS = [
|
|
|
3910
4208
|
},
|
|
3911
4209
|
run: async (input) => {
|
|
3912
4210
|
const project = requireProject(input, "get", USAGE2);
|
|
3913
|
-
const
|
|
4211
|
+
const path10 = requirePositional(input, 1, {
|
|
3914
4212
|
command: "get",
|
|
3915
4213
|
usage: USAGE2,
|
|
3916
4214
|
message: 'path is required (e.g. "scores.mentionShare.value")'
|
|
3917
4215
|
});
|
|
3918
4216
|
const from = getString(input.values, "from");
|
|
3919
|
-
await getCommand({ project, path:
|
|
4217
|
+
await getCommand({ project, path: path10, from, format: input.format });
|
|
3920
4218
|
}
|
|
3921
4219
|
}
|
|
3922
4220
|
];
|
|
@@ -3955,9 +4253,9 @@ async function trafficConnectWordpress(project, opts) {
|
|
|
3955
4253
|
}
|
|
3956
4254
|
let applicationPassword = opts.appPassword?.trim() ?? "";
|
|
3957
4255
|
if (!applicationPassword && opts.appPasswordFile) {
|
|
3958
|
-
const
|
|
4256
|
+
const fs13 = await import("fs");
|
|
3959
4257
|
try {
|
|
3960
|
-
applicationPassword =
|
|
4258
|
+
applicationPassword = fs13.readFileSync(opts.appPasswordFile, "utf-8").trim();
|
|
3961
4259
|
} catch (e) {
|
|
3962
4260
|
const msg = e instanceof Error ? e.message : String(e);
|
|
3963
4261
|
throw new CliError({
|
|
@@ -4013,10 +4311,10 @@ async function trafficConnectCloudRun(project, opts) {
|
|
|
4013
4311
|
details: { project }
|
|
4014
4312
|
});
|
|
4015
4313
|
}
|
|
4016
|
-
const
|
|
4314
|
+
const fs13 = await import("fs");
|
|
4017
4315
|
let keyJson;
|
|
4018
4316
|
try {
|
|
4019
|
-
keyJson =
|
|
4317
|
+
keyJson = fs13.readFileSync(opts.serviceAccountKey, "utf-8");
|
|
4020
4318
|
JSON.parse(keyJson);
|
|
4021
4319
|
} catch (e) {
|
|
4022
4320
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -4076,9 +4374,9 @@ async function trafficConnectVercel(project, opts) {
|
|
|
4076
4374
|
}
|
|
4077
4375
|
let token = opts.token?.trim() ?? "";
|
|
4078
4376
|
if (!token && opts.tokenFile) {
|
|
4079
|
-
const
|
|
4377
|
+
const fs13 = await import("fs");
|
|
4080
4378
|
try {
|
|
4081
|
-
token =
|
|
4379
|
+
token = fs13.readFileSync(opts.tokenFile, "utf-8").trim();
|
|
4082
4380
|
} catch (e) {
|
|
4083
4381
|
const msg = e instanceof Error ? e.message : String(e);
|
|
4084
4382
|
throw new CliError({
|
|
@@ -5892,7 +6190,7 @@ var KEYS_CLI_COMMANDS = [
|
|
|
5892
6190
|
];
|
|
5893
6191
|
|
|
5894
6192
|
// src/commands/keyword.ts
|
|
5895
|
-
import
|
|
6193
|
+
import fs3 from "fs";
|
|
5896
6194
|
function getClient12() {
|
|
5897
6195
|
return createApiClient();
|
|
5898
6196
|
}
|
|
@@ -5960,7 +6258,7 @@ async function listKeywords(project, format) {
|
|
|
5960
6258
|
}
|
|
5961
6259
|
}
|
|
5962
6260
|
async function importKeywords(project, filePath, format) {
|
|
5963
|
-
if (!
|
|
6261
|
+
if (!fs3.existsSync(filePath)) {
|
|
5964
6262
|
throw new CliError({
|
|
5965
6263
|
code: "KEYWORD_IMPORT_FILE_NOT_FOUND",
|
|
5966
6264
|
message: `File not found: ${filePath}`,
|
|
@@ -5971,7 +6269,7 @@ async function importKeywords(project, filePath, format) {
|
|
|
5971
6269
|
}
|
|
5972
6270
|
});
|
|
5973
6271
|
}
|
|
5974
|
-
const content =
|
|
6272
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
5975
6273
|
const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
5976
6274
|
if (keywords.length === 0) {
|
|
5977
6275
|
if (isMachineFormat(format)) {
|
|
@@ -6172,7 +6470,7 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
6172
6470
|
];
|
|
6173
6471
|
|
|
6174
6472
|
// src/commands/query.ts
|
|
6175
|
-
import
|
|
6473
|
+
import fs4 from "fs";
|
|
6176
6474
|
function getClient13() {
|
|
6177
6475
|
return createApiClient();
|
|
6178
6476
|
}
|
|
@@ -6263,7 +6561,7 @@ async function listQueries(project, format) {
|
|
|
6263
6561
|
}
|
|
6264
6562
|
}
|
|
6265
6563
|
async function importQueries(project, filePath, format) {
|
|
6266
|
-
if (!
|
|
6564
|
+
if (!fs4.existsSync(filePath)) {
|
|
6267
6565
|
throw new CliError({
|
|
6268
6566
|
code: "QUERY_IMPORT_FILE_NOT_FOUND",
|
|
6269
6567
|
message: `File not found: ${filePath}`,
|
|
@@ -6274,7 +6572,7 @@ async function importQueries(project, filePath, format) {
|
|
|
6274
6572
|
}
|
|
6275
6573
|
});
|
|
6276
6574
|
}
|
|
6277
|
-
const content =
|
|
6575
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
6278
6576
|
const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
6279
6577
|
if (queries2.length === 0) {
|
|
6280
6578
|
if (isMachineFormat(format)) {
|
|
@@ -6476,16 +6774,16 @@ var QUERY_CLI_COMMANDS = [
|
|
|
6476
6774
|
];
|
|
6477
6775
|
|
|
6478
6776
|
// src/commands/mcp.ts
|
|
6479
|
-
import
|
|
6480
|
-
import
|
|
6777
|
+
import fs5 from "fs";
|
|
6778
|
+
import path3 from "path";
|
|
6481
6779
|
import { createRequire } from "module";
|
|
6482
6780
|
|
|
6483
6781
|
// src/mcp-clients.ts
|
|
6484
6782
|
import os from "os";
|
|
6485
|
-
import
|
|
6783
|
+
import path2 from "path";
|
|
6486
6784
|
var CLAUDE_DESKTOP_CONFIG_FILENAME = "claude_desktop_config.json";
|
|
6487
6785
|
function homeRelative(...segments) {
|
|
6488
|
-
return
|
|
6786
|
+
return path2.join(os.homedir(), ...segments);
|
|
6489
6787
|
}
|
|
6490
6788
|
function claudeDesktopConfigPath() {
|
|
6491
6789
|
switch (process.platform) {
|
|
@@ -6493,7 +6791,7 @@ function claudeDesktopConfigPath() {
|
|
|
6493
6791
|
return homeRelative("Library", "Application Support", "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
|
|
6494
6792
|
case "win32": {
|
|
6495
6793
|
const appData = process.env.APPDATA ?? homeRelative("AppData", "Roaming");
|
|
6496
|
-
return
|
|
6794
|
+
return path2.join(appData, "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
|
|
6497
6795
|
}
|
|
6498
6796
|
default:
|
|
6499
6797
|
return homeRelative(".config", "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
|
|
@@ -6506,7 +6804,7 @@ function codexConfigPath() {
|
|
|
6506
6804
|
return homeRelative(".codex", "config.toml");
|
|
6507
6805
|
}
|
|
6508
6806
|
function claudeCodeProjectConfigPath() {
|
|
6509
|
-
return
|
|
6807
|
+
return path2.join(process.cwd(), ".mcp.json");
|
|
6510
6808
|
}
|
|
6511
6809
|
var SUPPORTED_MCP_CLIENTS = [
|
|
6512
6810
|
{
|
|
@@ -6549,7 +6847,7 @@ function listMcpClientIds() {
|
|
|
6549
6847
|
var _require = createRequire(import.meta.url);
|
|
6550
6848
|
function resolveCanonryMcpBin() {
|
|
6551
6849
|
const packageJsonPath = _require.resolve("../package.json");
|
|
6552
|
-
const packageRoot =
|
|
6850
|
+
const packageRoot = path3.dirname(packageJsonPath);
|
|
6553
6851
|
const pkg = _require("../package.json");
|
|
6554
6852
|
const relativeBin = pkg.bin?.["canonry-mcp"];
|
|
6555
6853
|
if (!relativeBin) {
|
|
@@ -6559,7 +6857,7 @@ function resolveCanonryMcpBin() {
|
|
|
6559
6857
|
exitCode: 2
|
|
6560
6858
|
});
|
|
6561
6859
|
}
|
|
6562
|
-
return
|
|
6860
|
+
return path3.resolve(packageRoot, relativeBin);
|
|
6563
6861
|
}
|
|
6564
6862
|
function buildEntry(opts) {
|
|
6565
6863
|
const target = opts.binPath ?? resolveCanonryMcpBin();
|
|
@@ -6592,8 +6890,8 @@ function renderClientSnippet(client, serverName, entry) {
|
|
|
6592
6890
|
return renderJsonSnippet(serverName, entry, client.format);
|
|
6593
6891
|
}
|
|
6594
6892
|
function readJsonConfig(configPath) {
|
|
6595
|
-
if (!
|
|
6596
|
-
const raw =
|
|
6893
|
+
if (!fs5.existsSync(configPath)) return {};
|
|
6894
|
+
const raw = fs5.readFileSync(configPath, "utf-8").trim();
|
|
6597
6895
|
if (!raw) return {};
|
|
6598
6896
|
try {
|
|
6599
6897
|
const parsed = JSON.parse(raw);
|
|
@@ -6611,14 +6909,14 @@ function readJsonConfig(configPath) {
|
|
|
6611
6909
|
}
|
|
6612
6910
|
}
|
|
6613
6911
|
function writeJsonConfig(configPath, value) {
|
|
6614
|
-
|
|
6615
|
-
|
|
6912
|
+
fs5.mkdirSync(path3.dirname(configPath), { recursive: true });
|
|
6913
|
+
fs5.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
6616
6914
|
`, "utf-8");
|
|
6617
6915
|
}
|
|
6618
6916
|
function backupConfigIfPresent(configPath) {
|
|
6619
|
-
if (!
|
|
6917
|
+
if (!fs5.existsSync(configPath)) return void 0;
|
|
6620
6918
|
const backupPath = `${configPath}.canonry.bak`;
|
|
6621
|
-
|
|
6919
|
+
fs5.copyFileSync(configPath, backupPath);
|
|
6622
6920
|
return backupPath;
|
|
6623
6921
|
}
|
|
6624
6922
|
function findClientOrThrow(id) {
|
|
@@ -6972,13 +7270,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
6972
7270
|
];
|
|
6973
7271
|
|
|
6974
7272
|
// src/commands/apply.ts
|
|
6975
|
-
import
|
|
7273
|
+
import fs6 from "fs";
|
|
6976
7274
|
import { parseAllDocuments } from "yaml";
|
|
6977
7275
|
async function applyConfigFile(filePath) {
|
|
6978
|
-
if (!
|
|
7276
|
+
if (!fs6.existsSync(filePath)) {
|
|
6979
7277
|
throw new Error(`File not found: ${filePath}`);
|
|
6980
7278
|
}
|
|
6981
|
-
const content =
|
|
7279
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
6982
7280
|
const docs = parseAllDocuments(content);
|
|
6983
7281
|
const client = createApiClient();
|
|
6984
7282
|
const errors = [];
|
|
@@ -7893,11 +8191,11 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
7893
8191
|
];
|
|
7894
8192
|
|
|
7895
8193
|
// src/commands/report.ts
|
|
7896
|
-
import
|
|
7897
|
-
import
|
|
8194
|
+
import fs7 from "fs";
|
|
8195
|
+
import path4 from "path";
|
|
7898
8196
|
function defaultOutputPath(project, audience) {
|
|
7899
8197
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7900
|
-
return
|
|
8198
|
+
return path4.resolve(process.cwd(), `canonry-report-${project}-${audience}-${date}.html`);
|
|
7901
8199
|
}
|
|
7902
8200
|
async function runReportCommand(project, opts = {}) {
|
|
7903
8201
|
const client = createApiClient();
|
|
@@ -7908,12 +8206,12 @@ async function runReportCommand(project, opts = {}) {
|
|
|
7908
8206
|
return;
|
|
7909
8207
|
}
|
|
7910
8208
|
const html = renderReportHtml(report, { audience });
|
|
7911
|
-
const targetPath = opts.output ?
|
|
7912
|
-
const dir =
|
|
7913
|
-
if (!
|
|
7914
|
-
|
|
8209
|
+
const targetPath = opts.output ? path4.resolve(opts.output) : defaultOutputPath(project, audience);
|
|
8210
|
+
const dir = path4.dirname(targetPath);
|
|
8211
|
+
if (!fs7.existsSync(dir)) {
|
|
8212
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
7915
8213
|
}
|
|
7916
|
-
|
|
8214
|
+
fs7.writeFileSync(targetPath, html, "utf-8");
|
|
7917
8215
|
console.log(`Report written to ${targetPath}`);
|
|
7918
8216
|
}
|
|
7919
8217
|
|
|
@@ -8778,12 +9076,12 @@ var SKILLS_CLI_COMMANDS = [
|
|
|
8778
9076
|
];
|
|
8779
9077
|
|
|
8780
9078
|
// src/commands/snapshot.ts
|
|
8781
|
-
import
|
|
8782
|
-
import
|
|
9079
|
+
import fs9 from "fs";
|
|
9080
|
+
import path6 from "path";
|
|
8783
9081
|
|
|
8784
9082
|
// src/snapshot-pdf.ts
|
|
8785
|
-
import
|
|
8786
|
-
import
|
|
9083
|
+
import fs8 from "fs";
|
|
9084
|
+
import path5 from "path";
|
|
8787
9085
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
8788
9086
|
var PAGE_WIDTH = 612;
|
|
8789
9087
|
var PAGE_HEIGHT = 792;
|
|
@@ -8995,9 +9293,9 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
8995
9293
|
renderCompetitors(pdf, report);
|
|
8996
9294
|
renderQueries(pdf, report);
|
|
8997
9295
|
const bytes = await doc.save();
|
|
8998
|
-
const resolvedPath =
|
|
8999
|
-
|
|
9000
|
-
|
|
9296
|
+
const resolvedPath = path5.resolve(outputPath);
|
|
9297
|
+
fs8.mkdirSync(path5.dirname(resolvedPath), { recursive: true });
|
|
9298
|
+
fs8.writeFileSync(resolvedPath, bytes);
|
|
9001
9299
|
return resolvedPath;
|
|
9002
9300
|
}
|
|
9003
9301
|
function renderCover(pdf, report) {
|
|
@@ -9155,9 +9453,9 @@ Markdown saved: ${savedMdPath}`);
|
|
|
9155
9453
|
PDF saved: ${savedPdfPath}`);
|
|
9156
9454
|
}
|
|
9157
9455
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
9158
|
-
const resolvedPath =
|
|
9159
|
-
|
|
9160
|
-
|
|
9456
|
+
const resolvedPath = path6.resolve(outputPath);
|
|
9457
|
+
fs9.mkdirSync(path6.dirname(resolvedPath), { recursive: true });
|
|
9458
|
+
fs9.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
9161
9459
|
return resolvedPath;
|
|
9162
9460
|
}
|
|
9163
9461
|
function formatSnapshotMarkdown(report) {
|
|
@@ -9449,7 +9747,7 @@ async function showOverview(project, opts) {
|
|
|
9449
9747
|
console.log(JSON.stringify(overview, null, 2));
|
|
9450
9748
|
return;
|
|
9451
9749
|
}
|
|
9452
|
-
|
|
9750
|
+
renderHuman2(overview);
|
|
9453
9751
|
}
|
|
9454
9752
|
async function showAllOverviews(opts) {
|
|
9455
9753
|
const client = createApiClient();
|
|
@@ -9490,7 +9788,7 @@ function cell(value, width) {
|
|
|
9490
9788
|
if (value.length >= width) return `${value.slice(0, width - 1)} `;
|
|
9491
9789
|
return value.padEnd(width);
|
|
9492
9790
|
}
|
|
9493
|
-
function
|
|
9791
|
+
function renderHuman2(overview) {
|
|
9494
9792
|
const {
|
|
9495
9793
|
project: meta,
|
|
9496
9794
|
latestRun,
|
|
@@ -10140,7 +10438,7 @@ var CONTENT_CLI_COMMANDS = [
|
|
|
10140
10438
|
|
|
10141
10439
|
// src/commands/bootstrap.ts
|
|
10142
10440
|
import crypto from "crypto";
|
|
10143
|
-
import
|
|
10441
|
+
import path7 from "path";
|
|
10144
10442
|
import { eq } from "drizzle-orm";
|
|
10145
10443
|
|
|
10146
10444
|
// ../config/src/index.ts
|
|
@@ -10297,7 +10595,7 @@ async function bootstrapCommand(_opts) {
|
|
|
10297
10595
|
);
|
|
10298
10596
|
}
|
|
10299
10597
|
const configDir = getConfigDir();
|
|
10300
|
-
const databasePath = env.databasePath ||
|
|
10598
|
+
const databasePath = env.databasePath || path7.join(configDir, "data.db");
|
|
10301
10599
|
const existing = configExists();
|
|
10302
10600
|
const existingConfig = existing ? loadConfig() : void 0;
|
|
10303
10601
|
let rawApiKey;
|
|
@@ -10367,10 +10665,10 @@ async function bootstrapCommand(_opts) {
|
|
|
10367
10665
|
|
|
10368
10666
|
// src/commands/daemon.ts
|
|
10369
10667
|
import { spawn } from "child_process";
|
|
10370
|
-
import
|
|
10371
|
-
import
|
|
10668
|
+
import fs10 from "fs";
|
|
10669
|
+
import path8 from "path";
|
|
10372
10670
|
function getPidPath() {
|
|
10373
|
-
return
|
|
10671
|
+
return path8.join(getConfigDir(), "canonry.pid");
|
|
10374
10672
|
}
|
|
10375
10673
|
function isProcessAlive(pid) {
|
|
10376
10674
|
try {
|
|
@@ -10410,8 +10708,8 @@ function buildServeForwardArgs(opts) {
|
|
|
10410
10708
|
async function startDaemon(opts) {
|
|
10411
10709
|
const pidPath = getPidPath();
|
|
10412
10710
|
const format = opts.format ?? "text";
|
|
10413
|
-
if (
|
|
10414
|
-
const existingPid = parseInt(
|
|
10711
|
+
if (fs10.existsSync(pidPath)) {
|
|
10712
|
+
const existingPid = parseInt(fs10.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
10415
10713
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
10416
10714
|
throw new CliError({
|
|
10417
10715
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -10422,9 +10720,9 @@ async function startDaemon(opts) {
|
|
|
10422
10720
|
}
|
|
10423
10721
|
});
|
|
10424
10722
|
}
|
|
10425
|
-
|
|
10723
|
+
fs10.unlinkSync(pidPath);
|
|
10426
10724
|
}
|
|
10427
|
-
const cliPath =
|
|
10725
|
+
const cliPath = path8.resolve(new URL(import.meta.url).pathname);
|
|
10428
10726
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
10429
10727
|
const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
|
|
10430
10728
|
args.push(...buildServeForwardArgs(opts));
|
|
@@ -10441,10 +10739,10 @@ async function startDaemon(opts) {
|
|
|
10441
10739
|
});
|
|
10442
10740
|
}
|
|
10443
10741
|
const configDir = getConfigDir();
|
|
10444
|
-
if (!
|
|
10445
|
-
|
|
10742
|
+
if (!fs10.existsSync(configDir)) {
|
|
10743
|
+
fs10.mkdirSync(configDir, { recursive: true });
|
|
10446
10744
|
}
|
|
10447
|
-
|
|
10745
|
+
fs10.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
10448
10746
|
const port = opts.port ?? "4100";
|
|
10449
10747
|
const host = opts.host ?? "127.0.0.1";
|
|
10450
10748
|
if (!isMachineFormat(format)) {
|
|
@@ -10453,7 +10751,7 @@ async function startDaemon(opts) {
|
|
|
10453
10751
|
const ready = await waitForReady(host, port);
|
|
10454
10752
|
if (!ready) {
|
|
10455
10753
|
try {
|
|
10456
|
-
|
|
10754
|
+
fs10.unlinkSync(pidPath);
|
|
10457
10755
|
} catch {
|
|
10458
10756
|
}
|
|
10459
10757
|
throw new CliError({
|
|
@@ -10485,7 +10783,7 @@ async function startDaemon(opts) {
|
|
|
10485
10783
|
}
|
|
10486
10784
|
function stopDaemon(format = "text") {
|
|
10487
10785
|
const pidPath = getPidPath();
|
|
10488
|
-
if (!
|
|
10786
|
+
if (!fs10.existsSync(pidPath)) {
|
|
10489
10787
|
if (isMachineFormat(format)) {
|
|
10490
10788
|
console.log(JSON.stringify({
|
|
10491
10789
|
stopped: false,
|
|
@@ -10496,7 +10794,7 @@ function stopDaemon(format = "text") {
|
|
|
10496
10794
|
console.log("Canonry is not running (no PID file found)");
|
|
10497
10795
|
return;
|
|
10498
10796
|
}
|
|
10499
|
-
const pid = parseInt(
|
|
10797
|
+
const pid = parseInt(fs10.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
10500
10798
|
if (isNaN(pid)) {
|
|
10501
10799
|
if (isMachineFormat(format)) {
|
|
10502
10800
|
console.log(JSON.stringify({
|
|
@@ -10507,7 +10805,7 @@ function stopDaemon(format = "text") {
|
|
|
10507
10805
|
} else {
|
|
10508
10806
|
console.error("Invalid PID file. Removing it.");
|
|
10509
10807
|
}
|
|
10510
|
-
|
|
10808
|
+
fs10.unlinkSync(pidPath);
|
|
10511
10809
|
return;
|
|
10512
10810
|
}
|
|
10513
10811
|
if (!isProcessAlive(pid)) {
|
|
@@ -10521,12 +10819,12 @@ function stopDaemon(format = "text") {
|
|
|
10521
10819
|
} else {
|
|
10522
10820
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
10523
10821
|
}
|
|
10524
|
-
|
|
10822
|
+
fs10.unlinkSync(pidPath);
|
|
10525
10823
|
return;
|
|
10526
10824
|
}
|
|
10527
10825
|
try {
|
|
10528
10826
|
process.kill(pid, "SIGTERM");
|
|
10529
|
-
|
|
10827
|
+
fs10.unlinkSync(pidPath);
|
|
10530
10828
|
if (isMachineFormat(format)) {
|
|
10531
10829
|
console.log(JSON.stringify({
|
|
10532
10830
|
stopped: true,
|
|
@@ -10550,9 +10848,9 @@ function stopDaemon(format = "text") {
|
|
|
10550
10848
|
|
|
10551
10849
|
// src/commands/init.ts
|
|
10552
10850
|
import crypto2 from "crypto";
|
|
10553
|
-
import
|
|
10851
|
+
import fs11 from "fs";
|
|
10554
10852
|
import readline from "readline";
|
|
10555
|
-
import
|
|
10853
|
+
import path9 from "path";
|
|
10556
10854
|
function prompt(question) {
|
|
10557
10855
|
const rl = readline.createInterface({
|
|
10558
10856
|
input: process.stdin,
|
|
@@ -10573,8 +10871,8 @@ var DEFAULT_QUOTA = {
|
|
|
10573
10871
|
var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
|
|
10574
10872
|
function cwdLooksLikeProject(dir) {
|
|
10575
10873
|
const home = process.env.HOME ?? "";
|
|
10576
|
-
if (home &&
|
|
10577
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
10874
|
+
if (home && path9.resolve(dir) === path9.resolve(home)) return false;
|
|
10875
|
+
return PROJECT_MARKERS.some((marker) => fs11.existsSync(path9.join(dir, marker)));
|
|
10578
10876
|
}
|
|
10579
10877
|
var DEFAULT_AGENT_MODELS = {
|
|
10580
10878
|
anthropic: "anthropic/claude-sonnet-4-6",
|
|
@@ -10605,8 +10903,8 @@ async function initCommand(opts) {
|
|
|
10605
10903
|
return void 0;
|
|
10606
10904
|
}
|
|
10607
10905
|
const configDir = getConfigDir();
|
|
10608
|
-
if (!
|
|
10609
|
-
|
|
10906
|
+
if (!fs11.existsSync(configDir)) {
|
|
10907
|
+
fs11.mkdirSync(configDir, { recursive: true });
|
|
10610
10908
|
}
|
|
10611
10909
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
10612
10910
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -10721,7 +11019,7 @@ async function initCommand(opts) {
|
|
|
10721
11019
|
const rawApiKey = `cnry_${crypto2.randomBytes(16).toString("hex")}`;
|
|
10722
11020
|
const keyHash = crypto2.createHash("sha256").update(rawApiKey).digest("hex");
|
|
10723
11021
|
const keyPrefix = rawApiKey.slice(0, 9);
|
|
10724
|
-
const databasePath =
|
|
11022
|
+
const databasePath = path9.join(configDir, "data.db");
|
|
10725
11023
|
const db = createClient(databasePath);
|
|
10726
11024
|
migrate(db);
|
|
10727
11025
|
db.insert(apiKeys).values({
|
|
@@ -11618,7 +11916,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
|
|
|
11618
11916
|
];
|
|
11619
11917
|
|
|
11620
11918
|
// src/cli-commands/wordpress.ts
|
|
11621
|
-
import
|
|
11919
|
+
import fs12 from "fs";
|
|
11622
11920
|
|
|
11623
11921
|
// src/commands/wordpress.ts
|
|
11624
11922
|
function getClient26() {
|
|
@@ -11857,12 +12155,12 @@ async function wordpressSetMeta(project, body) {
|
|
|
11857
12155
|
printPageDetail(result);
|
|
11858
12156
|
}
|
|
11859
12157
|
async function wordpressBulkSetMeta(project, opts) {
|
|
11860
|
-
const
|
|
11861
|
-
const
|
|
11862
|
-
const filePath =
|
|
12158
|
+
const fs13 = await import("fs/promises");
|
|
12159
|
+
const path10 = await import("path");
|
|
12160
|
+
const filePath = path10.resolve(opts.from);
|
|
11863
12161
|
let raw;
|
|
11864
12162
|
try {
|
|
11865
|
-
raw = await
|
|
12163
|
+
raw = await fs13.readFile(filePath, "utf8");
|
|
11866
12164
|
} catch {
|
|
11867
12165
|
throw new CliError({
|
|
11868
12166
|
code: "FILE_READ_ERROR",
|
|
@@ -11959,13 +12257,13 @@ async function wordpressSetSchema(project, body) {
|
|
|
11959
12257
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
11960
12258
|
}
|
|
11961
12259
|
async function wordpressSchemaDeploy(project, opts) {
|
|
11962
|
-
const
|
|
11963
|
-
const
|
|
12260
|
+
const fs13 = await import("fs/promises");
|
|
12261
|
+
const path10 = await import("path");
|
|
11964
12262
|
const yaml = await loadYamlModule();
|
|
11965
|
-
const filePath =
|
|
12263
|
+
const filePath = path10.resolve(opts.profile);
|
|
11966
12264
|
let raw;
|
|
11967
12265
|
try {
|
|
11968
|
-
raw = await
|
|
12266
|
+
raw = await fs13.readFile(filePath, "utf8");
|
|
11969
12267
|
} catch {
|
|
11970
12268
|
throw new CliError({
|
|
11971
12269
|
code: "FILE_READ_ERROR",
|
|
@@ -12070,13 +12368,13 @@ async function wordpressOnboard(project, opts) {
|
|
|
12070
12368
|
}
|
|
12071
12369
|
let profileData;
|
|
12072
12370
|
if (opts.profile) {
|
|
12073
|
-
const
|
|
12074
|
-
const
|
|
12371
|
+
const fs13 = await import("fs/promises");
|
|
12372
|
+
const path10 = await import("path");
|
|
12075
12373
|
const yaml = await loadYamlModule();
|
|
12076
|
-
const filePath =
|
|
12374
|
+
const filePath = path10.resolve(opts.profile);
|
|
12077
12375
|
let raw;
|
|
12078
12376
|
try {
|
|
12079
|
-
raw = await
|
|
12377
|
+
raw = await fs13.readFile(filePath, "utf8");
|
|
12080
12378
|
} catch {
|
|
12081
12379
|
throw new CliError({
|
|
12082
12380
|
code: "FILE_READ_ERROR",
|
|
@@ -12225,7 +12523,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
12225
12523
|
}
|
|
12226
12524
|
if (contentFile) {
|
|
12227
12525
|
try {
|
|
12228
|
-
return
|
|
12526
|
+
return fs12.readFileSync(contentFile, "utf-8");
|
|
12229
12527
|
} catch (error) {
|
|
12230
12528
|
const message = error instanceof Error ? error.message : String(error);
|
|
12231
12529
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|