@ainyc/canonry 4.109.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.
Files changed (27) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +1 -1
  2. package/assets/assets/{BacklinksPage-D48kAAiT.js → BacklinksPage-Ccp5dJm2.js} +1 -1
  3. package/assets/assets/ChartPrimitives-DZI_FVyX.js +1 -0
  4. package/assets/assets/ProjectPage-feeXXGgl.js +7 -0
  5. package/assets/assets/{RunRow-DQy-Gy9t.js → RunRow-CPf7aV1o.js} +1 -1
  6. package/assets/assets/{RunsPage-DRRG4uZS.js → RunsPage-CI8AcUal.js} +1 -1
  7. package/assets/assets/{SettingsPage-Pf0B9gMT.js → SettingsPage-QI2X5EIb.js} +1 -1
  8. package/assets/assets/{TrafficPage-Cd2OL96L.js → TrafficPage-CcELR6n1.js} +1 -1
  9. package/assets/assets/{TrafficSourceDetailPage-CiyttCo2.js → TrafficSourceDetailPage-C-9rc4ly.js} +1 -1
  10. package/assets/assets/{arrow-left-DaIR4jsx.js → arrow-left-3WT6TImA.js} +1 -1
  11. package/assets/assets/{extract-error-message-HqopXrW4.js → extract-error-message-43ehRbIG.js} +1 -1
  12. package/assets/assets/{index-CthlUeHu.js → index-BpnaXO_X.js} +65 -65
  13. package/assets/assets/index-JD5rv_sY.css +1 -0
  14. package/assets/assets/{trash-2-DUel-9g8.js → trash-2-Dk-RvBpF.js} +1 -1
  15. package/assets/index.html +2 -2
  16. package/dist/{chunk-YEOLQT5S.js → chunk-4TQOZJPF.js} +39 -19
  17. package/dist/{chunk-3HKBUYIY.js → chunk-CVXBE3ST.js} +44 -1
  18. package/dist/{chunk-QZQLZL3C.js → chunk-Y26GYDS6.js} +2 -1
  19. package/dist/{chunk-WXAHSQOX.js → chunk-ZT7GVLS3.js} +18 -0
  20. package/dist/cli.js +409 -106
  21. package/dist/index.js +4 -4
  22. package/dist/{intelligence-service-NXZXNM7T.js → intelligence-service-4MQUT3OO.js} +2 -2
  23. package/dist/mcp.js +2 -2
  24. package/package.json +8 -8
  25. package/assets/assets/ChartPrimitives-CLSeu1W4.js +0 -1
  26. package/assets/assets/ProjectPage-D20d2kjG.js +0 -7
  27. 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-YEOLQT5S.js";
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-QZQLZL3C.js";
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-3HKBUYIY.js";
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-WXAHSQOX.js";
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, path9) {
130
- if (args.length < path9.length) return false;
131
- return path9.every((segment, index) => args[index] === segment);
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 } : {};
@@ -1656,6 +1656,7 @@ function buildRunBody(opts, icpDescription) {
1656
1656
  const body = {};
1657
1657
  if (icpDescription) body.icpDescription = icpDescription;
1658
1658
  if (opts.buyer !== void 0 && opts.buyer.trim() !== "") body.buyerDescription = opts.buyer;
1659
+ if (opts.seedProviders && opts.seedProviders.length > 0) body.seedProviders = opts.seedProviders;
1659
1660
  if (opts.dedupThreshold !== void 0) body.dedupThreshold = opts.dedupThreshold;
1660
1661
  if (opts.maxProbes !== void 0) body.maxProbes = opts.maxProbes;
1661
1662
  if (opts.probeConcurrency !== void 0) body.probeConcurrency = opts.probeConcurrency;
@@ -1972,6 +1973,272 @@ async function pollSession(client, project, sessionId, quiet = false) {
1972
1973
  }
1973
1974
  }
1974
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
+
1975
2242
  // src/cli-commands/discover.ts
