@ainyc/canonry 4.190.1 → 4.192.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/SKILL.md +124 -216
- package/assets/assets/{AuditHistoryPanel-Dob_85ay.js → AuditHistoryPanel-C7MwfCl9.js} +1 -1
- package/assets/assets/{BacklinksPage-BDm4gQsa.js → BacklinksPage-1Nq1zbRk.js} +1 -1
- package/assets/assets/{ChartPrimitives-DLEICrrL.js → ChartPrimitives-Bxa_vFmq.js} +1 -1
- package/assets/assets/{HistoryPage-BUGJKNWJ.js → HistoryPage-BNACyEiz.js} +1 -1
- package/assets/assets/MeasurementPropertyPage-BqjpIYAw.js +1 -0
- package/assets/assets/ProjectPage-BhBzznlv.js +8 -0
- package/assets/assets/{RunRow-Cja3vahD.js → RunRow-DINPo5ES.js} +1 -1
- package/assets/assets/{RunsPage-BdVfLW9Z.js → RunsPage-BFuDLm7p.js} +1 -1
- package/assets/assets/{SettingsPage-Xw9rdDPd.js → SettingsPage-CkqmyTSK.js} +1 -1
- package/assets/assets/SiteHealthSection-DzFKj9lX.js +4 -0
- package/assets/assets/{TrafficPage-D5ZqJrJm.js → TrafficPage-CkIGVLET.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DB5V8cdH.js → TrafficSourceDetailPage-CTmn_FmZ.js} +1 -1
- package/assets/assets/{extract-error-message-lzuarNEg.js → extract-error-message-CC2kxd3e.js} +1 -1
- package/assets/assets/{index-BjjM151x.css → index-BtTEcbcB.css} +1 -1
- package/assets/assets/{index-YVHujfy1.js → index-CCPMPGar.js} +26 -26
- package/assets/assets/{react-sigma_core.esm.min-Ddu-c40B.js → react-sigma_core.esm.min-DkpQa1sf.js} +1 -1
- package/assets/assets/{vendor-lucide-dNHw1I5G.js → vendor-lucide-CW2qe0uH.js} +1 -1
- package/assets/assets/{vendor-markdown-9tTeP8v7.js → vendor-markdown-B-Oq2NYq.js} +1 -1
- package/assets/assets/{vendor-radix-BpmvLvpp.js → vendor-radix-twS1M3FF.js} +1 -1
- package/assets/assets/{vendor-recharts-FA0uySU7.js → vendor-recharts-D-cUuLZo.js} +1 -1
- package/assets/assets/{vendor-tanstack-CYBjbqVr.js → vendor-tanstack-ZXXkndVj.js} +1 -1
- package/assets/index.html +7 -7
- package/dist/{chunk-2II4ZMMH.js → chunk-32Q2NZ4S.js} +2 -2
- package/dist/{chunk-32QBVRMN.js → chunk-36RKISAI.js} +213 -32
- package/dist/{chunk-ROPJUNQN.js → chunk-BULKBROE.js} +1368 -1223
- package/dist/{chunk-ECPN4OUR.js → chunk-FTKZAOFD.js} +649 -249
- package/dist/{chunk-BE366UCM.js → chunk-JOSSB4QC.js} +73 -22
- package/dist/cli.js +65 -10
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-QCKX2W4G.js → intelligence-service-MEQ5VX5L.js} +2 -2
- package/dist/mcp.js +13 -8
- package/package.json +11 -11
- package/assets/assets/MeasurementPropertyPage-H2g4VdcA.js +0 -1
- package/assets/assets/ProjectPage-d7iOSkrd.js +0 -8
- package/assets/assets/SiteHealthSection-CjioXMWy.js +0 -4
|
@@ -1,220 +1,128 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: canonry
|
|
3
|
-
description: "
|
|
4
|
-
compatibility: Requires Node.js 22.14+ and globally installed @canonry/canonry; canonry-mcp must be on PATH.
|
|
5
|
-
metadata:
|
|
6
|
-
agent: >-
|
|
7
|
-
{"emoji":"📡","requires":{"bins":["canonry"]},"install":[{"id":"npm","kind":"npm","package":"@canonry/canonry","bins":["canonry"],"label":"Install canonry globally","command":"npm install -g @canonry/canonry"}]}
|
|
3
|
+
description: "Navigate Canonry through connected MCP tools or the `cnry` CLI to inspect evidence, diagnose changes, plan measurement, review integrations, and report results. Use this optional host-native skill for CLI workflows and detailed references; connected MCP users can operate through canonry_help without installing a local runtime or skill."
|
|
8
4
|
---
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
## Google Ads and GTM
|
|
135
|
-
|
|
136
|
-
Google Ads and GTM are separate, project-scoped sources for one conversion
|
|
137
|
-
contract. Provider snapshots are static configuration evidence. They do not
|
|
138
|
-
prove browser events, tag firing, or recorded conversions. Stored snapshots are
|
|
139
|
-
the safe default. A bounded live read needs `google-marketing.read-live`. Version
|
|
140
|
-
1 does not mutate Google Ads or edit, version, or publish GTM. Read
|
|
141
|
-
`references/google-marketing.md` before assessing or refreshing this evidence.
|
|
142
|
-
The operator must complete OAuth, resource selection, and contract creation.
|
|
143
|
-
Never request OAuth credentials or a Google Ads developer token.
|
|
144
|
-
|
|
145
|
-
## Server-Side Traffic
|
|
146
|
-
|
|
147
|
-
When the project ships behind a server you control, connect Cloud Run, WordPress,
|
|
148
|
-
or Vercel. `cnry traffic sync` pulls and classifies their logs into hourly
|
|
149
|
-
buckets. For Cloudflare, choose `direct-push` or `queue-pull` on the local,
|
|
150
|
-
credential-owning host. Direct push requires a public Canonry HTTPS receiver.
|
|
151
|
-
It does not use `traffic sync`. Queue pull sends events to a Cloudflare Queue,
|
|
152
|
-
then Canonry drains it through `traffic sync` and the `traffic-sync` schedule.
|
|
153
|
-
|
|
154
|
-
If the connect response reports `activationRequired`, attach the Worker route
|
|
155
|
-
first. Then run `cnry traffic activate <project> --source <id>`. Activation
|
|
156
|
-
pauses all sibling sources. It also moves the one `traffic-sync` schedule to
|
|
157
|
-
Queue pull. A first source becomes active automatically.
|
|
158
|
-
|
|
159
|
-
Each default Queue tick drains at most 1,000 messages. Use `cnry traffic status`
|
|
160
|
-
and the `traffic.source.queue-backlog` doctor check to read the backlog. If more
|
|
161
|
-
than 1,000 messages remain, get approval before a manual sync or a shorter
|
|
162
|
-
schedule interval. Use `cnry traffic events`, `cnry traffic sources`, and
|
|
163
|
-
`cnry traffic status` for every adapter. See
|
|
164
|
-
`references/server-side-traffic.md` for setup and smoke tests.
|
|
165
|
-
|
|
166
|
-
**WordPress safety:** incremental pulls are fixed `[since, until)` windows; a
|
|
167
|
-
new or idle source begins at the plugin's 365-day maximum retention horizon.
|
|
168
|
-
Canonry rejects an endpoint that returns events outside that window. Keep
|
|
169
|
-
existing WordPress rollups intact: generic replace-mode backfill is unavailable
|
|
170
|
-
until a retention-aware repair can prove coverage and declare any unrecoverable
|
|
171
|
-
span.
|
|
172
|
-
|
|
173
|
-
**Vercel gotcha:** a freshly connected Vercel source captures only going-forward traffic — `lastSyncedAt` is seeded to NOW to avoid the 30-day default window exceeding Vercel's ~14-day request-logs retention (which would otherwise throw on every first sync). Use `cnry traffic backfill <project> --source <id> --days N` for historical recovery. If an idle Vercel/Cloud Run source has been failing long enough that `lastSyncedAt` aged past retention, unstick it with `cnry traffic reset <project> --source <id> --advance-to-now`.
|
|
174
|
-
|
|
175
|
-
## Local AEO (Google Business Profile)
|
|
176
|
-
|
|
177
|
-
For businesses with a physical location or service area, Google Business Profile is the local-AEO signal source — reviews, search-keyword impressions, daily performance metrics, and (for hotels) structured amenities + booking CTAs all feed how AI engines answer local-intent queries. Connect with `cnry gbp connect <project>`, discover locations with `cnry gbp locations discover <project>`, and pick which sync with `cnry gbp locations select/deselect`.
|
|
178
|
-
|
|
179
|
-
**Hard prerequisites and gotchas — read `references/google-business-profile.md` before attempting setup:** GBP requires a Google access-form approval (0 QPM until granted), the only OAuth scope is the write-capable `business.manage`, **reviews live on a separately-gated legacy v4 API that the Basic approval does NOT grant** (and can't be self-enabled), and the **Q&A API was retired (2025-11-03)**. Keyword data is heavily privacy-redacted (often 100% for small businesses); an empty place-action profile is a real AEO finding to surface, but an empty lodging result is a verify-not-a-gap (the Lodging API can return 0 readable groups even when the owner-facing "Hotel details" panel has amenities set). The reference doc has the full setup walkthrough, the real-world data shapes, and the troubleshooting matrix.
|
|
180
|
-
|
|
181
|
-
## Built-in Analyst (Aero)
|
|
182
|
-
|
|
183
|
-
Canonry ships a built-in agent — Aero — for users who don't already have one. Drive it from the CLI:
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
cnry agent ask <project> "what changed since the last sweep?"
|
|
187
|
-
cnry agent ask <project> "..." --provider claude --scope read-only
|
|
188
|
-
cnry agent memory list <project> # durable project notes
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Aero also wakes unprompted after every `run.completed` so insights and regressions get analyzed without a user click. Users who already run their own agent (Claude Code, Codex, custom) wire webhooks instead: `cnry agent attach <project> --url <webhook-url>` subscribes to `run.completed`, `insight.critical`, `insight.high`, `citation.gained`.
|
|
192
|
-
|
|
193
|
-
## Boundaries & Safety
|
|
194
|
-
|
|
195
|
-
- **Get explicit approval before every mutation or quota-consuming sweep.** Also get approval before each live provider read. Stored reads and `--dry-run` previews are safe defaults.
|
|
196
|
-
- **Never touch live WordPress without explicit approval**
|
|
197
|
-
- **Back up `~/.canonry/config.yaml` before any config edit**
|
|
198
|
-
- **Never fabricate mention or citation data** — if a sweep hasn't run, say so; never coerce `answerMentioned` null → false (null = "not checked")
|
|
199
|
-
- **Client data stays private** — canonry repo is public; no real domains in issues
|
|
200
|
-
- **Respect API rate limits** — batch operations, avoid tight loops
|
|
201
|
-
- **Keep Google marketing read-only in v1** — stored evidence is the default.
|
|
202
|
-
`google-marketing.read-live` permits bounded provider reads only. It grants no
|
|
203
|
-
Google Ads mutation or GTM edit or publish authority.
|
|
204
|
-
|
|
205
|
-
## References
|
|
206
|
-
|
|
207
|
-
| File | Read when |
|
|
208
|
-
|---|---|
|
|
209
|
-
| `references/canonry-cli.md` | Looking up specific canonry commands, flags, or JSON return shapes |
|
|
210
|
-
| `references/aeo-analysis.md` | Interpreting sweep output, diagnosing regressions, planning content fixes |
|
|
211
|
-
| `references/indexing.md` | Submitting URLs, checking GSC/Bing coverage, fixing indexing gaps |
|
|
212
|
-
| `references/wordpress-integration.md` | Connecting to WordPress, editing pages, pushing staging → live |
|
|
213
|
-
| `references/server-side-traffic.md` | Wiring server-side evidence from Cloudflare, Cloud Run, WordPress, and Vercel. Connect, inspect, sync pull sources, and troubleshoot. |
|
|
214
|
-
| `references/google-business-profile.md` | Connecting Google Business Profile for local AEO: access-form approval, GCP API enablement, the v4-reviews access gate, hotel lodging/place-action signals, data shapes, troubleshooting. |
|
|
215
|
-
| `references/google-marketing.md` | Inspecting first-class Google Ads and GTM evidence. Covers the conversion-integrity chain, static and runtime truth, live-read scope, v1 read-only boundary, and future write approvals. |
|
|
216
|
-
|
|
217
|
-
---
|
|
218
|
-
|
|
219
|
-
**Tools:** canonry v4+, @canonry/aeo-audit@4
|
|
220
|
-
**Website:** [canonry.ai](https://canonry.ai) | **Org:** [ainyc.ai](https://ainyc.ai) | **Reference:** [AINYC AEO Methodology](https://ainyc.ai/aeo-methodology)
|
|
6
|
+
<!-- Generated from docs/agent-operations/v1.md by pnpm guide:sync. Do not edit. -->
|
|
7
|
+
|
|
8
|
+
# Canonry Operations Guide v1
|
|
9
|
+
|
|
10
|
+
Canonry is an agent-first AI visibility platform. MCP is the universal entry
|
|
11
|
+
point for connected agents. Host-native skills are optional upgrades, not a
|
|
12
|
+
prerequisite or a permission mechanism.
|
|
13
|
+
|
|
14
|
+
## Connect and choose a route
|
|
15
|
+
|
|
16
|
+
Read the initialization guidance, then call `canonry_help` with an `intent`:
|
|
17
|
+
`status`, `diagnose`, `measurement`, `integrations`, `reports`, or a short task
|
|
18
|
+
description. Select an accessible project with `canonry_projects_list` before
|
|
19
|
+
using its exact name in project tools. Inspect each listed tool's input schema;
|
|
20
|
+
help suggests tool names, not invented arguments or authorization.
|
|
21
|
+
|
|
22
|
+
Help returns a versioned, compact route: connection `mode`, available `next`
|
|
23
|
+
tools, workflow guidance, approval boundaries, and this guide's URL. It performs
|
|
24
|
+
no provider calls, reads no project data, and changes no permissions.
|
|
25
|
+
`includeCatalog: true` additionally returns toolkit details when needed.
|
|
26
|
+
|
|
27
|
+
Hosted connections use a fixed catalog. Help only suggests tools offered by that
|
|
28
|
+
connection; it never tells a hosted agent to dynamically load a toolkit. A
|
|
29
|
+
progressive local stdio connection may return `loadToolkits`: call
|
|
30
|
+
`canonry_load_toolkit` with one returned name, await it, then call help again.
|
|
31
|
+
Loading only changes local tool discovery, never server authority.
|
|
32
|
+
|
|
33
|
+
The optional `canonry://agent-operations/v1` MCP resource contains this same
|
|
34
|
+
guide. If the host cannot read resources or open links, continue through help.
|
|
35
|
+
Do not install a plugin, local runtime, or skill merely to use connected MCP.
|
|
36
|
+
An installed Codex or Claude Canonry skill contains a generated copy of this
|
|
37
|
+
guide plus links to host-native references. It does not replace runtime help.
|
|
38
|
+
|
|
39
|
+
## Vocabulary and evidence
|
|
40
|
+
|
|
41
|
+
- **Mentioned** means the brand appears in answer text. **Cited** means its
|
|
42
|
+
domain appears in source links. Either, both, or neither can occur; never
|
|
43
|
+
compute one signal from the other.
|
|
44
|
+
- `answerMentioned: null` means not checked, not false. Missing runs and empty
|
|
45
|
+
populations mean no measurement, not zero visibility.
|
|
46
|
+
- Preserve project, time window, provider, requested/served model, location,
|
|
47
|
+
sample size, and query class when comparing evidence. Use server-returned
|
|
48
|
+
metrics; do not invent a score from incompatible populations.
|
|
49
|
+
- Simple projects and Advanced portfolios share the workflow. For Advanced
|
|
50
|
+
results, preserve Property, Target, market, plan revision, and class scope.
|
|
51
|
+
Groups organize navigation; do not infer an unrequested fan-out.
|
|
52
|
+
- Research is isolated evidence, not tracked measurement. A probe still spends
|
|
53
|
+
quota and persists evidence but is excluded from normal tracking metrics.
|
|
54
|
+
|
|
55
|
+
## Workflows
|
|
56
|
+
|
|
57
|
+
**Status:** read the stored overview and freshness first. Say when evidence is
|
|
58
|
+
missing instead of silently creating it.
|
|
59
|
+
|
|
60
|
+
**Diagnose:** inspect stored history and comparable evidence. Explain what
|
|
61
|
+
changed separately from why it might have changed. A hypothesis is not a
|
|
62
|
+
measured cause. Propose bounded verification if stored evidence is insufficient.
|
|
63
|
+
|
|
64
|
+
**Measurement:** inspect the existing setup and results before proposing edits.
|
|
65
|
+
Keep research, query tracking, plan publication, and sweep execution separate.
|
|
66
|
+
For direct research, submit the final editable query text in one context. For a
|
|
67
|
+
reviewed batch, submit each explicit destination with its final text and one
|
|
68
|
+
idempotency key. Pattern substitution happens in the client before either
|
|
69
|
+
request; choosing a market or Property records a destination only and never
|
|
70
|
+
rewrites a query or creates an automatic fan-out. `research.run` does not
|
|
71
|
+
authorize saving patterns, changing tracking, publishing plans, or settings.
|
|
72
|
+
Use a supported preview where available, inspect its exact destination and
|
|
73
|
+
revision, then seek approval for the actual change. A preview may itself require
|
|
74
|
+
write permission; never treat a dry-run flag as a universal safety guarantee.
|
|
75
|
+
|
|
76
|
+
**Integrations:** inspect stored connection state and snapshot freshness first.
|
|
77
|
+
Provider configuration evidence does not prove a browser event fired or a
|
|
78
|
+
conversion was recorded. Connection, resource selection, refresh/sync, and live
|
|
79
|
+
reads are separate actions. Credentials belong in the operator's secure setup
|
|
80
|
+
flow, never in chat, tool arguments, reports, or public guidance.
|
|
81
|
+
|
|
82
|
+
**Reports:** use saved evidence for the requested period and scope. Keep mention
|
|
83
|
+
and citation signals separate, include dates and sample sizes, and state missing
|
|
84
|
+
or stale inputs. Preparing a report does not authorize new measurement.
|
|
85
|
+
|
|
86
|
+
## Authority and approval
|
|
87
|
+
|
|
88
|
+
Start with stored evidence. Before a live provider read, sweep, probe, research
|
|
89
|
+
run, sync, write, or externally visible action, obtain approval covering its
|
|
90
|
+
exact target, action, and bounded work. Approval already given for that exact
|
|
91
|
+
operation need not be asked for again, but does not extend to more projects,
|
|
92
|
+
larger batches, retries with new identities, or recurring work.
|
|
93
|
+
|
|
94
|
+
HTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost
|
|
95
|
+
or permission. Provider discovery, account reads, and live diagnostics may
|
|
96
|
+
consume quota even when labeled read-only. If the tool's effect is unclear,
|
|
97
|
+
inspect its description and request direction before calling it.
|
|
98
|
+
|
|
99
|
+
Authentication, role/scope checks, project restrictions, quotas, and guarded
|
|
100
|
+
approval receipts are enforced by the server. Help, skills, resources, and tool
|
|
101
|
+
visibility cannot grant authority. Never change credentials, endpoints, or
|
|
102
|
+
project identifiers to work around a missing tool or a `403` response.
|
|
103
|
+
|
|
104
|
+
For guarded ads writes, inspect unresolved operation receipts before retrying.
|
|
105
|
+
Use the receipt's supported recovery action; do not replay a mutation under a
|
|
106
|
+
new identity. An executor cannot create or widen its own human approval grant.
|
|
107
|
+
On ambiguous results, exhausted bounds, or refusal, stop and report what is
|
|
108
|
+
known and what permission or operator action is needed.
|
|
109
|
+
|
|
110
|
+
## Version and source
|
|
111
|
+
|
|
112
|
+
This public, versioned document is the source for initialization guidance,
|
|
113
|
+
intent routes, the optional resource, and generated Canonry `SKILL.md` files.
|
|
114
|
+
Guide v1 may receive compatible clarifications; incompatible routing contracts
|
|
115
|
+
require a new guide version. The running server's help describes its actual
|
|
116
|
+
catalog and remains usable without fetching this document.
|
|
117
|
+
|
|
118
|
+
## Optional host-native references
|
|
119
|
+
|
|
120
|
+
Read only references relevant to the requested task. They are not required for MCP operation.
|
|
121
|
+
|
|
122
|
+
- [CLI commands and JSON return shapes](references/canonry-cli.md)
|
|
123
|
+
- [Interpreting stored evidence and regressions](references/aeo-analysis.md)
|
|
124
|
+
- [Indexing workflow after inspection and approval](references/indexing.md)
|
|
125
|
+
- [Approved WordPress workflow](references/wordpress-integration.md)
|
|
126
|
+
- [Server-side traffic setup and diagnosis](references/server-side-traffic.md)
|
|
127
|
+
- [Google Business Profile prerequisites](references/google-business-profile.md)
|
|
128
|
+
- [Google Ads and GTM evidence boundaries](references/google-marketing.md)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as a,u as h,j as e}from"./vendor-tanstack-
|
|
1
|
+
import{r as a,u as h,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{db as L,dc as P,ck as E,i as u,B as x,f as v,T as k}from"./index-CCPMPGar.js";const o=100;function M(s){if(s==="all")return;const n=Number.parseInt(s,10);return new Date(Date.now()-n*24*60*60*1e3).toISOString()}function O(s){const n=s.userAgent?.toLowerCase()??"";return n.includes("canonry-mcp")?"MCP":n.includes("canonry-cli")?"CLI":n.includes("mozilla/")?"Dashboard":s.actor==="scheduler"?"Scheduler":s.actor==="agent"?"Agent":s.actor==="mcp"?"MCP":s.actor==="cli"?"CLI":s.actor}function B(s){return/delete|remove|revoke|disconnect|failed/.test(s)?"negative":/create|add|connect|completed/.test(s)?"positive":/update|replace|sync|apply/.test(s)?"caution":"neutral"}function D(s){return[s.action,s.actor,s.entityType,s.entityId,s.actorSession,s.userAgent,s.diff==null?"":JSON.stringify(s.diff)].filter(Boolean).join(" ").toLowerCase()}function H({projectName:s}){const[n,l]=a.useState(0),[c,y]=a.useState("90d"),[m,N]=a.useState(""),[p,w]=a.useState(""),S=a.useMemo(()=>M(c),[c]),g={limit:o,offset:n*o,since:S,actor:m||void 0},C=h({...L({client:u,path:{name:s??""},query:g}),enabled:!!s}),A=h({...P({client:u,query:g}),enabled:!s}),f=h({...E({client:u}),enabled:!s}),i=s?C:A,r=i.data??[],I=a.useMemo(()=>new Map((f.data??[]).map(t=>[t.id,t.displayName||t.name])),[f.data]),d=p.trim().toLowerCase(),j=a.useMemo(()=>d?r.filter(t=>D(t).includes(d)):r,[r,d]),b=t=>{l(0),t()};return i.isLoading?e.jsx("p",{className:"supporting-copy mt-6",role:"status",children:"Loading change history…"}):e.jsxs("section",{className:"mt-6","aria-labelledby":"change-history-heading",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Audit trail"}),e.jsx("h2",{id:"change-history-heading",children:"Change history"}),e.jsx("p",{className:"supporting-copy mt-1 max-w-2xl",children:"Configuration and operator actions. Execution outcomes remain in Runs."})]}),e.jsx(x,{type:"button",variant:"outline",size:"sm",onClick:()=>{i.refetch()},disabled:i.isFetching,children:i.isFetching?"Refreshing…":"Refresh"})]}),e.jsxs("div",{className:"mt-4 grid gap-2 sm:grid-cols-3",children:[e.jsx("input",{type:"search","aria-label":"Search change history",value:p,onChange:t=>w(t.target.value),placeholder:"Search actions, entities, or details",className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong placeholder-mono-600 focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600"}),e.jsxs("select",{"aria-label":"Filter change history by actor",value:m,onChange:t=>b(()=>N(t.target.value)),className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"",children:"All actors"}),e.jsx("option",{value:"api",children:"API and dashboard"}),e.jsx("option",{value:"cli",children:"CLI"}),e.jsx("option",{value:"scheduler",children:"Scheduler"}),e.jsx("option",{value:"agent",children:"Agent"}),e.jsx("option",{value:"mcp",children:"MCP"})]}),e.jsxs("select",{"aria-label":"Filter change history by date range",value:c,onChange:t=>b(()=>y(t.target.value)),className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"30d",children:"Last 30 days"}),e.jsx("option",{value:"90d",children:"Last 90 days"}),e.jsx("option",{value:"365d",children:"Last year"}),e.jsx("option",{value:"all",children:"All retained history"})]})]}),i.isError?e.jsxs(v,{className:"surface-card empty-card mt-4",children:[e.jsx("h3",{children:"Change history unavailable"}),e.jsx("p",{children:i.error instanceof Error?i.error.message:"Could not load the audit trail."})]}):j.length===0?e.jsxs(v,{className:"surface-card empty-card mt-4",children:[e.jsx("h3",{children:"No changes match these filters"}),e.jsx("p",{children:"Widen the date range or clear the actor and search filters."})]}):e.jsx("div",{className:"evidence-table-wrap mt-4",children:e.jsxs("table",{className:"evidence-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"When"}),s?null:e.jsx("th",{children:"Scope"}),e.jsx("th",{children:"Action"}),e.jsx("th",{children:"Entity"}),e.jsx("th",{children:"Origin"}),e.jsx("th",{children:"Details"})]})}),e.jsx("tbody",{children:j.map(t=>e.jsxs("tr",{children:[e.jsx("td",{className:"whitespace-nowrap tabular-nums text-muted",children:new Date(t.createdAt).toLocaleString()}),s?null:e.jsx("td",{className:"text-secondary",children:t.projectId?I.get(t.projectId)??`Deleted project · ${t.projectId}`:"Instance settings"}),e.jsx("td",{children:e.jsx(k,{tone:B(t.action),children:t.action})}),e.jsxs("td",{children:[e.jsx("span",{className:"text-strong",children:t.entityType}),t.entityId?e.jsx("span",{className:"mt-0.5 block max-w-48 truncate font-mono text-[11px] text-faint",title:t.entityId,children:t.entityId}):null]}),e.jsxs("td",{children:[e.jsx("span",{className:"text-secondary",children:O(t)}),t.actorSession?e.jsxs("span",{className:"mt-0.5 block max-w-40 truncate font-mono text-[11px] text-faint",title:t.actorSession,children:["Session ",t.actorSession]}):null]}),e.jsx("td",{children:t.diff==null?e.jsx("span",{className:"text-faint",children:"No field diff"}):e.jsxs("details",{children:[e.jsx("summary",{className:"min-h-11 cursor-pointer py-3 text-sm text-secondary hover:text-strong",children:"View diff"}),e.jsx("pre",{className:"max-h-72 max-w-xl overflow-auto whitespace-pre-wrap break-words rounded-md bg-bg-elevated p-3 text-xs text-secondary",children:JSON.stringify(t.diff,null,2)})]})})]},t.id))})]})}),!i.isError&&(n>0||r.length===o)?e.jsxs("div",{className:"mt-4 flex items-center justify-between gap-3",children:[e.jsx(x,{type:"button",variant:"outline",size:"sm",disabled:n===0,onClick:()=>l(t=>Math.max(0,t-1)),children:"Previous"}),e.jsxs("span",{className:"text-xs tabular-nums text-muted",children:["Page ",n+1]}),e.jsx(x,{type:"button",variant:"outline",size:"sm",disabled:r.length<o,onClick:()=>l(t=>t+1),children:"Next"})]}):null]})}export{H as A};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as n,j as e}from"./vendor-tanstack-CYBjbqVr.js";import{de as _,ai as H,df as U,dg as K,dh as V,f as x,T as j,j as u,B as w,l as F,di as Y,dj as J,al as X,dk as Z}from"./index-YVHujfy1.js";import{D as ee,T as se,E as te,P as ae,x as ne,t as re}from"./vendor-lucide-dNHw1I5G.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";function g({children:t,label:h="More info",placement:a="top",className:i}){const d=n.useId(),[y,c]=n.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${i??""}`,children:[e.jsx("button",{type:"button","aria-label":h,"aria-describedby":y?d:void 0,className:"inline-flex h-4 w-4 items-center justify-center rounded-full text-muted hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:e.jsx(re,{className:"h-3.5 w-3.5","aria-hidden":!0})}),y&&e.jsx("span",{id:d,role:"tooltip",className:`absolute z-50 w-64 rounded border border-strong bg-bg-elevated px-3 py-2 text-xs font-normal leading-relaxed text-strong shadow-lg ${a==="top"?"bottom-full mb-2":"top-full mt-2"} left-1/2 -translate-x-1/2 whitespace-normal`,children:t})]})}const le="https://commoncrawl.org/web-graphs";function S(t){return t==null?"—":t>=1e12?`${(t/1e12).toFixed(1)} TB`:t>=1e9?`${(t/1e9).toFixed(1)} GB`:t>=1e6?`${(t/1e6).toFixed(1)} MB`:t>=1e3?`${(t/1e3).toFixed(1)} KB`:`${t} B`}function b(t){if(!t)return"—";const h=Date.now()-new Date(t).getTime(),a=Math.floor(h/6e4);if(a<1)return"just now";if(a<60)return`${a}m ago`;const i=Math.floor(a/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function C(t){switch(t){case"ready":return"positive";case"failed":return"negative";case"downloading":case"querying":case"queued":return"caution"}}function me(){const[t,h]=n.useState(null),[a,i]=n.useState(null),[d,y]=n.useState([]),[c,$]=n.useState([]),[m,L]=n.useState(null),[B,D]=n.useState(!0),[R,E]=n.useState(!1),[p,I]=n.useState(!1),[N,v]=n.useState(""),[M,k]=n.useState(!1),[A,l]=n.useState(null),[P,o]=n.useState(null),f=n.useCallback(async()=>{D(!0),l(null);try{const[s,r,z,O,W]=await Promise.all([_(),H().catch(()=>null),U().catch(()=>[]),K().catch(()=>[]),V().catch(()=>null)]);h(s),i(r),y(z),$(O),L(W)}catch(s){l(s instanceof Error?s.message:"Failed to load backlinks status")}finally{D(!1)}},[]);n.useEffect(()=>{f()},[f]);async function T(){E(!0),l(null),o(null);try{const s=await Y();o(s.alreadyPresent?`DuckDB already installed (${s.version}).`:`Installed DuckDB ${s.version}.`),await f()}catch(s){l(s instanceof Error?s.message:"Failed to install DuckDB")}finally{E(!1)}}async function q(){const s=N.trim()||void 0;I(!0),l(null),o(null);try{const r=await J(s);o(s?`Queued sync for ${r.release}. Download + query runs in the background.`:`Queued sync for auto-discovered release ${r.release}. Download + query runs in the background.`),v(""),k(!1),await f()}catch(r){r instanceof X&&r.code==="MISSING_DEPENDENCY"?l("DuckDB is not installed. Install it first."):l(r instanceof Error?r.message:"Failed to trigger sync")}finally{I(!1)}}async function G(s){l(null),o(null);try{await Z(s),o(`Pruned cached release ${s}.`),await f()}catch(r){l(r instanceof Error?r.message:"Failed to prune release")}}const Q=a?.status==="ready"&&c.every(s=>s.release!==a.release);return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"Backlink data"}),e.jsx("p",{className:"page-subtitle",children:"Manage the shared backlink source and review its latest data."})]})}),A&&e.jsx(x,{className:"surface-card p-4 mb-4 border-negative-800/60",children:e.jsx("p",{className:"text-sm text-negative",children:A})}),P&&e.jsx(x,{className:"surface-card p-4 mb-4 border-positive-800/60",children:e.jsx("p",{className:"text-sm text-positive",children:P})}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Readiness"}),e.jsx("h2",{children:"Backlink source"})]}),t?.duckdbInstalled?e.jsx(j,{tone:"positive",children:"Installed"}):e.jsx(j,{tone:"caution",children:"Not installed"})]}),e.jsx(x,{className:"surface-card p-4",children:B?e.jsx("p",{className:"text-sm text-muted",children:"Checking…"}):t?.duckdbInstalled?e.jsx("p",{className:"text-sm text-secondary",children:"Ready to sync a Common Crawl release."}):e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("p",{className:"text-sm text-secondary",children:"Install the local query engine to enable release syncs."}),!u()&&e.jsxs(w,{type:"button",size:"sm",disabled:R,onClick:F(T),children:[e.jsx(ee,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),R?"Installing…":"Install DuckDB"]})]})})]}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Latest sync"}),e.jsxs("h2",{className:"flex items-center gap-2",children:["Release sync",e.jsx(g,{label:"What is a release sync?",children:"A release sync downloads one Common Crawl dump (~16 GB) and extracts backlinks for every project in this workspace in one pass. This is the heavy job — subsequent per-project re-runs skip the download and just re-query the cached files."})]})]}),a&&e.jsx(j,{tone:C(a.status),children:a.status})]}),e.jsxs(x,{className:"surface-card p-5",children:[a?e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("p",{className:"text-strong",children:["Release ",e.jsx("code",{className:"text-neutral",children:a.release})]}),a.phaseDetail&&e.jsx("p",{className:"text-secondary",children:a.phaseDetail}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-xs text-muted pt-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Projects"}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.projectsProcessed??"—"})]}),e.jsxs("div",{children:[e.jsxs("p",{className:"text-faint uppercase tracking-wide flex items-center gap-1",children:["Rows",e.jsx(g,{label:"What are rows?",children:"Total number of (project, referring domain) pairs persisted in SQLite from this sync, across every project in the workspace."})]}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.domainsDiscovered??"—"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Started"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.downloadStartedAt??a.createdAt)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Finished"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.queryFinishedAt)})]})]}),a.error&&e.jsx("p",{className:"text-sm text-negative-400 pt-2",children:a.error})]}):e.jsx("p",{className:"text-sm text-muted",children:"No release sync has run in this workspace yet."}),Q&&e.jsx("div",{className:"mt-4 rounded border border-caution-800/60 bg-caution-950/20 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(se,{className:"h-4 w-4 text-caution-400 shrink-0 mt-0.5","aria-hidden":!0}),e.jsxs("div",{className:"text-sm text-neutral leading-relaxed",children:[e.jsx("p",{className:"font-medium text-caution-200",children:"Cached files for this release are missing."}),e.jsx("p",{className:"mt-1 text-secondary",children:"Sync this release again, or sync the newest release, before refreshing individual projects."})]})]})}),e.jsxs("div",{className:"mt-4 rounded border border-base bg-bg-elevated/40 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted",children:"Auto-detected release"}),m?e.jsxs("p",{className:"text-sm text-strong mt-0.5",children:[e.jsx("code",{className:"text-heading",children:m.release}),e.jsxs("span",{className:"ml-2 text-xs text-muted",children:["Vertex ",S(m.vertexBytes),", edges ",S(m.edgesBytes)]})]}):e.jsx("p",{className:"text-sm text-muted mt-0.5",children:B?"Checking Common Crawl…":"Could not find a release. Choose one below."}),e.jsxs("a",{href:le,target:"_blank",rel:"noopener noreferrer",className:"mt-1 inline-flex items-center gap-1 text-xs text-secondary hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:["Browse all Common Crawl web-graph releases",e.jsx(te,{className:"h-3 w-3","aria-hidden":!0})]})]}),!u()&&e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsxs(w,{type:"button",size:"sm",disabled:p||!t?.duckdbInstalled||!m&&!N.trim(),onClick:F(q),children:[e.jsx(ae,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),p?"Queuing…":"Run sync"]}),e.jsxs(g,{label:"What does Run sync do?",children:[e.jsxs("span",{className:"block",children:["Downloads the auto-detected (or chosen) Common Crawl release (~16 GB) to"," ",e.jsx("code",{className:"text-neutral",children:"~/.canonry/cache/commoncrawl/"}),", then runs a single DuckDB query that extracts referring domains for every project in this workspace."]}),e.jsxs("span",{className:"mt-2 block text-secondary",children:["First time for a release: ",e.jsx("span",{className:"text-strong",children:"~10–20 min download + ~5 min query"}),". Re-running the same release later: ",e.jsx("span",{className:"text-strong",children:"skips download, just re-queries"})," (~5 min)."]})]})]})]}),u()?null:M?e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",className:"flex-1 min-w-[240px] rounded border border-strong bg-transparent px-2.5 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none",placeholder:"cc-main-2026-jan-feb-mar",value:N,onChange:s=>v(s.target.value),disabled:p,autoFocus:!0}),e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>{v(""),k(!1)},disabled:p,children:"Cancel"})]}):e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>k(!0),disabled:p,children:"Use a different release →"})]}),!t?.duckdbInstalled&&e.jsx("p",{className:"text-sm text-secondary mt-2",children:"Install DuckDB first to enable sync."})]})]}),e.jsxs("details",{className:"page-section-divider group",children:[e.jsx("summary",{className:"cursor-pointer text-sm font-medium text-secondary hover:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:"Technical details and cache"}),e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-secondary mb-3",children:"Cached releases support project re-extracts. Pruning a release does not remove saved backlink results."}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Sync status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Size"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Last used"}),!u()&&e.jsx("th",{className:"px-4 py-2 font-medium sr-only",children:"Actions"})]})}),e.jsxs("tbody",{children:[c.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:s.syncStatus?e.jsx(j,{tone:C(s.syncStatus),children:s.syncStatus}):e.jsx("span",{className:"text-faint",children:"—"})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:S(s.bytes)}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.lastUsedAt)}),!u()&&e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsxs("div",{className:"inline-flex items-center gap-1",children:[e.jsxs(w,{type:"button",variant:"outline",size:"sm",onClick:()=>{G(s.release)},children:[e.jsx(ne,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),"Prune"]}),e.jsx(g,{label:"What does Prune do?",placement:"top",children:"Deletes the ~16 GB cache for this release from disk. Backlink results already in SQLite remain untouched. To re-run extracts against this release, you’d have to sync it again (another ~16 GB download)."})]})})]},s.release)),c.length===0&&e.jsx("tr",{children:e.jsx("td",{className:"px-4 py-4 text-sm text-muted",colSpan:u()?4:5,children:"No cached releases on this machine. If you ran a sync from a different machine (or deleted the cache), the backlink data is still in the database — but you’ll need to re-sync a release to run new extracts."})})]})]})}),e.jsx("p",{className:"mt-3 text-xs text-muted",children:"Common Crawl files are stored locally. DuckDB reads them; Canonry stores results in its normal database."})]})]}),d.length>1&&e.jsxs("section",{className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"History"}),e.jsx("h2",{children:"Past release syncs"})]})}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Projects"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Rows"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Finished"})]})}),e.jsx("tbody",{children:d.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:e.jsx(j,{tone:C(s.status),children:s.status})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.projectsProcessed??"—"}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.domainsDiscovered??"—"}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.queryFinishedAt??s.updatedAt)})]},s.id))})]})})]})]})}export{me as BacklinksPage};
|
|
1
|
+
import{r as n,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{dr as _,aj as H,ds as U,dt as K,du as V,f as x,T as j,j as u,B as w,l as F,dv as Y,dw as J,am as X,dx as Z}from"./index-CCPMPGar.js";import{D as ee,T as se,E as te,P as ae,x as ne,t as re}from"./vendor-lucide-CW2qe0uH.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B-Oq2NYq.js";import"./vendor-yaml-GWJz5H2G.js";function g({children:t,label:h="More info",placement:a="top",className:i}){const d=n.useId(),[y,c]=n.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${i??""}`,children:[e.jsx("button",{type:"button","aria-label":h,"aria-describedby":y?d:void 0,className:"inline-flex h-4 w-4 items-center justify-center rounded-full text-muted hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:e.jsx(re,{className:"h-3.5 w-3.5","aria-hidden":!0})}),y&&e.jsx("span",{id:d,role:"tooltip",className:`absolute z-50 w-64 rounded border border-strong bg-bg-elevated px-3 py-2 text-xs font-normal leading-relaxed text-strong shadow-lg ${a==="top"?"bottom-full mb-2":"top-full mt-2"} left-1/2 -translate-x-1/2 whitespace-normal`,children:t})]})}const le="https://commoncrawl.org/web-graphs";function S(t){return t==null?"—":t>=1e12?`${(t/1e12).toFixed(1)} TB`:t>=1e9?`${(t/1e9).toFixed(1)} GB`:t>=1e6?`${(t/1e6).toFixed(1)} MB`:t>=1e3?`${(t/1e3).toFixed(1)} KB`:`${t} B`}function b(t){if(!t)return"—";const h=Date.now()-new Date(t).getTime(),a=Math.floor(h/6e4);if(a<1)return"just now";if(a<60)return`${a}m ago`;const i=Math.floor(a/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function C(t){switch(t){case"ready":return"positive";case"failed":return"negative";case"downloading":case"querying":case"queued":return"caution"}}function me(){const[t,h]=n.useState(null),[a,i]=n.useState(null),[d,y]=n.useState([]),[c,$]=n.useState([]),[m,L]=n.useState(null),[B,D]=n.useState(!0),[R,E]=n.useState(!1),[p,I]=n.useState(!1),[N,v]=n.useState(""),[M,k]=n.useState(!1),[A,l]=n.useState(null),[P,o]=n.useState(null),f=n.useCallback(async()=>{D(!0),l(null);try{const[s,r,z,O,W]=await Promise.all([_(),H().catch(()=>null),U().catch(()=>[]),K().catch(()=>[]),V().catch(()=>null)]);h(s),i(r),y(z),$(O),L(W)}catch(s){l(s instanceof Error?s.message:"Failed to load backlinks status")}finally{D(!1)}},[]);n.useEffect(()=>{f()},[f]);async function T(){E(!0),l(null),o(null);try{const s=await Y();o(s.alreadyPresent?`DuckDB already installed (${s.version}).`:`Installed DuckDB ${s.version}.`),await f()}catch(s){l(s instanceof Error?s.message:"Failed to install DuckDB")}finally{E(!1)}}async function q(){const s=N.trim()||void 0;I(!0),l(null),o(null);try{const r=await J(s);o(s?`Queued sync for ${r.release}. Download + query runs in the background.`:`Queued sync for auto-discovered release ${r.release}. Download + query runs in the background.`),v(""),k(!1),await f()}catch(r){r instanceof X&&r.code==="MISSING_DEPENDENCY"?l("DuckDB is not installed. Install it first."):l(r instanceof Error?r.message:"Failed to trigger sync")}finally{I(!1)}}async function G(s){l(null),o(null);try{await Z(s),o(`Pruned cached release ${s}.`),await f()}catch(r){l(r instanceof Error?r.message:"Failed to prune release")}}const Q=a?.status==="ready"&&c.every(s=>s.release!==a.release);return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"Backlink data"}),e.jsx("p",{className:"page-subtitle",children:"Manage the shared backlink source and review its latest data."})]})}),A&&e.jsx(x,{className:"surface-card p-4 mb-4 border-negative-800/60",children:e.jsx("p",{className:"text-sm text-negative",children:A})}),P&&e.jsx(x,{className:"surface-card p-4 mb-4 border-positive-800/60",children:e.jsx("p",{className:"text-sm text-positive",children:P})}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Readiness"}),e.jsx("h2",{children:"Backlink source"})]}),t?.duckdbInstalled?e.jsx(j,{tone:"positive",children:"Installed"}):e.jsx(j,{tone:"caution",children:"Not installed"})]}),e.jsx(x,{className:"surface-card p-4",children:B?e.jsx("p",{className:"text-sm text-muted",children:"Checking…"}):t?.duckdbInstalled?e.jsx("p",{className:"text-sm text-secondary",children:"Ready to sync a Common Crawl release."}):e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("p",{className:"text-sm text-secondary",children:"Install the local query engine to enable release syncs."}),!u()&&e.jsxs(w,{type:"button",size:"sm",disabled:R,onClick:F(T),children:[e.jsx(ee,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),R?"Installing…":"Install DuckDB"]})]})})]}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Latest sync"}),e.jsxs("h2",{className:"flex items-center gap-2",children:["Release sync",e.jsx(g,{label:"What is a release sync?",children:"A release sync downloads one Common Crawl dump (~16 GB) and extracts backlinks for every project in this workspace in one pass. This is the heavy job — subsequent per-project re-runs skip the download and just re-query the cached files."})]})]}),a&&e.jsx(j,{tone:C(a.status),children:a.status})]}),e.jsxs(x,{className:"surface-card p-5",children:[a?e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("p",{className:"text-strong",children:["Release ",e.jsx("code",{className:"text-neutral",children:a.release})]}),a.phaseDetail&&e.jsx("p",{className:"text-secondary",children:a.phaseDetail}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-xs text-muted pt-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Projects"}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.projectsProcessed??"—"})]}),e.jsxs("div",{children:[e.jsxs("p",{className:"text-faint uppercase tracking-wide flex items-center gap-1",children:["Rows",e.jsx(g,{label:"What are rows?",children:"Total number of (project, referring domain) pairs persisted in SQLite from this sync, across every project in the workspace."})]}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.domainsDiscovered??"—"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Started"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.downloadStartedAt??a.createdAt)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Finished"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.queryFinishedAt)})]})]}),a.error&&e.jsx("p",{className:"text-sm text-negative-400 pt-2",children:a.error})]}):e.jsx("p",{className:"text-sm text-muted",children:"No release sync has run in this workspace yet."}),Q&&e.jsx("div",{className:"mt-4 rounded border border-caution-800/60 bg-caution-950/20 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(se,{className:"h-4 w-4 text-caution-400 shrink-0 mt-0.5","aria-hidden":!0}),e.jsxs("div",{className:"text-sm text-neutral leading-relaxed",children:[e.jsx("p",{className:"font-medium text-caution-200",children:"Cached files for this release are missing."}),e.jsx("p",{className:"mt-1 text-secondary",children:"Sync this release again, or sync the newest release, before refreshing individual projects."})]})]})}),e.jsxs("div",{className:"mt-4 rounded border border-base bg-bg-elevated/40 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted",children:"Auto-detected release"}),m?e.jsxs("p",{className:"text-sm text-strong mt-0.5",children:[e.jsx("code",{className:"text-heading",children:m.release}),e.jsxs("span",{className:"ml-2 text-xs text-muted",children:["Vertex ",S(m.vertexBytes),", edges ",S(m.edgesBytes)]})]}):e.jsx("p",{className:"text-sm text-muted mt-0.5",children:B?"Checking Common Crawl…":"Could not find a release. Choose one below."}),e.jsxs("a",{href:le,target:"_blank",rel:"noopener noreferrer",className:"mt-1 inline-flex items-center gap-1 text-xs text-secondary hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:["Browse all Common Crawl web-graph releases",e.jsx(te,{className:"h-3 w-3","aria-hidden":!0})]})]}),!u()&&e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsxs(w,{type:"button",size:"sm",disabled:p||!t?.duckdbInstalled||!m&&!N.trim(),onClick:F(q),children:[e.jsx(ae,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),p?"Queuing…":"Run sync"]}),e.jsxs(g,{label:"What does Run sync do?",children:[e.jsxs("span",{className:"block",children:["Downloads the auto-detected (or chosen) Common Crawl release (~16 GB) to"," ",e.jsx("code",{className:"text-neutral",children:"~/.canonry/cache/commoncrawl/"}),", then runs a single DuckDB query that extracts referring domains for every project in this workspace."]}),e.jsxs("span",{className:"mt-2 block text-secondary",children:["First time for a release: ",e.jsx("span",{className:"text-strong",children:"~10–20 min download + ~5 min query"}),". Re-running the same release later: ",e.jsx("span",{className:"text-strong",children:"skips download, just re-queries"})," (~5 min)."]})]})]})]}),u()?null:M?e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",className:"flex-1 min-w-[240px] rounded border border-strong bg-transparent px-2.5 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none",placeholder:"cc-main-2026-jan-feb-mar",value:N,onChange:s=>v(s.target.value),disabled:p,autoFocus:!0}),e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>{v(""),k(!1)},disabled:p,children:"Cancel"})]}):e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>k(!0),disabled:p,children:"Use a different release →"})]}),!t?.duckdbInstalled&&e.jsx("p",{className:"text-sm text-secondary mt-2",children:"Install DuckDB first to enable sync."})]})]}),e.jsxs("details",{className:"page-section-divider group",children:[e.jsx("summary",{className:"cursor-pointer text-sm font-medium text-secondary hover:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:"Technical details and cache"}),e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-secondary mb-3",children:"Cached releases support project re-extracts. Pruning a release does not remove saved backlink results."}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Sync status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Size"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Last used"}),!u()&&e.jsx("th",{className:"px-4 py-2 font-medium sr-only",children:"Actions"})]})}),e.jsxs("tbody",{children:[c.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:s.syncStatus?e.jsx(j,{tone:C(s.syncStatus),children:s.syncStatus}):e.jsx("span",{className:"text-faint",children:"—"})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:S(s.bytes)}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.lastUsedAt)}),!u()&&e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsxs("div",{className:"inline-flex items-center gap-1",children:[e.jsxs(w,{type:"button",variant:"outline",size:"sm",onClick:()=>{G(s.release)},children:[e.jsx(ne,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),"Prune"]}),e.jsx(g,{label:"What does Prune do?",placement:"top",children:"Deletes the ~16 GB cache for this release from disk. Backlink results already in SQLite remain untouched. To re-run extracts against this release, you’d have to sync it again (another ~16 GB download)."})]})})]},s.release)),c.length===0&&e.jsx("tr",{children:e.jsx("td",{className:"px-4 py-4 text-sm text-muted",colSpan:u()?4:5,children:"No cached releases on this machine. If you ran a sync from a different machine (or deleted the cache), the backlink data is still in the database — but you’ll need to re-sync a release to run new extracts."})})]})]})}),e.jsx("p",{className:"mt-3 text-xs text-muted",children:"Common Crawl files are stored locally. DuckDB reads them; Canonry stores results in its normal database."})]})]}),d.length>1&&e.jsxs("section",{className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"History"}),e.jsx("h2",{children:"Past release syncs"})]})}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Projects"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Rows"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Finished"})]})}),e.jsx("tbody",{children:d.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:e.jsx(j,{tone:C(s.status),children:s.status})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.projectsProcessed??"—"}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.domainsDiscovered??"—"}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.queryFinishedAt??s.updatedAt)})]},s.id))})]})})]})]})}export{me as BacklinksPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as i}from"./vendor-tanstack-
|
|
1
|
+
import{j as i}from"./vendor-tanstack-ZXXkndVj.js";import{R as k,C,a as R,e as A,X as I,Y as _,T as D,d as m}from"./vendor-recharts-D-cUuLZo.js";const L={contentStyle:{backgroundColor:"var(--chart-tooltip-bg, #18181b)",border:"1px solid var(--chart-tooltip-border, #3f3f46)",borderRadius:8,fontSize:12},labelStyle:{color:"var(--chart-tooltip-label, #e4e4e7)"},itemStyle:{color:"var(--chart-tooltip-item, #a1a1aa)"}},v={fill:"var(--chart-neutral-text-dim, #8b8b93)",fontSize:11},O="var(--chart-grid, #27272a)",b="var(--chart-axis, #27272a)",p=["var(--chart-series-1, #34d399)","var(--chart-series-2, #60a5fa)","var(--chart-series-3, #f472b6)","var(--chart-series-4, #facc15)","var(--chart-series-5, #a78bfa)","var(--chart-series-6, #fb923c)","var(--chart-series-7, #22d3ee)","var(--chart-series-8, #f87171)"],j={gemini:"#60a5fa",openai:"#34d399",claude:"#fb923c",perplexity:"#22d3ee",local:"#a78bfa"};function $(r,a=0){return j[r]??p[a%p.length]}const K={text:"var(--chart-neutral-text, #a1a1aa)",textDim:"var(--chart-neutral-text-dim, #8b8b93)",textFaint:"var(--chart-neutral-text-faint, #52525b)",surface:"var(--chart-neutral-surface, #27272a)",trackSubtle:"var(--chart-neutral-track-subtle, rgb(255 255 255 / 0.04))"},H={positive:"var(--chart-tone-positive, #34d399)",positiveDeep:"var(--chart-tone-positive-deep, #10b981)",caution:"var(--chart-tone-caution, #fbbf24)",negative:"var(--chart-tone-negative, #fb7185)"};function N(r){return r}function y(r){const a=/^(\d{4})-(\d{2})-(\d{2})/.exec(r);return a?{year:Number(a[1]),month:Number(a[2]),day:Number(a[3])}:null}function M(r){const a=String(r),e=y(a);return e?new Date(Date.UTC(e.year,e.month-1,e.day)).toLocaleDateString(void 0,{timeZone:"UTC",month:"short",day:"numeric",year:"numeric"}):a}function F(r){const a=y(String(r));return a?`${a.month}/${a.day}`:String(r)}function G(r){return new Date(r).toLocaleDateString(void 0,{month:"short",day:"numeric",year:"numeric"})}function P(r){const a=new Date(r);return`${a.getMonth()+1}/${a.getDate()}`}function U({data:r,xKey:a,series:e,height:x=260,xTickFormatter:g,labelFormatter:f,onSelectX:d,selectedX:u}){const h=[...new Set(e.map(t=>t.axisId))],S=new Map(e.map(t=>[t.label,t.formatValue])),T=r.map((t,s)=>{const n={...t};for(const o of e){if(!o.trend)continue;const c=o.trend.startIndex??0,l=o.trend.endIndex??r.length-1;if(s<c||s>l){n[`${o.dataKey}__trend`]=null;continue}n[`${o.dataKey}__trend`]=l<=c?o.trend.start:o.trend.start+(o.trend.end-o.trend.start)*(s-c)/(l-c)}return n});return i.jsx(k,{width:"100%",height:x,children:i.jsxs(C,{data:T,margin:{top:8,right:8,bottom:4,left:0},onClick:d?t=>{t?.activeLabel!==void 0&&d(String(t.activeLabel))}:void 0,style:d?{cursor:"pointer"}:void 0,children:[i.jsx(R,{stroke:O,strokeDasharray:"3 3",vertical:!1}),u!=null&&i.jsx(A,{x:u,yAxisId:h[0],stroke:K.text,strokeDasharray:"2 3",strokeWidth:1}),i.jsx(I,{dataKey:a,tick:v,stroke:b,tickFormatter:g,minTickGap:24}),h.map((t,s)=>{const n=e.find(o=>o.axisId===t);return i.jsx(_,{yAxisId:t,orientation:s===1?"right":"left",hide:s>1,reversed:n.inverted??!1,domain:n.inverted?[1,"auto"]:[0,"auto"],tick:v,stroke:b,width:48,tickFormatter:n.formatValue},t)}),i.jsx(D,{...L,labelFormatter:t=>f?f(String(t)):String(t),formatter:(t,s)=>{const n=String(s??"");return typeof t!="number"?[String(t??""),n]:[S.get(n)?.(t)??t.toLocaleString(),n]}}),e.filter(t=>t.trend).map(t=>i.jsx(m,{yAxisId:t.axisId,dataKey:`${t.dataKey}__trend`,name:`${t.label} trend`,stroke:t.color,strokeWidth:1.5,strokeDasharray:"5 4",strokeOpacity:.55,dot:!1,activeDot:!1,isAnimationActive:!1,legendType:"none",tooltipType:"none"},`${t.dataKey}-trend`)),e.map(t=>i.jsx(m,{yAxisId:t.axisId,dataKey:t.dataKey,name:t.label,stroke:t.color,strokeWidth:2,dot:!1,activeDot:{r:3},connectNulls:!1,isAnimationActive:!1},t.dataKey))]})})}export{O as C,U as M,b as a,v as b,M as c,L as d,p as e,F as f,K as g,H as h,P as i,G as j,N as o,$ as p};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./vendor-tanstack-
|
|
1
|
+
import{j as e}from"./vendor-tanstack-ZXXkndVj.js";import{A as s}from"./AuditHistoryPanel-C7MwfCl9.js";import"./index-CCPMPGar.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-lucide-CW2qe0uH.js";import"./vendor-markdown-B-Oq2NYq.js";import"./vendor-yaml-GWJz5H2G.js";function l(){return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"History"}),e.jsx("p",{className:"page-subtitle",children:"Changes to projects and settings."})]})}),e.jsx(s,{})]})}export{l as HistoryPage};
|