@ainyc/canonry 4.28.0 → 4.29.1

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/index.html CHANGED
@@ -12,7 +12,7 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index--jYjUA0o.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-DC2S5T9p.js"></script>
16
16
  <link rel="stylesheet" crossorigin href="./assets/index-BnALDZI7.css">
17
17
  </head>
18
18
  <body>
package/dist/cli.js CHANGED
@@ -1965,30 +1965,120 @@ var TERMINAL_DISCOVERY_STATUSES = /* @__PURE__ */ new Set([
1965
1965
  function getClient4() {
1966
1966
  return createApiClient();
1967
1967
  }
1968
- async function discoverRun(project, opts) {
1969
- const client = getClient4();
1968
+ function buildRunBody(opts, icpDescription) {
1970
1969
  const body = {};
1971
- if (opts.icp) body.icpDescription = opts.icp;
1970
+ if (icpDescription) body.icpDescription = icpDescription;
1972
1971
  if (opts.dedupThreshold !== void 0) body.dedupThreshold = opts.dedupThreshold;
1973
1972
  if (opts.maxProbes !== void 0) body.maxProbes = opts.maxProbes;
1974
- const start = await client.triggerDiscoveryRun(project, body);
1973
+ return body;
1974
+ }
1975
+ function resolveIcpAngles(opts) {
1976
+ const angles = (opts.icpAngles ?? []).map((a) => a.trim()).filter((a) => a.length > 0);
1977
+ if (angles.length > 0) return { angles, multiAngle: true };
1978
+ const icp = opts.icp?.trim();
1979
+ if (icp) return { angles: [icp], multiAngle: false };
1980
+ return { angles: [void 0], multiAngle: false };
1981
+ }
1982
+ function summarizeAngles(sessions) {
1983
+ return {
1984
+ angleCount: sessions.length,
1985
+ totalProbes: sessions.reduce((sum, s) => sum + (s.probeCount ?? 0), 0),
1986
+ totalCited: sessions.reduce((sum, s) => sum + (s.citedCount ?? 0), 0),
1987
+ totalWasted: sessions.reduce((sum, s) => sum + (s.wastedCount ?? 0), 0),
1988
+ totalAspirational: sessions.reduce((sum, s) => sum + (s.aspirationalCount ?? 0), 0)
1989
+ };
1990
+ }
1991
+ function errorMessage(err) {
1992
+ return err instanceof Error ? err.message : String(err);
1993
+ }
1994
+ async function discoverRun(project, opts) {
1995
+ const client = getClient4();
1996
+ const { angles, multiAngle } = resolveIcpAngles(opts);
1997
+ const runs2 = [];
1998
+ for (const angle of angles) {
1999
+ try {
2000
+ const start = await client.triggerDiscoveryRun(project, buildRunBody(opts, angle));
2001
+ runs2.push({ angle, start });
2002
+ } catch (err) {
2003
+ if (runs2.length > 0) {
2004
+ process.stderr.write(
2005
+ `
2006
+ Failed to start ${angle ? `angle "${angle}"` : "discovery run"}: ${errorMessage(err)}
2007
+ Sessions already started (recover with \`canonry discover show ${project} <id>\`):
2008
+ ` + runs2.map((r) => ` ${r.start.sessionId}`).join("\n") + "\n"
2009
+ );
2010
+ }
2011
+ throw err;
2012
+ }
2013
+ }
1975
2014
  if (!opts.wait) {
1976
2015
  if (opts.format === "json") {
1977
- console.log(JSON.stringify(start, null, 2));
2016
+ console.log(JSON.stringify(multiAngle ? runs2.map((r) => r.start) : runs2[0].start, null, 2));
1978
2017
  return;
1979
2018
  }
1980
- console.log(`Discovery run started: ${start.runId}`);
1981
- console.log(` Session: ${start.sessionId}`);
1982
- console.log(` Status: ${start.status}`);
1983
- console.log(` Tail: canonry discover show ${project} ${start.sessionId}`);
2019
+ for (const { angle, start } of runs2) {
2020
+ if (angle) console.log(`[${angle}]`);
2021
+ console.log(`Discovery run started: ${start.runId}`);
2022
+ console.log(` Session: ${start.sessionId}`);
2023
+ console.log(` Status: ${start.status}`);
2024
+ console.log(` Tail: canonry discover show ${project} ${start.sessionId}`);
2025
+ if (runs2.length > 1) console.log();
2026
+ }
1984
2027
  return;
1985
2028
  }
1986
- const final = await pollSession(client, project, start.sessionId);
1987
- if (opts.format === "json") {
1988
- console.log(JSON.stringify(final, null, 2));
1989
- return;
2029
+ const parallel = runs2.length > 1;
2030
+ if (parallel) process.stderr.write(`Waiting for ${runs2.length} discovery sessions...
2031
+ `);
2032
+ const settled = await Promise.allSettled(
2033
+ runs2.map((r) => pollSession(client, project, r.start.sessionId, parallel))
2034
+ );
2035
+ const results = [];
2036
+ const failures = [];
2037
+ settled.forEach((outcome, i) => {
2038
+ const run = runs2[i];
2039
+ if (outcome.status === "fulfilled") {
2040
+ results.push({ angle: run.angle, session: outcome.value });
2041
+ } else {
2042
+ failures.push({ angle: run.angle, sessionId: run.start.sessionId, reason: outcome.reason });
2043
+ }
2044
+ });
2045
+ if (results.length > 0) {
2046
+ if (opts.format === "json") {
2047
+ console.log(JSON.stringify(multiAngle ? results.map((r) => r.session) : results[0].session, null, 2));
2048
+ } else {
2049
+ for (const { angle, session } of results) {
2050
+ if (angle) console.log(`## ICP angle: ${angle}
2051
+ `);
2052
+ printSessionDetail(session);
2053
+ if (results.length > 1) console.log();
2054
+ }
2055
+ if (results.length > 1) {
2056
+ const summary = summarizeAngles(results.map((r) => r.session));
2057
+ console.log(`\u2500\u2500 Summary across ${summary.angleCount} angle(s) \u2500\u2500`);
2058
+ console.log(
2059
+ ` Probes: ${summary.totalProbes} Cited: ${summary.totalCited} Wasted: ${summary.totalWasted} Aspirational: ${summary.totalAspirational}`
2060
+ );
2061
+ console.log("\n Promote each session:");
2062
+ for (const { session } of results) {
2063
+ console.log(` canonry discover promote ${project} ${session.id}`);
2064
+ }
2065
+ }
2066
+ }
2067
+ }
2068
+ if (failures.length > 0) {
2069
+ if (!multiAngle) throw failures[0].reason;
2070
+ for (const f of failures) {
2071
+ process.stderr.write(
2072
+ `Discovery session ${f.sessionId}${f.angle ? ` ("${f.angle}")` : ""} did not complete: ${errorMessage(f.reason)}
2073
+ `
2074
+ );
2075
+ }
2076
+ throw new CliError({
2077
+ code: "DISCOVERY_INCOMPLETE",
2078
+ message: `${failures.length} of ${runs2.length} discovery session(s) did not complete`,
2079
+ details: { failed: failures.map((f) => f.sessionId) }
2080
+ });
1990
2081
  }
1991
- printSessionDetail(final);
1992
2082
  }
1993
2083
  async function discoverSeed(project, opts) {
1994
2084
  await discoverRun(project, opts);
@@ -2110,8 +2200,8 @@ function printSessionDetail(session) {
2110
2200
  }
2111
2201
  var POLL_INTERVAL_MS = 3e3;
2112
2202
  var POLL_TIMEOUT_MS = 15 * 60 * 1e3;
2113
- async function pollSession(client, project, sessionId) {
2114
- process.stderr.write(`Waiting for discovery session ${sessionId}`);
2203
+ async function pollSession(client, project, sessionId, quiet = false) {
2204
+ if (!quiet) process.stderr.write(`Waiting for discovery session ${sessionId}`);
2115
2205
  const deadline = Date.now() + POLL_TIMEOUT_MS;
2116
2206
  for (; ; ) {
2117
2207
  await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
@@ -2122,9 +2212,9 @@ async function pollSession(client, project, sessionId) {
2122
2212
  });
2123
2213
  }
2124
2214
  const session = await client.getDiscoverySession(project, sessionId);
2125
- process.stderr.write(".");
2215
+ if (!quiet) process.stderr.write(".");
2126
2216
  if (TERMINAL_DISCOVERY_STATUSES.has(session.status)) {
2127
- process.stderr.write("\n");
2217
+ if (!quiet) process.stderr.write("\n");
2128
2218
  return session;
2129
2219
  }
2130
2220
  }
@@ -2178,22 +2268,20 @@ Usage: ${usage}`,
2178
2268
  var DISCOVER_CLI_COMMANDS = [
2179
2269
  {
2180
2270
  path: ["discover", "run"],
2181
- usage: 'canonry discover run <project> [--icp "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]',
2271
+ usage: 'canonry discover run <project> [--icp "..."] [--icp-angle "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]',
2182
2272
  options: {
2183
2273
  icp: stringOption(),
2274
+ "icp-angle": multiStringOption(),
2184
2275
  "dedup-threshold": stringOption(),
2185
2276
  "max-probes": stringOption(),
2186
2277
  wait: { type: "boolean", default: false }
2187
2278
  },
2188
2279
  run: async (input) => {
2189
- const project = requireProject(
2190
- input,
2191
- "discover.run",
2192
- 'canonry discover run <project> [--icp "..."] [--wait] [--format json]'
2193
- );
2194
- const usage = 'canonry discover run <project> [--icp "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]';
2280
+ const usage = 'canonry discover run <project> [--icp "..."] [--icp-angle "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]';
2281
+ const project = requireProject(input, "discover.run", usage);
2195
2282
  await discoverRun(project, {
2196
2283
  icp: getString(input.values, "icp"),
2284
+ icpAngles: getStringArray(input.values, "icp-angle"),
2197
2285
  dedupThreshold: parseFloatOption(input.values, "dedup-threshold", usage),
2198
2286
  maxProbes: parseIntegerOption(input, "max-probes", {
2199
2287
  command: "discover.run",
@@ -2207,22 +2295,20 @@ var DISCOVER_CLI_COMMANDS = [
2207
2295
  },
2208
2296
  {
2209
2297
  path: ["discover", "seed"],
2210
- usage: 'canonry discover seed <project> [--icp "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]',
2298
+ usage: 'canonry discover seed <project> [--icp "..."] [--icp-angle "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]',
2211
2299
  options: {
2212
2300
  icp: stringOption(),
2301
+ "icp-angle": multiStringOption(),
2213
2302
  "dedup-threshold": stringOption(),
2214
2303
  "max-probes": stringOption(),
2215
2304
  wait: { type: "boolean", default: false }
2216
2305
  },
2217
2306
  run: async (input) => {
2218
- const project = requireProject(
2219
- input,
2220
- "discover.seed",
2221
- 'canonry discover seed <project> [--icp "..."] [--wait] [--format json]'
2222
- );
2223
- const usage = 'canonry discover seed <project> [--icp "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]';
2307
+ const usage = 'canonry discover seed <project> [--icp "..."] [--icp-angle "..."] [--dedup-threshold 0.85] [--max-probes 100] [--wait] [--format json]';
2308
+ const project = requireProject(input, "discover.seed", usage);
2224
2309
  await discoverSeed(project, {
2225
2310
  icp: getString(input.values, "icp"),
2311
+ icpAngles: getStringArray(input.values, "icp-angle"),
2226
2312
  dedupThreshold: parseFloatOption(input.values, "dedup-threshold", usage),
2227
2313
  maxProbes: parseIntegerOption(input, "max-probes", {
2228
2314
  command: "discover.seed",
@@ -3279,11 +3365,11 @@ async function trafficBackfill(project, opts) {
3279
3365
  console.log(`Inspect rebuilt rollups: canonry traffic events ${project} --source ${opts.source} --since-minutes ${submitted.daysApplied * 24 * 60}`);
3280
3366
  return;
3281
3367
  }
3282
- const errorMessage = final.error?.message ?? null;
3368
+ const errorMessage2 = final.error?.message ?? null;
3283
3369
  throw new CliError({
3284
3370
  code: "TRAFFIC_BACKFILL_FAILED",
3285
- message: errorMessage ?? "backfill run did not complete successfully",
3286
- displayMessage: `Error: backfill run ${final.id} ${final.status}${errorMessage ? ` \u2014 ${errorMessage}` : ""}`,
3371
+ message: errorMessage2 ?? "backfill run did not complete successfully",
3372
+ displayMessage: `Error: backfill run ${final.id} ${final.status}${errorMessage2 ? ` \u2014 ${errorMessage2}` : ""}`,
3287
3373
  details: { project, runId: final.id, status: final.status }
3288
3374
  });
3289
3375
  }
@@ -7212,7 +7298,7 @@ Usage: canonry settings provider ${name} --api-key <key> [--model <model>] [--ma
7212
7298
  import fs7 from "fs";
7213
7299
  import path4 from "path";
7214
7300
  import { fileURLToPath } from "url";
7215
- var BUNDLED_SKILL_NAMES = ["canonry-setup", "aero"];
7301
+ var BUNDLED_SKILL_NAMES = ["canonry", "aero"];
7216
7302
  function resolveBundledSkillsRoot(pkgDir) {
7217
7303
  const here = pkgDir ?? path4.dirname(fileURLToPath(import.meta.url));
7218
7304
  const candidates = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.28.0",
3
+ "version": "4.29.1",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -59,23 +59,23 @@
59
59
  "@types/node-cron": "^3.0.11",
60
60
  "tsup": "^8.5.1",
61
61
  "tsx": "^4.19.0",
62
- "@ainyc/canonry-api-routes": "0.0.0",
63
62
  "@ainyc/canonry-config": "0.0.0",
64
- "@ainyc/canonry-db": "0.0.0",
65
- "@ainyc/canonry-integration-bing": "0.0.0",
66
63
  "@ainyc/canonry-contracts": "0.0.0",
67
- "@ainyc/canonry-intelligence": "0.0.0",
64
+ "@ainyc/canonry-api-routes": "0.0.0",
65
+ "@ainyc/canonry-db": "0.0.0",
68
66
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
67
+ "@ainyc/canonry-intelligence": "0.0.0",
68
+ "@ainyc/canonry-integration-bing": "0.0.0",
69
69
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
70
70
  "@ainyc/canonry-integration-google": "0.0.0",
71
71
  "@ainyc/canonry-integration-traffic": "0.0.0",
72
72
  "@ainyc/canonry-integration-wordpress": "0.0.0",
73
+ "@ainyc/canonry-provider-claude": "0.0.0",
73
74
  "@ainyc/canonry-provider-cdp": "0.0.0",
74
75
  "@ainyc/canonry-provider-gemini": "0.0.0",
75
- "@ainyc/canonry-provider-claude": "0.0.0",
76
- "@ainyc/canonry-provider-openai": "0.0.0",
76
+ "@ainyc/canonry-provider-local": "0.0.0",
77
77
  "@ainyc/canonry-provider-perplexity": "0.0.0",
78
- "@ainyc/canonry-provider-local": "0.0.0"
78
+ "@ainyc/canonry-provider-openai": "0.0.0"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",