1976
2243
  function parseFloatOption(values, key, usage) {
1977
2244
  const raw = values[key];
@@ -2058,10 +2325,11 @@ Usage: ${usage}`,
2058
2325
  var DISCOVER_CLI_COMMANDS = [
2059
2326
  {
2060
2327
  path: ["discover", "run"],
2061
- usage: 'canonry discover run <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
2328
+ usage: 'canonry discover run <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]',
2062
2329
  options: {
2063
2330
  icp: stringOption(),
2064
2331
  buyer: stringOption(),
2332
+ "seed-provider": multiStringOption(),
2065
2333
  "icp-angle": multiStringOption(),
2066
2334
  locations: multiStringOption(),
2067
2335
  "dedup-threshold": stringOption(),
@@ -2070,11 +2338,12 @@ var DISCOVER_CLI_COMMANDS = [
2070
2338
  wait: { type: "boolean", default: false }
2071
2339
  },
2072
2340
  run: async (input) => {
2073
- const usage = 'canonry discover run <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]';
2341
+ const usage = 'canonry discover run <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]';
2074
2342
  const project = requireProject(input, "discover.run", usage);
2075
2343
  await discoverRun(project, {
2076
2344
  icp: getString(input.values, "icp"),
2077
2345
  buyer: getString(input.values, "buyer"),
2346
+ seedProviders: getStringArray(input.values, "seed-provider"),
2078
2347
  icpAngles: getStringArray(input.values, "icp-angle"),
2079
2348
  locations: parseLocationsOption(input.values),
2080
2349
  dedupThreshold: parseFloatOption(input.values, "dedup-threshold", usage),
@@ -2093,12 +2362,45 @@ var DISCOVER_CLI_COMMANDS = [
2093
2362
  });
2094
2363
  }
2095
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
+ },
2096
2397
  {
2097
2398
  path: ["discover", "seed"],
2098
- usage: 'canonry discover seed <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
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]',
2099
2400
  options: {
2100
2401
  icp: stringOption(),
2101
2402
  buyer: stringOption(),
2403
+ "seed-provider": multiStringOption(),
2102
2404
  "icp-angle": multiStringOption(),
2103
2405
  locations: multiStringOption(),
2104
2406
  "dedup-threshold": stringOption(),
@@ -2107,11 +2409,12 @@ var DISCOVER_CLI_COMMANDS = [
2107
2409
  wait: { type: "boolean", default: false }
2108
2410
  },
2109
2411
  run: async (input) => {
2110
- const usage = 'canonry discover seed <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]';
2412
+ const 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]';
2111
2413
  const project = requireProject(input, "discover.seed", usage);
2112
2414
  await discoverSeed(project, {
2113
2415
  icp: getString(input.values, "icp"),
2114
2416
  buyer: getString(input.values, "buyer"),
2417
+ seedProviders: getStringArray(input.values, "seed-provider"),
2115
2418
  icpAngles: getStringArray(input.values, "icp-angle"),
2116
2419
  locations: parseLocationsOption(input.values),
2117
2420
  dedupThreshold: parseFloatOption(input.values, "dedup-threshold", usage),
@@ -2645,9 +2948,9 @@ async function gaConnect(project, opts) {
2645
2948
  propertyId: opts.propertyId
2646
2949
  };
2647
2950
  if (opts.keyFile) {
2648
- const fs12 = await import("fs");
2951
+ const fs13 = await import("fs");
2649
2952
  try {
2650
- const content = fs12.readFileSync(opts.keyFile, "utf-8");
2953
+ const content = fs13.readFileSync(opts.keyFile, "utf-8");
2651
2954
  JSON.parse(content);
2652
2955
  body.keyJson = content;
2653
2956
  } catch (e) {
@@ -3855,9 +4158,9 @@ async function getCommand(opts) {
3855
4158
  console.log(JSON.stringify(leaf, null, 2));
3856
4159
  }
3857
4160
  }
3858
- function walkPath(value, path9) {
3859
- if (!path9 || path9 === ".") return value;
3860
- const segments = path9.split(".").flatMap((part) => {
4161
+ function walkPath(value, path10) {
4162
+ if (!path10 || path10 === ".") return value;
4163
+ const segments = path10.split(".").flatMap((part) => {
3861
4164
  const tokens = [];
3862
4165
  let i = 0;
3863
4166
  const bracketStart = part.indexOf("[");
@@ -3905,13 +4208,13 @@ var GET_CLI_COMMANDS = [
3905
4208
  },
3906
4209
  run: async (input) => {
3907
4210
  const project = requireProject(input, "get", USAGE2);
3908
- const path9 = requirePositional(input, 1, {
4211
+ const path10 = requirePositional(input, 1, {
3909
4212
  command: "get",
3910
4213
  usage: USAGE2,
3911
4214
  message: 'path is required (e.g. "scores.mentionShare.value")'
3912
4215
  });
3913
4216
  const from = getString(input.values, "from");
3914
- await getCommand({ project, path: path9, from, format: input.format });
4217
+ await getCommand({ project, path: path10, from, format: input.format });
3915
4218
  }
3916
4219
  }
3917
4220
  ];
@@ -3950,9 +4253,9 @@ async function trafficConnectWordpress(project, opts) {
3950
4253
  }
3951
4254
  let applicationPassword = opts.appPassword?.trim() ?? "";
3952
4255
  if (!applicationPassword && opts.appPasswordFile) {
3953
- const fs12 = await import("fs");
4256
+ const fs13 = await import("fs");
3954
4257
  try {
3955
- applicationPassword = fs12.readFileSync(opts.appPasswordFile, "utf-8").trim();
4258
+ applicationPassword = fs13.readFileSync(opts.appPasswordFile, "utf-8").trim();
3956
4259
  } catch (e) {
3957
4260
  const msg = e instanceof Error ? e.message : String(e);
3958
4261
  throw new CliError({
@@ -4008,10 +4311,10 @@ async function trafficConnectCloudRun(project, opts) {
4008
4311
  details: { project }
4009
4312
  });
4010
4313
  }
4011
- const fs12 = await import("fs");
4314
+ const fs13 = await import("fs");
4012
4315
  let keyJson;
4013
4316
  try {
4014
- keyJson = fs12.readFileSync(opts.serviceAccountKey, "utf-8");
4317
+ keyJson = fs13.readFileSync(opts.serviceAccountKey, "utf-8");
4015
4318
  JSON.parse(keyJson);
4016
4319
  } catch (e) {
4017
4320
  const msg = e instanceof Error ? e.message : String(e);
@@ -4071,9 +4374,9 @@ async function trafficConnectVercel(project, opts) {
4071
4374
  }
4072
4375
  let token = opts.token?.trim() ?? "";
4073
4376
  if (!token && opts.tokenFile) {
4074
- const fs12 = await import("fs");
4377
+ const fs13 = await import("fs");
4075
4378
  try {
4076
- token = fs12.readFileSync(opts.tokenFile, "utf-8").trim();
4379
+ token = fs13.readFileSync(opts.tokenFile, "utf-8").trim();
4077
4380
  } catch (e) {
4078
4381
  const msg = e instanceof Error ? e.message : String(e);
4079
4382
  throw new CliError({
@@ -5887,7 +6190,7 @@ var KEYS_CLI_COMMANDS = [
5887
6190
  ];
5888
6191
 
5889
6192
  // src/commands/keyword.ts
5890
- import fs2 from "fs";
6193
+ import fs3 from "fs";
5891
6194
  function getClient12() {
5892
6195
  return createApiClient();
5893
6196
  }
@@ -5955,7 +6258,7 @@ async function listKeywords(project, format) {
5955
6258
  }
5956
6259
  }
5957
6260
  async function importKeywords(project, filePath, format) {
5958
- if (!fs2.existsSync(filePath)) {
6261
+ if (!fs3.existsSync(filePath)) {
5959
6262
  throw new CliError({
5960
6263
  code: "KEYWORD_IMPORT_FILE_NOT_FOUND",
5961
6264
  message: `File not found: ${filePath}`,
@@ -5966,7 +6269,7 @@ async function importKeywords(project, filePath, format) {
5966
6269
  }
5967
6270
  });
5968
6271
  }
5969
- const content = fs2.readFileSync(filePath, "utf-8");
6272
+ const content = fs3.readFileSync(filePath, "utf-8");
5970
6273
  const keywords = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
5971
6274
  if (keywords.length === 0) {
5972
6275
  if (isMachineFormat(format)) {
@@ -6167,7 +6470,7 @@ var KEYWORD_CLI_COMMANDS = [
6167
6470
  ];
6168
6471
 
6169
6472
  // src/commands/query.ts
6170
- import fs3 from "fs";
6473
+ import fs4 from "fs";
6171
6474
  function getClient13() {
6172
6475
  return createApiClient();
6173
6476
  }
@@ -6258,7 +6561,7 @@ async function listQueries(project, format) {
6258
6561
  }
6259
6562
  }
6260
6563
  async function importQueries(project, filePath, format) {
6261
- if (!fs3.existsSync(filePath)) {
6564
+ if (!fs4.existsSync(filePath)) {
6262
6565
  throw new CliError({
6263
6566
  code: "QUERY_IMPORT_FILE_NOT_FOUND",
6264
6567
  message: `File not found: ${filePath}`,
@@ -6269,7 +6572,7 @@ async function importQueries(project, filePath, format) {
6269
6572
  }
6270
6573
  });
6271
6574
  }
6272
- const content = fs3.readFileSync(filePath, "utf-8");
6575
+ const content = fs4.readFileSync(filePath, "utf-8");
6273
6576
  const queries2 = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
6274
6577
  if (queries2.length === 0) {
6275
6578
  if (isMachineFormat(format)) {
@@ -6471,16 +6774,16 @@ var QUERY_CLI_COMMANDS = [
6471
6774
  ];
6472
6775
 
6473
6776
  // src/commands/mcp.ts
6474
- import fs4 from "fs";
6475
- import path2 from "path";
6777
+ import fs5 from "fs";
6778
+ import path3 from "path";
6476
6779
  import { createRequire } from "module";
6477
6780
 
6478
6781
  // src/mcp-clients.ts
6479
6782
  import os from "os";
6480
- import path from "path";
6783
+ import path2 from "path";
6481
6784
  var CLAUDE_DESKTOP_CONFIG_FILENAME = "claude_desktop_config.json";
6482
6785
  function homeRelative(...segments) {
6483
- return path.join(os.homedir(), ...segments);
6786
+ return path2.join(os.homedir(), ...segments);
6484
6787
  }
6485
6788
  function claudeDesktopConfigPath() {
6486
6789
  switch (process.platform) {
@@ -6488,7 +6791,7 @@ function claudeDesktopConfigPath() {
6488
6791
  return homeRelative("Library", "Application Support", "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
6489
6792
  case "win32": {
6490
6793
  const appData = process.env.APPDATA ?? homeRelative("AppData", "Roaming");
6491
- return path.join(appData, "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
6794
+ return path2.join(appData, "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
6492
6795
  }
6493
6796
  default:
6494
6797
  return homeRelative(".config", "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
@@ -6501,7 +6804,7 @@ function codexConfigPath() {
6501
6804
  return homeRelative(".codex", "config.toml");
6502
6805
  }
6503
6806
  function claudeCodeProjectConfigPath() {
6504
- return path.join(process.cwd(), ".mcp.json");
6807
+ return path2.join(process.cwd(), ".mcp.json");
6505
6808
  }
6506
6809
  var SUPPORTED_MCP_CLIENTS = [
6507
6810
  {
@@ -6544,7 +6847,7 @@ function listMcpClientIds() {
6544
6847
  var _require = createRequire(import.meta.url);
6545
6848
  function resolveCanonryMcpBin() {
6546
6849
  const packageJsonPath = _require.resolve("../package.json");
6547
- const packageRoot = path2.dirname(packageJsonPath);
6850
+ const packageRoot = path3.dirname(packageJsonPath);
6548
6851
  const pkg = _require("../package.json");
6549
6852
  const relativeBin = pkg.bin?.["canonry-mcp"];
6550
6853
  if (!relativeBin) {
@@ -6554,7 +6857,7 @@ function resolveCanonryMcpBin() {
6554
6857
  exitCode: 2
6555
6858
  });
6556
6859
  }
6557
- return path2.resolve(packageRoot, relativeBin);
6860
+ return path3.resolve(packageRoot, relativeBin);
6558
6861
  }
6559
6862
  function buildEntry(opts) {
6560
6863
  const target = opts.binPath ?? resolveCanonryMcpBin();
@@ -6587,8 +6890,8 @@ function renderClientSnippet(client, serverName, entry) {
6587
6890
  return renderJsonSnippet(serverName, entry, client.format);
6588
6891
  }
6589
6892
  function readJsonConfig(configPath) {
6590
- if (!fs4.existsSync(configPath)) return {};
6591
- const raw = fs4.readFileSync(configPath, "utf-8").trim();
6893
+ if (!fs5.existsSync(configPath)) return {};
6894
+ const raw = fs5.readFileSync(configPath, "utf-8").trim();
6592
6895
  if (!raw) return {};
6593
6896
  try {
6594
6897
  const parsed = JSON.parse(raw);
@@ -6606,14 +6909,14 @@ function readJsonConfig(configPath) {
6606
6909
  }
6607
6910
  }
6608
6911
  function writeJsonConfig(configPath, value) {
6609
- fs4.mkdirSync(path2.dirname(configPath), { recursive: true });
6610
- fs4.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
6912
+ fs5.mkdirSync(path3.dirname(configPath), { recursive: true });
6913
+ fs5.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
6611
6914
  `, "utf-8");
