@agentsean/keywords 1.0.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 (46) hide show
  1. package/LICENSE +661 -0
  2. package/dist/cluster.d.ts +10 -0
  3. package/dist/cluster.d.ts.map +1 -0
  4. package/dist/cluster.js +119 -0
  5. package/dist/cluster.js.map +1 -0
  6. package/dist/difficulty.d.ts +8 -0
  7. package/dist/difficulty.d.ts.map +1 -0
  8. package/dist/difficulty.js +103 -0
  9. package/dist/difficulty.js.map +1 -0
  10. package/dist/embeddings.d.ts +28 -0
  11. package/dist/embeddings.d.ts.map +1 -0
  12. package/dist/embeddings.js +103 -0
  13. package/dist/embeddings.js.map +1 -0
  14. package/dist/engine.d.ts +4 -0
  15. package/dist/engine.d.ts.map +1 -0
  16. package/dist/engine.js +84 -0
  17. package/dist/engine.js.map +1 -0
  18. package/dist/gsc.d.ts +4 -0
  19. package/dist/gsc.d.ts.map +1 -0
  20. package/dist/gsc.js +17 -0
  21. package/dist/gsc.js.map +1 -0
  22. package/dist/index.d.ts +11 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +10 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/opportunities.d.ts +13 -0
  27. package/dist/opportunities.d.ts.map +1 -0
  28. package/dist/opportunities.js +79 -0
  29. package/dist/opportunities.js.map +1 -0
  30. package/dist/persist.d.ts +43 -0
  31. package/dist/persist.d.ts.map +1 -0
  32. package/dist/persist.js +127 -0
  33. package/dist/persist.js.map +1 -0
  34. package/dist/ranks.d.ts +27 -0
  35. package/dist/ranks.d.ts.map +1 -0
  36. package/dist/ranks.js +70 -0
  37. package/dist/ranks.js.map +1 -0
  38. package/dist/types.d.ts +81 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/vectors.d.ts +8 -0
  43. package/dist/vectors.d.ts.map +1 -0
  44. package/dist/vectors.js +24 -0
  45. package/dist/vectors.js.map +1 -0
  46. package/package.json +53 -0