6612
6915
  }
6613
6916
  function backupConfigIfPresent(configPath) {
6614
- if (!fs4.existsSync(configPath)) return void 0;
6917
+ if (!fs5.existsSync(configPath)) return void 0;
6615
6918
  const backupPath = `${configPath}.canonry.bak`;
6616
- fs4.copyFileSync(configPath, backupPath);
6919
+ fs5.copyFileSync(configPath, backupPath);
6617
6920
  return backupPath;
6618
6921
  }
6619
6922
  function findClientOrThrow(id) {
@@ -6967,13 +7270,13 @@ var NOTIFY_CLI_COMMANDS = [
6967
7270
  ];
6968
7271
 
6969
7272
  // src/commands/apply.ts
6970
- import fs5 from "fs";
7273
+ import fs6 from "fs";
6971
7274
  import { parseAllDocuments } from "yaml";
6972
7275
  async function applyConfigFile(filePath) {
6973
- if (!fs5.existsSync(filePath)) {
7276
+ if (!fs6.existsSync(filePath)) {
6974
7277
  throw new Error(`File not found: ${filePath}`);
6975
7278
  }
6976
- const content = fs5.readFileSync(filePath, "utf-8");
7279
+ const content = fs6.readFileSync(filePath, "utf-8");
6977
7280
  const docs = parseAllDocuments(content);
6978
7281
  const client = createApiClient();
6979
7282
  const errors = [];
@@ -7888,11 +8191,11 @@ var PROJECT_CLI_COMMANDS = [
7888
8191
  ];
7889
8192
 
7890
8193
  // src/commands/report.ts
7891
- import fs6 from "fs";
7892
- import path3 from "path";
8194
+ import fs7 from "fs";
8195
+ import path4 from "path";
7893
8196
  function defaultOutputPath(project, audience) {
7894
8197
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7895
- return path3.resolve(process.cwd(), `canonry-report-${project}-${audience}-${date}.html`);
8198
+ return path4.resolve(process.cwd(), `canonry-report-${project}-${audience}-${date}.html`);
7896
8199
  }
7897
8200
  async function runReportCommand(project, opts = {}) {
7898
8201
  const client = createApiClient();
@@ -7903,12 +8206,12 @@ async function runReportCommand(project, opts = {}) {
7903
8206
  return;
7904
8207
  }
7905
8208
  const html = renderReportHtml(report, { audience });
7906
- const targetPath = opts.output ? path3.resolve(opts.output) : defaultOutputPath(project, audience);
7907
- const dir = path3.dirname(targetPath);
7908
- if (!fs6.existsSync(dir)) {
7909
- fs6.mkdirSync(dir, { recursive: true });
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 });
7910
8213
  }
7911
- fs6.writeFileSync(targetPath, html, "utf-8");
8214
+ fs7.writeFileSync(targetPath, html, "utf-8");
7912
8215
  console.log(`Report written to ${targetPath}`);
7913
8216
  }
7914
8217
 
@@ -8773,12 +9076,12 @@ var SKILLS_CLI_COMMANDS = [
8773
9076
  ];
8774
9077
 
8775
9078
  // src/commands/snapshot.ts
8776
- import fs8 from "fs";
8777
- import path5 from "path";
9079
+ import fs9 from "fs";
9080
+ import path6 from "path";
8778
9081
 
8779
9082
  // src/snapshot-pdf.ts
8780
- import fs7 from "fs";
8781
- import path4 from "path";
9083
+ import fs8 from "fs";
9084
+ import path5 from "path";
8782
9085
  import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
8783
9086
  var PAGE_WIDTH = 612;
8784
9087
  var PAGE_HEIGHT = 792;
@@ -8990,9 +9293,9 @@ async function writeSnapshotPdf(report, outputPath) {
8990
9293
  renderCompetitors(pdf, report);
8991
9294
  renderQueries(pdf, report);
8992
9295
  const bytes = await doc.save();
8993
- const resolvedPath = path4.resolve(outputPath);
8994
- fs7.mkdirSync(path4.dirname(resolvedPath), { recursive: true });
8995
- fs7.writeFileSync(resolvedPath, bytes);
9296
+ const resolvedPath = path5.resolve(outputPath);
9297
+ fs8.mkdirSync(path5.dirname(resolvedPath), { recursive: true });
9298
+ fs8.writeFileSync(resolvedPath, bytes);
8996
9299
  return resolvedPath;
8997
9300
  }
8998
9301
  function renderCover(pdf, report) {
@@ -9150,9 +9453,9 @@ Markdown saved: ${savedMdPath}`);
9150
9453
  PDF saved: ${savedPdfPath}`);
9151
9454
  }