@@ -0,0 +1,79 @@
1
+ const STRIKE_LO = 8;
2
+ const STRIKE_HI = 20;
3
+ export function aggregateQueries(rows) {
4
+ const map = new Map();
5
+ for (const r of rows) {
6
+ const cur = map.get(r.query) ?? {
7
+ query: r.query,
8
+ clicks: 0,
9
+ impressions: 0,
10
+ position: 0,
11
+ n: 0,
12
+ page: r.page ?? null,
13
+ };
14
+ cur.clicks += r.clicks;
15
+ cur.impressions += r.impressions;
16
+ if (r.position !== null) {
17
+ cur.position += r.position;
18
+ cur.n++;
19
+ }
20
+ if (!cur.page && r.page)
21
+ cur.page = r.page;
22
+ map.set(r.query, cur);
23
+ }
24
+ return [...map.values()].map((v) => ({
25
+ query: v.query,
26
+ clicks: v.clicks,
27
+ impressions: v.impressions,
28
+ position: v.n ? v.position / v.n : null,
29
+ page: v.page,
30
+ }));
31
+ }
32
+ export function strikingDistance(rows) {
33
+ return aggregateQueries(rows)
34
+ .filter((r) => r.position !== null && r.position >= STRIKE_LO && r.position <= STRIKE_HI)
35
+ .toSorted((a, b) => b.clicks - a.clicks)
36
+ .map((r) => ({
37
+ query: r.query,
38
+ kind: "striking_distance",
39
+ clicks: r.clicks,
40
+ impressions: r.impressions,
41
+ position: r.position,
42
+ page: r.page,
43
+ volume: null,
44
+ difficulty: null,
45
+ source: "gsc",
46
+ }));
47
+ }
48
+ export function demandOpportunities(rows) {
49
+ return aggregateQueries(rows)
50
+ .filter((r) => r.clicks > 0 || r.impressions > 0)
51
+ .toSorted((a, b) => b.clicks - a.clicks || b.impressions - a.impressions)
52
+ .map((r) => ({
53
+ query: r.query,
54
+ kind: "demand",
55
+ clicks: r.clicks,
56
+ impressions: r.impressions,
57
+ position: r.position,
58
+ page: r.page,
59
+ volume: null,
60
+ difficulty: null,
61
+ source: "gsc",
62
+ }));
63
+ }
64
+ export function expansionOpportunities(related, known) {
65
+ return related
66
+ .filter((r) => !known.has(r.query.toLowerCase()))
67
+ .map((r) => ({
68
+ query: r.query,
69
+ kind: "expansion",
70
+ clicks: r.clicks ?? 0,
71
+ impressions: r.impressions ?? 0,
72
+ position: r.position ?? null,
73
+ page: r.page ?? null,
74
+ volume: r.volume ?? null,
75
+ difficulty: null,
76
+ source: r.source,
77
+ }));
78
+ }
79
+ //# sourceMappingURL=opportunities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opportunities.js","sourceRoot":"","sources":["../src/opportunities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ import type { Cluster, Opportunity, RankRow } from "./types.js";
3
+ export declare function saveKeywords(db: SqliteDatabase, siteId: string, rows: Opportunity[], now?: Date): void;
4
+ export declare function saveClusters(db: SqliteDatabase, siteId: string, clusters: Cluster[], now?: Date): void;
5
+ export declare function saveRanks(db: SqliteDatabase, siteId: string, ranks: RankRow[], now?: Date): void;
6
+ export declare function listKeywords(db: SqliteDatabase, siteId: string): {
7
+ id: string;
8
+ siteId: string;
9
+ query: string;
10
+ source: string;
11
+ volume: number | null;
12
+ volumeSource: string | null;
13
+ difficulty: number | null;
14
+ clicks: number;
15
+ impressions: number;
16
+ position: number | null;
17
+ page: string | null;
18
+ clusterId: string | null;
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ }[];
22
+ export declare function listClusters(db: SqliteDatabase, siteId: string): {
23
+ id: string;
24
+ siteId: string;
25
+ label: string;
26
+ memberCount: number;
27
+ centroidJson: string | null;
28
+ serpConfirmed: number;
29
+ createdAt: string;
30
+ }[];
31
+ export declare function listRanks(db: SqliteDatabase, siteId: string): {
32
+ id: string;
33
+ siteId: string;
34
+ query: string;
35
+ url: string | null;
36
+ position: number | null;
37
+ date: string;
38
+ provider: string;
39
+ estimatedUsd: number;
40
+ actualUsd: number;
41
+ createdAt: string;
42
+ }[];
43
+ //# sourceMappingURL=persist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEhE,wBAAgB,YAAY,CAC1B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,EAAE,EACnB,GAAG,OAAa,GACf,IAAI,CA4CN;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EAAE,EACnB,GAAG,OAAa,GACf,IAAI,CA0BN;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EAAE,EAChB,GAAG,OAAa,GACf,IAAI,CAwCN;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;IAE9D;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM;;;;;;;;IAM9D;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;IAE3D"}
@@ -0,0 +1,127 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { eq } from "drizzle-orm";
3
+ import { keywordClusters, keywords, rankSnapshots, } from "@agentsean/db";
4
+ export function saveKeywords(db, siteId, rows, now = new Date()) {
5
+ const ts = now.toISOString();
6
+ for (const row of rows) {
7
+ const existing = db
8
+ .select()
9
+ .from(keywords)
10
+ .where(eq(keywords.siteId, siteId))
11
+ .all()
12
+ .find((r) => r.query === row.query);
13
+ if (existing) {
14
+ db.update(keywords)
15
+ .set({
16
+ source: row.source,
17
+ volume: row.volume,
18
+ difficulty: row.difficulty,
19
+ clicks: row.clicks,
20
+ impressions: row.impressions,
21
+ position: row.position,
22
+ page: row.page,
23
+ updatedAt: ts,
24
+ })
25
+ .where(eq(keywords.id, existing.id))
26
+ .run();
27
+ continue;
28
+ }
29
+ db.insert(keywords)
30
+ .values({
31
+ id: randomUUID(),
32
+ siteId,
33
+ query: row.query,
34
+ source: row.source,
35
+ volume: row.volume,
36
+ volumeSource: row.volume !== null ? row.source : null,
37
+ difficulty: row.difficulty,
38
+ clicks: row.clicks,
39
+ impressions: row.impressions,
40
+ position: row.position,
41
+ page: row.page,
42
+ clusterId: null,
43
+ createdAt: ts,
44
+ updatedAt: ts,
45
+ })
46
+ .run();
47
+ }
48
+ }
49
+ export function saveClusters(db, siteId, clusters, now = new Date()) {
50
+ const ts = now.toISOString();
51
+ db.delete(keywordClusters).where(eq(keywordClusters.siteId, siteId)).run();
52
+ const allKw = db.select().from(keywords).where(eq(keywords.siteId, siteId)).all();
53
+ for (const c of clusters) {
54
+ db.insert(keywordClusters)
55
+ .values({
56
+ id: c.id,
57
+ siteId,
58
+ label: c.label,
59
+ memberCount: c.members.length,
60
+ centroidJson: null,
61
+ serpConfirmed: c.serpConfirmed ? 1 : 0,
62
+ createdAt: ts,
63
+ })
64
+ .run();
65
+ for (const member of c.members) {
66
+ const row = allKw.find((k) => k.query === member);
67
+ if (row) {
68
+ db.update(keywords)
69
+ .set({ clusterId: c.id, updatedAt: ts })
70
+ .where(eq(keywords.id, row.id))
71
+ .run();
72
+ }
73
+ }
74
+ }
75
+ }
76
+ export function saveRanks(db, siteId, ranks, now = new Date()) {
77
+ const ts = now.toISOString();
78
+ const date = ts.slice(0, 10);
79
+ for (const r of ranks) {
80
+ const existing = db
81
+ .select()
82
+ .from(rankSnapshots)
83
+ .where(eq(rankSnapshots.siteId, siteId))
84
+ .all()
85
+ .find((row) => row.query === r.query && row.date === date && row.provider === r.provider);
86
+ if (existing) {
87
+ db.update(rankSnapshots)
88
+ .set({
89
+ url: r.url,
90
+ position: r.position,
91
+ estimatedUsd: r.estimatedUsd,
92
+ actualUsd: r.actualUsd,
93
+ })
94
+ .where(eq(rankSnapshots.id, existing.id))
95
+ .run();
96
+ continue;
97
+ }
98
+ db.insert(rankSnapshots)
99
+ .values({
100
+ id: randomUUID(),
101
+ siteId,
102
+ query: r.query,
103
+ url: r.url,
104
+ position: r.position,
105
+ date,
106
+ provider: r.provider,
107
+ estimatedUsd: r.estimatedUsd,
108
+ actualUsd: r.actualUsd,
109
+ createdAt: ts,
110
+ })
111
+ .run();
112
+ }
113
+ }
114
+ export function listKeywords(db, siteId) {
115
+ return db.select().from(keywords).where(eq(keywords.siteId, siteId)).all();
116
+ }
117
+ export function listClusters(db, siteId) {
118
+ return db
119
+ .select()
120
+ .from(keywordClusters)
121
+ .where(eq(keywordClusters.siteId, siteId))
122
+ .all();
123
+ }
124
+ export function listRanks(db, siteId) {
125
+ return db.select().from(rankSnapshots).where(eq(rankSnapshots.siteId, siteId)).all();
126
+ }
127
+ //# sourceMappingURL=persist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.js","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ProviderStack } from "@agentsean/providers";
2
+ import { type CostEstimate } from "@agentsean/providers";
3
+ import type { SqliteDatabase } from "@agentsean/db";
4
+ import type { RankRow } from "./types.js";
5
+ export type RankCheckResult = {
6
+ skipped: boolean;
7
+ reason?: string;
8
+ cadence: "weekly";
9
+ provider: string;
10
+ ranks: RankRow[];
11
+ quotes: CostEstimate[];
12
+ };
13
+ /**
14
+ * Weekly licensed rank check. Sean never scrapes Google.
15
+ * GSC position remains the free proxy; DataForSEO is the paid upgrade.
16
+ */
17
+ export declare function runRankCheck(opts: {
18
+ db: SqliteDatabase;
19
+ siteId: string;
20
+ origin: string;
21
+ queries: string[];
22
+ stack: ProviderStack;
23
+ now?: Date;
24
+ dailyBudgetUsd?: number;
25
+ scrapeGoogle?: boolean;
26
+ }): Promise<RankCheckResult>;
27
+ //# sourceMappingURL=ranks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranks.d.ts","sourceRoot":"","sources":["../src/ranks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,QAAQ,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,EAAE,EAAE,cAAc,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;IACrB,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0D3B"}
package/dist/ranks.js ADDED
@@ -0,0 +1,70 @@
1
+ import { debitProvider, remainingBudgetUsd, } from "@agentsean/providers";
2
+ import { scrapeGoogleSerp } from "@agentsean/providers";
3
+ /**
4
+ * Weekly licensed rank check. Sean never scrapes Google.
5
+ * GSC position remains the free proxy; DataForSEO is the paid upgrade.
6
+ */
7
+ export async function runRankCheck(opts) {
8
+ if (opts.scrapeGoogle)
9
+ scrapeGoogleSerp();
10
+ const now = opts.now ?? new Date();
11
+ if (!opts.stack.serp.available) {
12
+ return {
13
+ skipped: true,
14
+ reason: "no_licensed_rank_provider",
15
+ cadence: "weekly",
16
+ provider: "gsc",
17
+ ranks: [],
18
+ quotes: [],
19
+ };
20
+ }
21
+ const quotes = [];
22
+ const ranks = [];
23
+ const host = hostOf(opts.origin);
24
+ let remaining = remainingBudgetUsd(opts.db, opts.siteId, opts.dailyBudgetUsd ?? 8, now);
25
+ for (const query of opts.queries) {
26
+ const call = opts.stack.serp.serp(query);
27
+ quotes.push(call.estimate);
28
+ if (call.estimate.estimatedUsd > remaining) {
29
+ return {
30
+ skipped: ranks.length === 0,
31
+ reason: ranks.length === 0 ? "over_budget" : "partial_budget",
32
+ cadence: "weekly",
33
+ provider: opts.stack.serp.id,
34
+ ranks,
35
+ quotes,
36
+ };
37
+ }
38
+ const result = await call.run();
39
+ debitProvider(opts.db, call.estimate, {
40
+ siteId: opts.siteId,
41
+ actualUsd: call.estimate.estimatedUsd,
42
+ });
43
+ remaining -= call.estimate.estimatedUsd;
44
+ const hit = result.items.find((i) => hostOf(i.url) === host) ?? null;
45
+ ranks.push({
46
+ query,
47
+ url: hit?.url ?? null,
48
+ position: hit?.rank ?? null,
49
+ provider: result.provider,
50
+ estimatedUsd: call.estimate.estimatedUsd,
51
+ actualUsd: call.estimate.estimatedUsd,
52
+ });
53
+ }
54
+ return {
55
+ skipped: false,
56
+ cadence: "weekly",
57
+ provider: opts.stack.serp.id,
58
+ ranks,
59
+ quotes,
60
+ };
61
+ }
62
+ function hostOf(value) {
63
+ try {
64
+ return new URL(value.includes("://") ? value : `https://${value}`).hostname.replace(/^www\./, "");
65
+ }
66
+ catch {
67
+ return value.replace(/^www\./, "");
68
+ }
69
+ }
70
+ //# sourceMappingURL=ranks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranks.js","sourceRoot":"","sources":["../src/ranks.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,kBAAkB,GAEnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAWxD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IASlC;IACC,IAAI,IAAI,CAAC,YAAY;QAAE,gBAAgB,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/B,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,2BAA2B;YACnC,OAAO,EAAE,QAAQ;YACjB,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAmB,EAAE,CAAC;IAClC,MAAM,KAAK,GAAc,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,SAAS,GAAG,kBAAkB,CAChC,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,cAAc,IAAI,CAAC,EACxB,GAAG,CACJ,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,GAAG,SAAS,EAAE,CAAC;YAC3C,OAAO;gBACL,OAAO,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC;gBAC3B,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB;gBAC7D,OAAO,EAAE,QAAQ;gBACjB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;gBAC5B,KAAK;gBACL,MAAM;aACP,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,aAAa,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE;YACpC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY;SACtC,CAAC,CAAC;QACH,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC;QACrE,KAAK,CAAC,IAAI,CAAC;YACT,KAAK;YACL,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,IAAI;YACrB,QAAQ,EAAE,GAAG,EAAE,IAAI,IAAI,IAAI;YAC3B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY;YACxC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY;SACtC,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,QAAQ;QACjB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;QAC5B,KAAK;QACL,MAAM;KACP,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CACjF,QAAQ,EACR,EAAE,CACH,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
@@ -0,0 +1,81 @@
1
+ import type { CostEstimate, KeywordRow, ProviderStack, SerpResult } from "@agentsean/providers";
2
+ export type QueryDaily = {
3
+ date: string;
4
+ query: string;
5
+ clicks: number;
6
+ impressions: number;
7
+ position: number | null;
8
+ page?: string | null;
9
+ };
10
+ export type Opportunity = {
11
+ query: string;
12
+ kind: "striking_distance" | "demand" | "expansion";
13
+ clicks: number;
14
+ impressions: number;
15
+ position: number | null;
16
+ page: string | null;
17
+ volume: number | null;
18
+ difficulty: number | null;
19
+ source: string;
20
+ };
21
+ export type Cluster = {
22
+ id: string;
23
+ label: string;
24
+ members: string[];
25
+ serpConfirmed: boolean;
26
+ };
27
+ export type RankRow = {
28
+ query: string;
29
+ url: string | null;
30
+ position: number | null;
31
+ provider: string;
32
+ estimatedUsd: number;
33
+ actualUsd: number;
34
+ };
35
+ export type Embeddings = {
36
+ model: string;
37
+ dim: number;
38
+ embed(text: string): number[] | Promise<number[]>;
39
+ };
40
+ export type VectorHit = {
41
+ id: string;
42
+ score: number;
43
+ };
44
+ export type VectorStore = {
45
+ upsert(id: string, vector: number[]): void;
46
+ knn(vector: number[], k: number): VectorHit[];
47
+ };
48
+ export type DifficultyModel = {
49
+ trained: boolean;
50
+ samples: number;
51
+ note: string;
52
+ predict(query: string, impressions: number): number | null;
53
+ };
54
+ export type KeywordsJobResult = {
55
+ skipped?: boolean;
56
+ reason?: string;
57
+ paidUpgrade: boolean;
58
+ opportunities: Opportunity[];
59
+ clusters: Cluster[];
60
+ strikingDistance: Opportunity[];
61
+ ranks: RankRow[];
62
+ quotes: CostEstimate[];
63
+ embeddingsModel: string;
64
+ difficultyNote: string;
65
+ };
66
+ export type KeywordsJobOptions = {
67
+ siteId: string;
68
+ origin: string;
69
+ now?: Date;
70
+ stack: ProviderStack;
71
+ gsc: QueryDaily[];
72
+ brandTerms?: string[];
73
+ embeddings?: Embeddings;
74
+ serpForCluster?: (query: string) => Promise<SerpResult | null>;
75
+ expandSeeds?: string[];
76
+ expand?: (seed: string) => Promise<KeywordRow[]>;
77
+ dailyBudgetUsd?: number;
78
+ trackLimit?: number;
79
+ };
80
+ export type { KeywordRow };
81
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import type { VectorStore } from "./types.js";
2
+ /**
3
+ * Brute-force cosine KNN. sqlite-vec 0.1.9 is still alpha with brute-force only,
4
+ * so this is the honest default. LanceDB is the escape hatch above ~200k vectors.
5
+ */
6
+ export declare function createMemoryVectorStore(): VectorStore;
7
+ export declare function createLanceVectorStore(): VectorStore;
8
+ //# sourceMappingURL=vectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectors.d.ts","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzD;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,WAAW,CAcrD;AAED,wBAAgB,sBAAsB,IAAI,WAAW,CAIpD"}
@@ -0,0 +1,24 @@
1
+ import { cosine } from "./embeddings.js";
2
+ /**
3
+ * Brute-force cosine KNN. sqlite-vec 0.1.9 is still alpha with brute-force only,
4
+ * so this is the honest default. LanceDB is the escape hatch above ~200k vectors.
5
+ */
6
+ export function createMemoryVectorStore() {
7
+ const rows = new Map();
8
+ return {
9
+ upsert(id, vector) {
10
+ rows.set(id, vector);
11
+ },
12
+ knn(vector, k) {
13
+ const hits = [];
14
+ for (const [id, v] of rows) {
15
+ hits.push({ id, score: cosine(vector, v) });
16
+ }
17
+ return hits.toSorted((a, b) => b.score - a.score).slice(0, k);
18
+ },
19
+ };
20
+ }
21
+ export function createLanceVectorStore() {
22
+ throw new Error("LanceDB is the escape hatch above ~200k vectors and is not bundled. Stay on the in-memory/SQLite brute-force store until then.");
23
+ }
24
+ //# sourceMappingURL=vectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectors.js","sourceRoot":"","sources":["../src/vectors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;IACzC,OAAO;QACL,MAAM,CAAC,EAAE,EAAE,MAAM;YACf,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,GAAgB,EAAE,CAAC;YAC7B,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,IAAI,KAAK,CACb,gIAAgI,CACjI,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@agentsean/keywords",
3
+ "version": "1.0.0",
4
+ "license": "AGPL-3.0-only",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "engines": {
16
+ "node": ">=22.19.0"
17
+ },
18
+ "dependencies": {
19
+ "drizzle-orm": "0.45.2",
20
+ "@agentsean/credentials": "1.0.0",
21
+ "@agentsean/providers": "1.0.0",
22
+ "@agentsean/db": "1.0.0"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "~5.9.3",
26
+ "vitest": "^4.1.11"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/seziro-team/agentsean.git",
34
+ "directory": "packages/keywords"
35
+ },
36
+ "homepage": "https://github.com/seziro-team/agentsean#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/seziro-team/agentsean/issues"
39
+ },
40
+ "author": "Seziro (https://seziro.com)",
41
+ "description": "Agent Sean — keywords module",
42
+ "keywords": [
43
+ "seo",
44
+ "agent",
45
+ "agentsean",
46
+ "seo-automation"
47
+ ],
48
+ "scripts": {
49
+ "build": "tsc -p tsconfig.json",
50
+ "typecheck": "tsc -p tsconfig.json --noEmit",
51
+ "test": "vitest run --config ../../vitest.config.ts"
52
+ }
53
+ }