9152
9455
  function writeSnapshotMarkdown(report, outputPath) {
9153
- const resolvedPath = path5.resolve(outputPath);
9154
- fs8.mkdirSync(path5.dirname(resolvedPath), { recursive: true });
9155
- fs8.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
9456
+ const resolvedPath = path6.resolve(outputPath);
9457
+ fs9.mkdirSync(path6.dirname(resolvedPath), { recursive: true });
9458
+ fs9.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
9156
9459
  return resolvedPath;
9157
9460
  }
9158
9461
  function formatSnapshotMarkdown(report) {
@@ -9444,7 +9747,7 @@ async function showOverview(project, opts) {
9444
9747
  console.log(JSON.stringify(overview, null, 2));
9445
9748
  return;
9446
9749
  }
9447
- renderHuman(overview);
9750
+ renderHuman2(overview);
9448
9751
  }
9449
9752
  async function showAllOverviews(opts) {
9450
9753
  const client = createApiClient();
@@ -9485,7 +9788,7 @@ function cell(value, width) {
9485
9788
  if (value.length >= width) return `${value.slice(0, width - 1)} `;
9486
9789
  return value.padEnd(width);
9487
9790
  }
9488
- function renderHuman(overview) {
9791
+ function renderHuman2(overview) {
9489
9792
  const {
9490
9793
  project: meta,
9491
9794
  latestRun,
@@ -10135,7 +10438,7 @@ var CONTENT_CLI_COMMANDS = [
10135
10438
 
10136
10439
  // src/commands/bootstrap.ts
10137
10440
  import crypto from "crypto";
10138
- import path6 from "path";
10441
+ import path7 from "path";
10139
10442
  import { eq } from "drizzle-orm";
10140
10443
 
10141
10444
  // ../config/src/index.ts
@@ -10292,7 +10595,7 @@ async function bootstrapCommand(_opts) {
10292
10595
  );
10293
10596
  }
10294
10597
  const configDir = getConfigDir();
10295
- const databasePath = env.databasePath || path6.join(configDir, "data.db");
10598
+ const databasePath = env.databasePath || path7.join(configDir, "data.db");
10296
10599
  const existing = configExists();
10297
10600
  const existingConfig = existing ? loadConfig() : void 0;
10298
10601
  let rawApiKey;
@@ -10362,10 +10665,10 @@ async function bootstrapCommand(_opts) {
10362
10665
 
10363
10666
  // src/commands/daemon.ts
10364
10667
  import { spawn } from "child_process";
10365
- import fs9 from "fs";
10366
- import path7 from "path";
10668
+ import fs10 from "fs";
10669
+ import path8 from "path";
10367
10670
  function getPidPath() {
10368
- return path7.join(getConfigDir(), "canonry.pid");
10671
+ return path8.join(getConfigDir(), "canonry.pid");
10369
10672
  }
10370
10673
  function isProcessAlive(pid) {
10371
10674
  try {
@@ -10405,8 +10708,8 @@ function buildServeForwardArgs(opts) {
10405
10708
  async function startDaemon(opts) {
10406
10709
  const pidPath = getPidPath();
10407
10710
  const format = opts.format ?? "text";
10408
- if (fs9.existsSync(pidPath)) {
10409
- const existingPid = parseInt(fs9.readFileSync(pidPath, "utf-8").trim(), 10);
10711
+ if (fs10.existsSync(pidPath)) {
10712
+ const existingPid = parseInt(fs10.readFileSync(pidPath, "utf-8").trim(), 10);
10410
10713
  if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
10411
10714
  throw new CliError({
10412
10715
  code: "DAEMON_ALREADY_RUNNING",
@@ -10417,9 +10720,9 @@ async function startDaemon(opts) {
10417
10720
  }
10418
10721
  });
10419
10722
  }
10420
- fs9.unlinkSync(pidPath);
10723
+ fs10.unlinkSync(pidPath);
10421
10724
  }
10422
- const cliPath = path7.resolve(new URL(import.meta.url).pathname);
10725
+ const cliPath = path8.resolve(new URL(import.meta.url).pathname);
10423
10726
  const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
10424
10727
  const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
10425
10728
  args.push(...buildServeForwardArgs(opts));
@@ -10436,10 +10739,10 @@ async function startDaemon(opts) {
10436
10739
  });
10437
10740
  }
10438
10741
  const configDir = getConfigDir();
10439
- if (!fs9.existsSync(configDir)) {
10440
- fs9.mkdirSync(configDir, { recursive: true });
10742
+ if (!fs10.existsSync(configDir)) {
10743
+ fs10.mkdirSync(configDir, { recursive: true });
10441
10744
  }
10442
- fs9.writeFileSync(pidPath, String(child.pid), "utf-8");
10745
+ fs10.writeFileSync(pidPath, String(child.pid), "utf-8");
10443
10746
  const port = opts.port ?? "4100";
10444
10747
  const host = opts.host ?? "127.0.0.1";
10445
10748
  if (!isMachineFormat(format)) {
@@ -10448,7 +10751,7 @@ async function startDaemon(opts) {
10448
10751
  const ready = await waitForReady(host, port);
10449
10752
  if (!ready) {
10450
10753
  try {
10451
- fs9.unlinkSync(pidPath);
10754
+ fs10.unlinkSync(pidPath);
10452
10755
  } catch {
10453
10756
  }
10454
10757
  throw new CliError({
@@ -10480,7 +10783,7 @@ async function startDaemon(opts) {
10480
10783
  }
10481
10784
  function stopDaemon(format = "text") {
10482
10785
  const pidPath = getPidPath();
10483
- if (!fs9.existsSync(pidPath)) {
10786
+ if (!fs10.existsSync(pidPath)) {
10484
10787
  if (isMachineFormat(format)) {
10485
10788
  console.log(JSON.stringify({
10486
10789
  stopped: false,
@@ -10491,7 +10794,7 @@ function stopDaemon(format = "text") {
10491
10794
  console.log("Canonry is not running (no PID file found)");
10492
10795
  return;
10493
10796
  }
10494
- const pid = parseInt(fs9.readFileSync(pidPath, "utf-8").trim(), 10);
10797
+ const pid = parseInt(fs10.readFileSync(pidPath, "utf-8").trim(), 10);
10495
10798
  if (isNaN(pid)) {
10496
10799
  if (isMachineFormat(format)) {
10497
10800
  console.log(JSON.stringify({
@@ -10502,7 +10805,7 @@ function stopDaemon(format = "text") {
10502
10805
  } else {
10503
10806
  console.error("Invalid PID file. Removing it.");
10504
10807
  }
10505
- fs9.unlinkSync(pidPath);
10808
+ fs10.unlinkSync(pidPath);
10506
10809
  return;
10507
10810
  }
10508
10811
  if (!isProcessAlive(pid)) {
@@ -10516,12 +10819,12 @@ function stopDaemon(format = "text") {
10516
10819
  } else {
10517
10820
  console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
10518
10821
  }
10519
- fs9.unlinkSync(pidPath);
10822
+ fs10.unlinkSync(pidPath);
10520
10823
  return;
10521
10824
  }
10522
10825
  try {
10523
10826
  process.kill(pid, "SIGTERM");
10524
- fs9.unlinkSync(pidPath);
10827
+ fs10.unlinkSync(pidPath);
10525
10828
  if (isMachineFormat(format)) {
10526
10829
  console.log(JSON.stringify({
10527
10830
  stopped: true,
@@ -10545,9 +10848,9 @@ function stopDaemon(format = "text") {
10545
10848
 
10546
10849
  // src/commands/init.ts
10547
10850
  import crypto2 from "crypto";
10548
- import fs10 from "fs";
10851
+ import fs11 from "fs";
10549
10852
  import readline from "readline";
10550
- import path8 from "path";
10853
+ import path9 from "path";
10551
10854
  function prompt(question) {
10552
10855
  const rl = readline.createInterface({
10553
10856
  input: process.stdin,
@@ -10568,8 +10871,8 @@ var DEFAULT_QUOTA = {
10568
10871
  var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
10569
10872
  function cwdLooksLikeProject(dir) {
10570
10873
  const home = process.env.HOME ?? "";
10571
- if (home && path8.resolve(dir) === path8.resolve(home)) return false;
10572
- return PROJECT_MARKERS.some((marker) => fs10.existsSync(path8.join(dir, marker)));
10874
+ if (home && path9.resolve(dir) === path9.resolve(home)) return false;
10875
+ return PROJECT_MARKERS.some((marker) => fs11.existsSync(path9.join(dir, marker)));
10573
10876
  }
10574
10877
  var DEFAULT_AGENT_MODELS = {
10575
10878
  anthropic: "anthropic/claude-sonnet-4-6",
@@ -10600,8 +10903,8 @@ async function initCommand(opts) {
10600
10903
  return void 0;
10601
10904
  }
10602
10905
  const configDir = getConfigDir();
10603
- if (!fs10.existsSync(configDir)) {
10604
- fs10.mkdirSync(configDir, { recursive: true });
10906
+ if (!fs11.existsSync(configDir)) {
10907
+ fs11.mkdirSync(configDir, { recursive: true });
10605
10908
  }
10606
10909
  const bootstrapEnv = getBootstrapEnv(process.env, {
10607
10910
  GEMINI_API_KEY: opts?.geminiKey,
@@ -10716,7 +11019,7 @@ async function initCommand(opts) {
10716
11019
  const rawApiKey = `cnry_${crypto2.randomBytes(16).toString("hex")}`;
10717
11020
  const keyHash = crypto2.createHash("sha256").update(rawApiKey).digest("hex");
10718
11021
  const keyPrefix = rawApiKey.slice(0, 9);
10719
- const databasePath = path8.join(configDir, "data.db");
11022
+ const databasePath = path9.join(configDir, "data.db");
10720
11023
  const db = createClient(databasePath);
10721
11024
  migrate(db);
10722
11025
  db.insert(apiKeys).values({
@@ -11613,7 +11916,7 @@ var VISIBILITY_STATS_CLI_COMMANDS = [
11613
11916
  ];
11614
11917
 
11615
11918
  // src/cli-commands/wordpress.ts
11616
- import fs11 from "fs";
11919
+ import fs12 from "fs";
11617
11920
 
11618
11921
  // src/commands/wordpress.ts
11619
11922
  function getClient26() {
@@ -11852,12 +12155,12 @@ async function wordpressSetMeta(project, body) {
11852
12155
  printPageDetail(result);
11853
12156
  }
11854
12157
  async function wordpressBulkSetMeta(project, opts) {
11855
- const fs12 = await import("fs/promises");
11856
- const path9 = await import("path");
11857
- const filePath = path9.resolve(opts.from);
12158
+ const fs13 = await import("fs/promises");
12159
+ const path10 = await import("path");
12160
+ const filePath = path10.resolve(opts.from);
11858
12161
  let raw;
11859
12162
  try {
11860
- raw = await fs12.readFile(filePath, "utf8");
12163
+ raw = await fs13.readFile(filePath, "utf8");
11861
12164
  } catch {
11862
12165
  throw new CliError({
11863
12166
  code: "FILE_READ_ERROR",
@@ -11954,13 +12257,13 @@ async function wordpressSetSchema(project, body) {
11954
12257
  printManualAssist(`Schema update for "${body.slug}"`, result);
11955
12258
  }
11956
12259
  async function wordpressSchemaDeploy(project, opts) {
11957
- const fs12 = await import("fs/promises");
11958
- const path9 = await import("path");
12260
+ const fs13 = await import("fs/promises");
12261
+ const path10 = await import("path");
11959
12262
  const yaml = await loadYamlModule();
11960
- const filePath = path9.resolve(opts.profile);
12263
+ const filePath = path10.resolve(opts.profile);
11961
12264
  let raw;
11962
12265
  try {
11963
- raw = await fs12.readFile(filePath, "utf8");
12266
+ raw = await fs13.readFile(filePath, "utf8");
11964
12267
  } catch {
11965
12268
  throw new CliError({
11966
12269
  code: "FILE_READ_ERROR",
@@ -12065,13 +12368,13 @@ async function wordpressOnboard(project, opts) {
12065
12368
  }
12066
12369
  let profileData;
12067
12370
  if (opts.profile) {
12068
- const fs12 = await import("fs/promises");
12069
- const path9 = await import("path");
12371
+ const fs13 = await import("fs/promises");
12372
+ const path10 = await import("path");
12070
12373
  const yaml = await loadYamlModule();
12071
- const filePath = path9.resolve(opts.profile);
12374
+ const filePath = path10.resolve(opts.profile);
12072
12375
  let raw;
12073
12376
  try {
12074
- raw = await fs12.readFile(filePath, "utf8");
12377
+ raw = await fs13.readFile(filePath, "utf8");
12075
12378
  } catch {
12076
12379
  throw new CliError({
12077
12380
  code: "FILE_READ_ERROR",
@@ -12220,7 +12523,7 @@ function resolveContent(input, command, usage, options) {
12220
12523
  }
12221
12524
  if (contentFile) {
12222
12525
  try {
12223
- return fs11.readFileSync(contentFile, "utf-8");
12526
+ return fs12.readFileSync(contentFile, "utf-8");
12224
12527
  } catch (error) {
12225
12528
  const message = error instanceof Error ? error.message : String(error);
12226
12529
  throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {