@agent-pattern-labs/leads-rig 0.1.4 → 0.1.6
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/.claude/agents/general-free.md +3 -1
- package/.codex/config.toml +1 -1
- package/.cursor/rules/agent-general-free.mdc +3 -1
- package/.cursor/rules/main.mdc +3 -2
- package/.opencode/agents/general-free.md +3 -1
- package/.pi/skills/general-free/SKILL.md +3 -1
- package/AGENTS.md +3 -2
- package/CLAUDE.md +3 -2
- package/README.md +5 -2
- package/bin/create-leads-harness.mjs +1 -1
- package/bin/lead-harness.mjs +75 -75
- package/docs/ARCHITECTURE.md +3 -3
- package/docs/CONSTRUCTION.md +2 -2
- package/iso/agents/general-free.md +3 -1
- package/iso/instructions.md +3 -2
- package/lib/leadharness-crawler.mjs +3 -2
- package/lib/leadharness-leads.mjs +97 -1
- package/modes/_shared.md +7 -3
- package/modes/batch.md +1 -1
- package/package.json +25 -25
- package/scripts/batch-orchestrator.mjs +1 -1
- package/scripts/crawl.mjs +1 -1
- package/scripts/manifest.mjs +3 -2
- package/scripts/pipeline.mjs +2 -1
- package/scripts/validate-leads.mjs +1 -1
|
@@ -27,7 +27,9 @@ Skip this only if the task explicitly says to attach to an existing session.
|
|
|
27
27
|
## Do
|
|
28
28
|
|
|
29
29
|
- Crawl only public, high-signal company pages.
|
|
30
|
-
-
|
|
30
|
+
- Use your judgment on each email candidate: only emit an email lead when public evidence identifies one specific human owner of the address.
|
|
31
|
+
- Extract high-quality named human emails, contact forms, public names/titles, source URL, evidence, and warnings.
|
|
32
|
+
- If an address is shared, role-based, departmental, generic, blocked, or not tied to a visible named human, do not emit it as an email lead; emit a `contact_path` if useful.
|
|
31
33
|
- Emit JSON/JSONL matching `templates/lead-schema.json`.
|
|
32
34
|
- Run `npx public-leads validate --input <file>` before returning a result.
|
|
33
35
|
- Return file paths and terminal status, not a prose-only summary.
|
package/.codex/config.toml
CHANGED
|
@@ -26,7 +26,9 @@ Skip this only if the task explicitly says to attach to an existing session.
|
|
|
26
26
|
## Do
|
|
27
27
|
|
|
28
28
|
- Crawl only public, high-signal company pages.
|
|
29
|
-
-
|
|
29
|
+
- Use your judgment on each email candidate: only emit an email lead when public evidence identifies one specific human owner of the address.
|
|
30
|
+
- Extract high-quality named human emails, contact forms, public names/titles, source URL, evidence, and warnings.
|
|
31
|
+
- If an address is shared, role-based, departmental, generic, blocked, or not tied to a visible named human, do not emit it as an email lead; emit a `contact_path` if useful.
|
|
30
32
|
- Emit JSON/JSONL matching `templates/lead-schema.json`.
|
|
31
33
|
- Run `npx public-leads validate --input <file>` before returning a result.
|
|
32
34
|
- Return file paths and terminal status, not a prose-only summary.
|
package/.cursor/rules/main.mdc
CHANGED
|
@@ -9,7 +9,8 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
9
9
|
|
|
10
10
|
## Hard Limits
|
|
11
11
|
|
|
12
|
-
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt.
|
|
12
|
+
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt. The primary goal is named people, not generic company inboxes.
|
|
13
|
+
- [H8] Apply coding-agent judgment to every email candidate. An email may pass only when public source evidence identifies one specific human owner of that email. Shared, role, departmental, generic, blocked, unknown-owner, or unnamed person-like emails must not be emitted as email leads.
|
|
13
14
|
- [H2] Respect robots.txt, terms, rate limits, and site intent. If a page blocks crawling or is not public, record a warning and move on.
|
|
14
15
|
- [H3] Never send outreach from this harness. The output is reviewable lead records and ingest-ready artifacts, not email campaigns.
|
|
15
16
|
- [H4] Use file-backed artifacts before ingest. A subagent prose summary is not enough; write validated JSON/JSONL first, then ingest.
|
|
@@ -23,7 +24,7 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
23
24
|
- [D2] Use deterministic local helpers when they can validate, normalize, manifest, preflight, postflight, or ingest artifacts.
|
|
24
25
|
- [D3] Read the active mode file before executing. Mode files own output shapes and gates.
|
|
25
26
|
- [D4] Prefer official company websites and high-signal pages: home, contact, about, team, leadership, people, press, blog, careers, and legal pages.
|
|
26
|
-
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`.
|
|
27
|
+
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`. Reject generic catch-all inboxes such as `info@`, `hello@`, `contact@`, `support@`, `team@`, and similar aliases; if no named human email is available, prefer a `contact_path` record instead.
|
|
27
28
|
|
|
28
29
|
## Procedure
|
|
29
30
|
|
|
@@ -36,7 +36,9 @@ Skip this only if the task explicitly says to attach to an existing session.
|
|
|
36
36
|
## Do
|
|
37
37
|
|
|
38
38
|
- Crawl only public, high-signal company pages.
|
|
39
|
-
-
|
|
39
|
+
- Use your judgment on each email candidate: only emit an email lead when public evidence identifies one specific human owner of the address.
|
|
40
|
+
- Extract high-quality named human emails, contact forms, public names/titles, source URL, evidence, and warnings.
|
|
41
|
+
- If an address is shared, role-based, departmental, generic, blocked, or not tied to a visible named human, do not emit it as an email lead; emit a `contact_path` if useful.
|
|
40
42
|
- Emit JSON/JSONL matching `templates/lead-schema.json`.
|
|
41
43
|
- Run `npx public-leads validate --input <file>` before returning a result.
|
|
42
44
|
- Return file paths and terminal status, not a prose-only summary.
|
|
@@ -26,7 +26,9 @@ Skip this only if the task explicitly says to attach to an existing session.
|
|
|
26
26
|
## Do
|
|
27
27
|
|
|
28
28
|
- Crawl only public, high-signal company pages.
|
|
29
|
-
-
|
|
29
|
+
- Use your judgment on each email candidate: only emit an email lead when public evidence identifies one specific human owner of the address.
|
|
30
|
+
- Extract high-quality named human emails, contact forms, public names/titles, source URL, evidence, and warnings.
|
|
31
|
+
- If an address is shared, role-based, departmental, generic, blocked, or not tied to a visible named human, do not emit it as an email lead; emit a `contact_path` if useful.
|
|
30
32
|
- Emit JSON/JSONL matching `templates/lead-schema.json`.
|
|
31
33
|
- Run `npx public-leads validate --input <file>` before returning a result.
|
|
32
34
|
- Return file paths and terminal status, not a prose-only summary.
|
package/AGENTS.md
CHANGED
|
@@ -4,7 +4,8 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
4
4
|
|
|
5
5
|
## Hard Limits
|
|
6
6
|
|
|
7
|
-
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt.
|
|
7
|
+
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt. The primary goal is named people, not generic company inboxes.
|
|
8
|
+
- [H8] Apply coding-agent judgment to every email candidate. An email may pass only when public source evidence identifies one specific human owner of that email. Shared, role, departmental, generic, blocked, unknown-owner, or unnamed person-like emails must not be emitted as email leads.
|
|
8
9
|
- [H2] Respect robots.txt, terms, rate limits, and site intent. If a page blocks crawling or is not public, record a warning and move on.
|
|
9
10
|
- [H3] Never send outreach from this harness. The output is reviewable lead records and ingest-ready artifacts, not email campaigns.
|
|
10
11
|
- [H4] Use file-backed artifacts before ingest. A subagent prose summary is not enough; write validated JSON/JSONL first, then ingest.
|
|
@@ -18,7 +19,7 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
18
19
|
- [D2] Use deterministic local helpers when they can validate, normalize, manifest, preflight, postflight, or ingest artifacts.
|
|
19
20
|
- [D3] Read the active mode file before executing. Mode files own output shapes and gates.
|
|
20
21
|
- [D4] Prefer official company websites and high-signal pages: home, contact, about, team, leadership, people, press, blog, careers, and legal pages.
|
|
21
|
-
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`.
|
|
22
|
+
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`. Reject generic catch-all inboxes such as `info@`, `hello@`, `contact@`, `support@`, `team@`, and similar aliases; if no named human email is available, prefer a `contact_path` record instead.
|
|
22
23
|
|
|
23
24
|
## Procedure
|
|
24
25
|
|
package/CLAUDE.md
CHANGED
|
@@ -4,7 +4,8 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
4
4
|
|
|
5
5
|
## Hard Limits
|
|
6
6
|
|
|
7
|
-
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt.
|
|
7
|
+
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt. The primary goal is named people, not generic company inboxes.
|
|
8
|
+
- [H8] Apply coding-agent judgment to every email candidate. An email may pass only when public source evidence identifies one specific human owner of that email. Shared, role, departmental, generic, blocked, unknown-owner, or unnamed person-like emails must not be emitted as email leads.
|
|
8
9
|
- [H2] Respect robots.txt, terms, rate limits, and site intent. If a page blocks crawling or is not public, record a warning and move on.
|
|
9
10
|
- [H3] Never send outreach from this harness. The output is reviewable lead records and ingest-ready artifacts, not email campaigns.
|
|
10
11
|
- [H4] Use file-backed artifacts before ingest. A subagent prose summary is not enough; write validated JSON/JSONL first, then ingest.
|
|
@@ -18,7 +19,7 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
18
19
|
- [D2] Use deterministic local helpers when they can validate, normalize, manifest, preflight, postflight, or ingest artifacts.
|
|
19
20
|
- [D3] Read the active mode file before executing. Mode files own output shapes and gates.
|
|
20
21
|
- [D4] Prefer official company websites and high-signal pages: home, contact, about, team, leadership, people, press, blog, careers, and legal pages.
|
|
21
|
-
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`.
|
|
22
|
+
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`. Reject generic catch-all inboxes such as `info@`, `hello@`, `contact@`, `support@`, `team@`, and similar aliases; if no named human email is available, prefer a `contact_path` record instead.
|
|
22
23
|
|
|
23
24
|
## Procedure
|
|
24
25
|
|
package/README.md
CHANGED
|
@@ -6,11 +6,14 @@ Agentic public-web lead discovery harness for portable, source-backed lead artif
|
|
|
6
6
|
|
|
7
7
|
- Crawls public company websites through agent workflows.
|
|
8
8
|
- Produces source-backed lead artifacts matching the local lead-ingest contract.
|
|
9
|
-
- Validates lead JSON/JSONL before database handoff
|
|
9
|
+
- Validates lead JSON/JSONL before database handoff and rejects generic catch-all inboxes such as `info@` and `hello@`.
|
|
10
10
|
- Builds a local manifest for batch auditability.
|
|
11
11
|
- Submits validated payloads to a configured ingest API.
|
|
12
12
|
- Ships OpenCode, Claude Code, Cursor, Codex, and Pi harness config from one `iso/` source.
|
|
13
13
|
|
|
14
|
+
The harness is optimized to find named people who can actually be contacted. When only a general company contact path exists, it should emit a `contact_path` record rather than a generic organizational inbox.
|
|
15
|
+
CLI summaries distinguish total reviewable records from `goodLeads`; only non-generic `person` email records with a named human owner visible in the evidence count as good leads. Role, shared, departmental, unknown-owner, blocked, unsupported, or unnamed person-like emails are rejected by validation.
|
|
16
|
+
|
|
14
17
|
## Core Commands
|
|
15
18
|
|
|
16
19
|
```bash
|
|
@@ -68,7 +71,7 @@ gh run watch
|
|
|
68
71
|
You can also publish by creating a GitHub release for the package version:
|
|
69
72
|
|
|
70
73
|
```bash
|
|
71
|
-
gh release create v0.1.
|
|
74
|
+
gh release create v0.1.6 --title v0.1.6 --generate-notes
|
|
72
75
|
```
|
|
73
76
|
|
|
74
77
|
The package version must not already exist on npm.
|
|
@@ -51,7 +51,7 @@ write('package.json', JSON.stringify({
|
|
|
51
51
|
'update-harness': 'npm install @agent-pattern-labs/leads-rig@latest && public-leads sync',
|
|
52
52
|
},
|
|
53
53
|
dependencies: {
|
|
54
|
-
'@agent-pattern-labs/leads-rig': '^0.1.
|
|
54
|
+
'@agent-pattern-labs/leads-rig': '^0.1.6',
|
|
55
55
|
},
|
|
56
56
|
engines: {
|
|
57
57
|
node: '>=20.6.0',
|
package/bin/lead-harness.mjs
CHANGED
|
@@ -23,80 +23,80 @@ const commands = {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const helperAliases = {
|
|
26
|
-
'trace:list': ['@
|
|
27
|
-
'trace:stats': ['@
|
|
28
|
-
'trace:show': ['@
|
|
29
|
-
'guard:audit': ['@
|
|
30
|
-
'guard:explain': ['@
|
|
31
|
-
'ledger:status': ['@
|
|
32
|
-
'ledger:rebuild': ['@
|
|
33
|
-
'ledger:verify': ['@
|
|
34
|
-
'capabilities:list': ['@
|
|
35
|
-
'capabilities:explain': ['@
|
|
36
|
-
'capabilities:check': ['@
|
|
37
|
-
'context:list': ['@
|
|
38
|
-
'context:explain': ['@
|
|
39
|
-
'context:plan': ['@
|
|
40
|
-
'context:check': ['@
|
|
41
|
-
'context:render': ['@
|
|
42
|
-
'cache:key': ['@
|
|
43
|
-
'cache:has': ['@
|
|
44
|
-
'cache:get': ['@
|
|
45
|
-
'cache:put': ['@
|
|
46
|
-
'cache:status': ['@
|
|
47
|
-
'cache:list': ['@
|
|
48
|
-
'cache:verify': ['@
|
|
49
|
-
'cache:prune': ['@
|
|
50
|
-
'index:build': ['@
|
|
51
|
-
'index:status': ['@
|
|
52
|
-
'index:query': ['@
|
|
53
|
-
'index:has': ['@
|
|
54
|
-
'index:verify': ['@
|
|
55
|
-
'facts:build': ['@
|
|
56
|
-
'facts:status': ['@
|
|
57
|
-
'facts:query': ['@
|
|
58
|
-
'facts:has': ['@
|
|
59
|
-
'facts:verify': ['@
|
|
60
|
-
'score:compute': ['@
|
|
61
|
-
'score:verify': ['@
|
|
62
|
-
'score:check': ['@
|
|
63
|
-
'score:gate': ['@
|
|
64
|
-
'score:compare': ['@
|
|
65
|
-
'score:explain': ['@
|
|
66
|
-
'canon:normalize': ['@
|
|
67
|
-
'canon:key': ['@
|
|
68
|
-
'canon:compare': ['@
|
|
69
|
-
'canon:explain': ['@
|
|
70
|
-
'preflight:plan': ['@
|
|
71
|
-
'preflight:check': ['@
|
|
72
|
-
'preflight:explain': ['@
|
|
73
|
-
'postflight:status': ['@
|
|
74
|
-
'postflight:check': ['@
|
|
75
|
-
'postflight:explain': ['@
|
|
76
|
-
'timeline:status': ['@
|
|
77
|
-
'timeline:build': ['@
|
|
78
|
-
'timeline:plan': ['@
|
|
79
|
-
'timeline:due': ['@
|
|
80
|
-
'timeline:check': ['@
|
|
81
|
-
'timeline:verify': ['@
|
|
82
|
-
'prioritize:status': ['@
|
|
83
|
-
'prioritize:items': ['@
|
|
84
|
-
'prioritize:build': ['@
|
|
85
|
-
'prioritize:rank': ['@
|
|
86
|
-
'prioritize:select': ['@
|
|
87
|
-
'prioritize:check': ['@
|
|
88
|
-
'prioritize:verify': ['@
|
|
89
|
-
'lineage:status': ['@
|
|
90
|
-
'lineage:record': ['@
|
|
91
|
-
'lineage:check': ['@
|
|
92
|
-
'lineage:stale': ['@
|
|
93
|
-
'lineage:verify': ['@
|
|
94
|
-
'redact:scan': ['@
|
|
95
|
-
'redact:verify': ['@
|
|
96
|
-
'redact:apply': ['@
|
|
97
|
-
'migrate:plan': ['@
|
|
98
|
-
'migrate:apply': ['@
|
|
99
|
-
'migrate:check': ['@
|
|
26
|
+
'trace:list': ['@agent-pattern-labs/iso-trace', 'list'],
|
|
27
|
+
'trace:stats': ['@agent-pattern-labs/iso-trace', 'stats'],
|
|
28
|
+
'trace:show': ['@agent-pattern-labs/iso-trace', 'show'],
|
|
29
|
+
'guard:audit': ['@agent-pattern-labs/iso-guard', 'audit'],
|
|
30
|
+
'guard:explain': ['@agent-pattern-labs/iso-guard', 'explain'],
|
|
31
|
+
'ledger:status': ['@agent-pattern-labs/iso-ledger', 'status'],
|
|
32
|
+
'ledger:rebuild': ['@agent-pattern-labs/iso-ledger', 'rebuild'],
|
|
33
|
+
'ledger:verify': ['@agent-pattern-labs/iso-ledger', 'verify'],
|
|
34
|
+
'capabilities:list': ['@agent-pattern-labs/iso-capabilities', 'list'],
|
|
35
|
+
'capabilities:explain': ['@agent-pattern-labs/iso-capabilities', 'explain'],
|
|
36
|
+
'capabilities:check': ['@agent-pattern-labs/iso-capabilities', 'check'],
|
|
37
|
+
'context:list': ['@agent-pattern-labs/iso-context', 'list'],
|
|
38
|
+
'context:explain': ['@agent-pattern-labs/iso-context', 'explain'],
|
|
39
|
+
'context:plan': ['@agent-pattern-labs/iso-context', 'plan'],
|
|
40
|
+
'context:check': ['@agent-pattern-labs/iso-context', 'check'],
|
|
41
|
+
'context:render': ['@agent-pattern-labs/iso-context', 'render'],
|
|
42
|
+
'cache:key': ['@agent-pattern-labs/iso-cache', 'key'],
|
|
43
|
+
'cache:has': ['@agent-pattern-labs/iso-cache', 'has'],
|
|
44
|
+
'cache:get': ['@agent-pattern-labs/iso-cache', 'get'],
|
|
45
|
+
'cache:put': ['@agent-pattern-labs/iso-cache', 'put'],
|
|
46
|
+
'cache:status': ['@agent-pattern-labs/iso-cache', 'status'],
|
|
47
|
+
'cache:list': ['@agent-pattern-labs/iso-cache', 'list'],
|
|
48
|
+
'cache:verify': ['@agent-pattern-labs/iso-cache', 'verify'],
|
|
49
|
+
'cache:prune': ['@agent-pattern-labs/iso-cache', 'prune'],
|
|
50
|
+
'index:build': ['@agent-pattern-labs/iso-index', 'build'],
|
|
51
|
+
'index:status': ['@agent-pattern-labs/iso-index', 'status'],
|
|
52
|
+
'index:query': ['@agent-pattern-labs/iso-index', 'query'],
|
|
53
|
+
'index:has': ['@agent-pattern-labs/iso-index', 'has'],
|
|
54
|
+
'index:verify': ['@agent-pattern-labs/iso-index', 'verify'],
|
|
55
|
+
'facts:build': ['@agent-pattern-labs/iso-facts', 'build'],
|
|
56
|
+
'facts:status': ['@agent-pattern-labs/iso-facts', 'status'],
|
|
57
|
+
'facts:query': ['@agent-pattern-labs/iso-facts', 'query'],
|
|
58
|
+
'facts:has': ['@agent-pattern-labs/iso-facts', 'has'],
|
|
59
|
+
'facts:verify': ['@agent-pattern-labs/iso-facts', 'verify'],
|
|
60
|
+
'score:compute': ['@agent-pattern-labs/iso-score', 'compute'],
|
|
61
|
+
'score:verify': ['@agent-pattern-labs/iso-score', 'verify'],
|
|
62
|
+
'score:check': ['@agent-pattern-labs/iso-score', 'check'],
|
|
63
|
+
'score:gate': ['@agent-pattern-labs/iso-score', 'gate'],
|
|
64
|
+
'score:compare': ['@agent-pattern-labs/iso-score', 'compare'],
|
|
65
|
+
'score:explain': ['@agent-pattern-labs/iso-score', 'explain'],
|
|
66
|
+
'canon:normalize': ['@agent-pattern-labs/iso-canon', 'normalize'],
|
|
67
|
+
'canon:key': ['@agent-pattern-labs/iso-canon', 'key'],
|
|
68
|
+
'canon:compare': ['@agent-pattern-labs/iso-canon', 'compare'],
|
|
69
|
+
'canon:explain': ['@agent-pattern-labs/iso-canon', 'explain'],
|
|
70
|
+
'preflight:plan': ['@agent-pattern-labs/iso-preflight', 'plan'],
|
|
71
|
+
'preflight:check': ['@agent-pattern-labs/iso-preflight', 'check'],
|
|
72
|
+
'preflight:explain': ['@agent-pattern-labs/iso-preflight', 'explain'],
|
|
73
|
+
'postflight:status': ['@agent-pattern-labs/iso-postflight', 'status'],
|
|
74
|
+
'postflight:check': ['@agent-pattern-labs/iso-postflight', 'check'],
|
|
75
|
+
'postflight:explain': ['@agent-pattern-labs/iso-postflight', 'explain'],
|
|
76
|
+
'timeline:status': ['@agent-pattern-labs/iso-timeline', 'status'],
|
|
77
|
+
'timeline:build': ['@agent-pattern-labs/iso-timeline', 'build'],
|
|
78
|
+
'timeline:plan': ['@agent-pattern-labs/iso-timeline', 'plan'],
|
|
79
|
+
'timeline:due': ['@agent-pattern-labs/iso-timeline', 'due'],
|
|
80
|
+
'timeline:check': ['@agent-pattern-labs/iso-timeline', 'check'],
|
|
81
|
+
'timeline:verify': ['@agent-pattern-labs/iso-timeline', 'verify'],
|
|
82
|
+
'prioritize:status': ['@agent-pattern-labs/iso-prioritize', 'status'],
|
|
83
|
+
'prioritize:items': ['@agent-pattern-labs/iso-prioritize', 'items'],
|
|
84
|
+
'prioritize:build': ['@agent-pattern-labs/iso-prioritize', 'build'],
|
|
85
|
+
'prioritize:rank': ['@agent-pattern-labs/iso-prioritize', 'rank'],
|
|
86
|
+
'prioritize:select': ['@agent-pattern-labs/iso-prioritize', 'select'],
|
|
87
|
+
'prioritize:check': ['@agent-pattern-labs/iso-prioritize', 'check'],
|
|
88
|
+
'prioritize:verify': ['@agent-pattern-labs/iso-prioritize', 'verify'],
|
|
89
|
+
'lineage:status': ['@agent-pattern-labs/iso-lineage', 'status'],
|
|
90
|
+
'lineage:record': ['@agent-pattern-labs/iso-lineage', 'record'],
|
|
91
|
+
'lineage:check': ['@agent-pattern-labs/iso-lineage', 'check'],
|
|
92
|
+
'lineage:stale': ['@agent-pattern-labs/iso-lineage', 'stale'],
|
|
93
|
+
'lineage:verify': ['@agent-pattern-labs/iso-lineage', 'verify'],
|
|
94
|
+
'redact:scan': ['@agent-pattern-labs/iso-redact', 'scan'],
|
|
95
|
+
'redact:verify': ['@agent-pattern-labs/iso-redact', 'verify'],
|
|
96
|
+
'redact:apply': ['@agent-pattern-labs/iso-redact', 'apply'],
|
|
97
|
+
'migrate:plan': ['@agent-pattern-labs/iso-migrate', 'plan'],
|
|
98
|
+
'migrate:apply': ['@agent-pattern-labs/iso-migrate', 'apply'],
|
|
99
|
+
'migrate:check': ['@agent-pattern-labs/iso-migrate', 'check'],
|
|
100
100
|
};
|
|
101
101
|
|
|
102
102
|
const [, , cmd, ...rest] = process.argv;
|
|
@@ -161,7 +161,7 @@ function runIsoCli(pkgName, args) {
|
|
|
161
161
|
|
|
162
162
|
function defaultIsoArgs(pkgName, subcommand, args) {
|
|
163
163
|
const defaults = [];
|
|
164
|
-
if (pkgName === '@
|
|
164
|
+
if (pkgName === '@agent-pattern-labs/iso-trace') {
|
|
165
165
|
if (!hasFlag(args, '--cwd')) defaults.push('--cwd', PROJECT_DIR);
|
|
166
166
|
if ((subcommand === 'list' || subcommand === 'stats') && !hasFlag(args, '--since')) {
|
|
167
167
|
defaults.push('--since', '7d');
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -68,10 +68,10 @@ domain input
|
|
|
68
68
|
| `scripts/validate-leads.mjs` | Normalizes and validates JSON/JSONL lead artifacts |
|
|
69
69
|
| `scripts/manifest.mjs` | Records validated batches in `data/lead-manifest.json` |
|
|
70
70
|
| `scripts/ingest.mjs` | Posts to the configured ingest endpoint |
|
|
71
|
-
| `scripts/batch-orchestrator.mjs` | Durable batch runner using `@
|
|
71
|
+
| `scripts/batch-orchestrator.mjs` | Durable batch runner using `@agent-pattern-labs/iso-orchestrator` |
|
|
72
72
|
| `verify-pipeline.mjs` | Repo/consumer health gate |
|
|
73
73
|
|
|
74
|
-
The package also carries the `@
|
|
74
|
+
The package also carries the `@agent-pattern-labs/iso-*` helper ecosystem for trace, guard, ledger, cache, canon, context, preflight, postflight, prioritize, lineage, redact, migrate, score, and timeline commands.
|
|
75
75
|
|
|
76
76
|
## Data Contract
|
|
77
77
|
|
|
@@ -82,4 +82,4 @@ The package also carries the `@razroo/iso-*` helper ecosystem for trace, guard,
|
|
|
82
82
|
- page visits
|
|
83
83
|
- ingest requests
|
|
84
84
|
|
|
85
|
-
The validator intentionally accepts the same defaults the local runtime normalizes, but it fails missing source evidence, invalid URL fields, invalid `emailType`, invalid `verificationStatus`, invalid confidence, and person
|
|
85
|
+
The validator intentionally accepts the same defaults the local runtime normalizes, but it fails missing source evidence, invalid URL fields, invalid `emailType`, invalid `verificationStatus`, invalid confidence, person leads without email, and generic catch-all inboxes such as `info@`, `hello@`, or similar organizational aliases. Any email record must be a named `person` lead with a non-generic email and a human owner visible in the evidence; role inboxes, unknown-owner emails, blocked emails, unsupported emails, and unnamed person-like emails fail validation. Summaries expose `goodLeadCount`, which only counts those high-quality named human email records.
|
package/docs/CONSTRUCTION.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
| Deterministic helpers | `scripts/crawl.mjs`, `scripts/pipeline.mjs`, `scripts/validate-leads.mjs`, `scripts/manifest.mjs`, `scripts/ingest.mjs`, `scripts/batch-orchestrator.mjs` |
|
|
15
15
|
| Consumer scaffold | `create-public-leads-harness <dir>` writes local config, input, output, and ignore files |
|
|
16
16
|
| Consumer sync | `public-leads sync` symlinks shared harness files from the installed package |
|
|
17
|
-
| Batch orchestration | `batch/batch-runner.sh` delegates to `@
|
|
17
|
+
| Batch orchestration | `batch/batch-runner.sh` delegates to `@agent-pattern-labs/iso-orchestrator` with bounded parallelism |
|
|
18
18
|
| Verification gates | `npm run verify`, `npm run smoke:iso`, sample validate/manifest/ingest, `npm pack` |
|
|
19
19
|
|
|
20
20
|
## Maintainer Rules
|
|
@@ -37,4 +37,4 @@
|
|
|
37
37
|
6. Run `npm audit`.
|
|
38
38
|
7. Run `npm pack` and confirm generated runtime surfaces are included.
|
|
39
39
|
8. Scaffold a clean consumer project and test install-time sync from the packed package or source tree.
|
|
40
|
-
9. Publish through GitHub Actions with `gh workflow run publish.yml --ref main`, or create a published release with `gh release create v0.1.
|
|
40
|
+
9. Publish through GitHub Actions with `gh workflow run publish.yml --ref main`, or create a published release with `gh release create v0.1.6 --title v0.1.6 --generate-notes`.
|
|
@@ -38,7 +38,9 @@ Skip this only if the task explicitly says to attach to an existing session.
|
|
|
38
38
|
## Do
|
|
39
39
|
|
|
40
40
|
- Crawl only public, high-signal company pages.
|
|
41
|
-
-
|
|
41
|
+
- Use your judgment on each email candidate: only emit an email lead when public evidence identifies one specific human owner of the address.
|
|
42
|
+
- Extract high-quality named human emails, contact forms, public names/titles, source URL, evidence, and warnings.
|
|
43
|
+
- If an address is shared, role-based, departmental, generic, blocked, or not tied to a visible named human, do not emit it as an email lead; emit a `contact_path` if useful.
|
|
42
44
|
- Emit JSON/JSONL matching `templates/lead-schema.json`.
|
|
43
45
|
- Run `npx public-leads validate --input <file>` before returning a result.
|
|
44
46
|
- Return file paths and terminal status, not a prose-only summary.
|
package/iso/instructions.md
CHANGED
|
@@ -4,7 +4,8 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
4
4
|
|
|
5
5
|
## Hard Limits
|
|
6
6
|
|
|
7
|
-
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt.
|
|
7
|
+
- [H1] Only collect public-source business contact data. Do not infer, guess, brute-force, or enrich private email addresses. Every lead needs a source URL and evidence excerpt. The primary goal is named people, not generic company inboxes.
|
|
8
|
+
- [H8] Apply coding-agent judgment to every email candidate. An email may pass only when public source evidence identifies one specific human owner of that email. Shared, role, departmental, generic, blocked, unknown-owner, or unnamed person-like emails must not be emitted as email leads.
|
|
8
9
|
- [H2] Respect robots.txt, terms, rate limits, and site intent. If a page blocks crawling or is not public, record a warning and move on.
|
|
9
10
|
- [H3] Never send outreach from this harness. The output is reviewable lead records and ingest-ready artifacts, not email campaigns.
|
|
10
11
|
- [H4] Use file-backed artifacts before ingest. A subagent prose summary is not enough; write validated JSON/JSONL first, then ingest.
|
|
@@ -18,7 +19,7 @@ Agentic public-web lead discovery harness. It crawls company domains, extracts r
|
|
|
18
19
|
- [D2] Use deterministic local helpers when they can validate, normalize, manifest, preflight, postflight, or ingest artifacts.
|
|
19
20
|
- [D3] Read the active mode file before executing. Mode files own output shapes and gates.
|
|
20
21
|
- [D4] Prefer official company websites and high-signal pages: home, contact, about, team, leadership, people, press, blog, careers, and legal pages.
|
|
21
|
-
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`.
|
|
22
|
+
- [D5] Keep artifacts source-backed. Every emitted lead should include `domain`, `sourceUrl`, `evidence`, `emailType`, `extractionMethod`, `verificationStatus`, and `confidence`. Reject generic catch-all inboxes such as `info@`, `hello@`, `contact@`, `support@`, `team@`, and similar aliases; if no named human email is available, prefer a `contact_path` record instead.
|
|
22
23
|
|
|
23
24
|
## Procedure
|
|
24
25
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
import { lookup, resolveMx } from 'dns/promises';
|
|
3
3
|
import { setTimeout as sleep } from 'timers/promises';
|
|
4
|
-
import { cleanDomains, dedupeLeadRecords, mergeLeadRecords, normalizeDomain } from './leadharness-leads.mjs';
|
|
4
|
+
import { cleanDomains, dedupeLeadRecords, isGoodLead, isRejectedLeadEmail, mergeLeadRecords, normalizeDomain } from './leadharness-leads.mjs';
|
|
5
5
|
|
|
6
6
|
const DEFAULT_MAX_PAGES = 10;
|
|
7
7
|
const HARD_MAX_PAGES = 25;
|
|
@@ -366,7 +366,7 @@ function extractEmails(html) {
|
|
|
366
366
|
for (const value of values) {
|
|
367
367
|
for (const found of String(value || '').matchAll(EMAIL_RE)) {
|
|
368
368
|
const email = found[0].toLowerCase().replace(/^mailto:/, '').replace(/[.,;:!?()[\]{}<>"']+$/g, '');
|
|
369
|
-
if (email && !isLikelyAssetEmail(email)) emails.add(email);
|
|
369
|
+
if (email && !isLikelyAssetEmail(email) && !isRejectedLeadEmail(email)) emails.add(email);
|
|
370
370
|
}
|
|
371
371
|
}
|
|
372
372
|
return [...emails].sort();
|
|
@@ -575,6 +575,7 @@ function classifyEmailLocal(local) {
|
|
|
575
575
|
}
|
|
576
576
|
|
|
577
577
|
function isRelevantLead(lead, options) {
|
|
578
|
+
if (lead.email && !isGoodLead(lead)) return false;
|
|
578
579
|
if (!options.includeBlocked && lead.emailType === 'blocked') return false;
|
|
579
580
|
return lead.confidence >= options.minConfidence;
|
|
580
581
|
}
|
|
@@ -28,6 +28,37 @@ export const ALLOWED_VERIFICATION_STATUSES = new Set([
|
|
|
28
28
|
'blocked',
|
|
29
29
|
'unknown',
|
|
30
30
|
]);
|
|
31
|
+
export const REJECTED_EMAIL_LOCAL_PREFIXES = [
|
|
32
|
+
'admin',
|
|
33
|
+
'booking',
|
|
34
|
+
'bookings',
|
|
35
|
+
'business',
|
|
36
|
+
'contact',
|
|
37
|
+
'customerservice',
|
|
38
|
+
'customer-service',
|
|
39
|
+
'customersuccess',
|
|
40
|
+
'customer-success',
|
|
41
|
+
'events',
|
|
42
|
+
'hello',
|
|
43
|
+
'help',
|
|
44
|
+
'hi',
|
|
45
|
+
'info',
|
|
46
|
+
'inquiries',
|
|
47
|
+
'enquiries',
|
|
48
|
+
'media',
|
|
49
|
+
'office',
|
|
50
|
+
'outreach',
|
|
51
|
+
'partners',
|
|
52
|
+
'partnerships',
|
|
53
|
+
'press',
|
|
54
|
+
'sales',
|
|
55
|
+
'service',
|
|
56
|
+
'services',
|
|
57
|
+
'speaking',
|
|
58
|
+
'success',
|
|
59
|
+
'support',
|
|
60
|
+
'team',
|
|
61
|
+
];
|
|
31
62
|
|
|
32
63
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
33
64
|
|
|
@@ -232,6 +263,9 @@ export function validatePayload(payload, { allowEmpty = false } = {}) {
|
|
|
232
263
|
|
|
233
264
|
results.forEach((result, index) => {
|
|
234
265
|
validateResult(result, `results[${index}]`, issues);
|
|
266
|
+
result.leads.forEach((lead, leadIndex) => {
|
|
267
|
+
validateLead(lead, `results[${index}].leads[${leadIndex}]`, issues);
|
|
268
|
+
});
|
|
235
269
|
});
|
|
236
270
|
|
|
237
271
|
const errors = issues.filter((item) => item.severity === 'error').length;
|
|
@@ -259,6 +293,12 @@ export function validateLead(lead, path, issues) {
|
|
|
259
293
|
if (lead.email && !EMAIL_RE.test(lead.email)) {
|
|
260
294
|
issues.push(issue('error', `${path}.email`, 'invalid_email', 'email must be a valid email address when present'));
|
|
261
295
|
}
|
|
296
|
+
if (lead.email && isRejectedLeadEmail(lead.email)) {
|
|
297
|
+
issues.push(issue('error', `${path}.email`, 'generic_inbox_rejected', 'generic company inboxes such as info@, hello@, or support@ are not accepted; submit named people instead'));
|
|
298
|
+
}
|
|
299
|
+
if (lead.email && !isRejectedLeadEmail(lead.email) && ALLOWED_EMAIL_TYPES.has(lead.emailType) && !isGoodLead(lead)) {
|
|
300
|
+
issues.push(issue('error', `${path}.emailType`, 'non_person_email_rejected', 'email records must identify one named human visible in the evidence; role, unknown, blocked, unsupported, or unnamed person emails are not accepted'));
|
|
301
|
+
}
|
|
262
302
|
if (lead.emailType && !ALLOWED_EMAIL_TYPES.has(lead.emailType)) {
|
|
263
303
|
issues.push(issue('error', `${path}.emailType`, 'invalid_email_type', `emailType must be one of ${[...ALLOWED_EMAIL_TYPES].join(', ')}`));
|
|
264
304
|
}
|
|
@@ -344,11 +384,13 @@ export function summarizePayload(payload) {
|
|
|
344
384
|
const byType = {};
|
|
345
385
|
let confidenceTotal = 0;
|
|
346
386
|
let withEmail = 0;
|
|
387
|
+
let goodLeadCount = 0;
|
|
347
388
|
const uniqueEmails = new Set();
|
|
348
389
|
const mxVerifiedEmails = new Set();
|
|
349
390
|
for (const lead of leads) {
|
|
350
391
|
byType[lead.emailType || 'unknown'] = (byType[lead.emailType || 'unknown'] || 0) + 1;
|
|
351
392
|
confidenceTotal += Number.isFinite(lead.confidence) ? lead.confidence : 0;
|
|
393
|
+
if (isGoodLead(lead)) goodLeadCount++;
|
|
352
394
|
if (lead.email) {
|
|
353
395
|
withEmail++;
|
|
354
396
|
uniqueEmails.add(String(lead.email).toLowerCase());
|
|
@@ -362,6 +404,8 @@ export function summarizePayload(payload) {
|
|
|
362
404
|
domainCount: domains.length,
|
|
363
405
|
leadCount: leads.length,
|
|
364
406
|
resultCount: results.length,
|
|
407
|
+
goodLeadCount,
|
|
408
|
+
reviewOnlyLeadCount: Math.max(0, leads.length - goodLeadCount),
|
|
365
409
|
withEmail,
|
|
366
410
|
uniqueEmailCount: uniqueEmails.size,
|
|
367
411
|
mxVerifiedEmailCount: mxVerifiedEmails.size,
|
|
@@ -380,6 +424,7 @@ export function createManifestRecord({ inputPath, payload, validation, generated
|
|
|
380
424
|
generatedAt,
|
|
381
425
|
domains: payload.domains,
|
|
382
426
|
leadCount: payload.leads.length,
|
|
427
|
+
goodLeadCount: validation.summary?.goodLeadCount || 0,
|
|
383
428
|
resultCount: payload.results.length,
|
|
384
429
|
errorCount: payload.errors.length,
|
|
385
430
|
validation: {
|
|
@@ -611,7 +656,10 @@ function stableLeadKey(lead) {
|
|
|
611
656
|
}
|
|
612
657
|
|
|
613
658
|
function leadQualityScore(lead) {
|
|
614
|
-
|
|
659
|
+
const goodLead = isGoodLead(lead);
|
|
660
|
+
return (goodLead ? 50_000 : 0)
|
|
661
|
+
+ (lead?.email && !goodLead ? -20_000 : 0)
|
|
662
|
+
+ (lead?.confidence || 0) * 1000
|
|
615
663
|
+ verificationRank(lead?.verificationStatus) * 100
|
|
616
664
|
+ pagePriority(lead?.sourceUrl || '') * 10
|
|
617
665
|
+ (Array.isArray(lead?.sources) ? lead.sources.length : 0) * 5
|
|
@@ -685,6 +733,54 @@ export function fileHash(path) {
|
|
|
685
733
|
return createHash('sha256').update(readFileSync(path)).digest('hex');
|
|
686
734
|
}
|
|
687
735
|
|
|
736
|
+
export function isRejectedLeadEmail(email) {
|
|
737
|
+
const local = String(email || '').trim().toLowerCase().split('@')[0] || '';
|
|
738
|
+
return isRejectedLeadLocalPart(local);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function isRejectedLeadLocalPart(local) {
|
|
742
|
+
const value = normalizeRejectedLeadLocalPart(local);
|
|
743
|
+
if (!value) return false;
|
|
744
|
+
return REJECTED_EMAIL_LOCAL_PREFIXES.some((prefix) => {
|
|
745
|
+
if (value === prefix) return true;
|
|
746
|
+
if (!value.startsWith(prefix) || value.length === prefix.length) return false;
|
|
747
|
+
const next = value[prefix.length];
|
|
748
|
+
return next === '.' || next === '_' || next === '-' || next === '+' || /\d/.test(next);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
export function isGoodLead(lead) {
|
|
753
|
+
if (!lead || typeof lead !== 'object') return false;
|
|
754
|
+
if (stringValue(lead.emailType).toLowerCase() !== 'person') return false;
|
|
755
|
+
if (!lead.email || isRejectedLeadEmail(lead.email)) return false;
|
|
756
|
+
const contactName = stringValue(lead.contactName);
|
|
757
|
+
if (!contactName) return false;
|
|
758
|
+
if (!evidenceIdentifiesContact(lead, contactName)) return false;
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function evidenceIdentifiesContact(lead, contactName) {
|
|
763
|
+
const needle = compactComparable(contactName);
|
|
764
|
+
if (!needle) return false;
|
|
765
|
+
const evidence = [
|
|
766
|
+
lead.evidence,
|
|
767
|
+
...(Array.isArray(lead.sources) ? lead.sources.map((source) => source?.evidence) : []),
|
|
768
|
+
].map(compactComparable).join(' ');
|
|
769
|
+
return evidence.includes(needle);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function compactComparable(value) {
|
|
773
|
+
return stringValue(value).toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function normalizeRejectedLeadLocalPart(local) {
|
|
777
|
+
let value = String(local || '').trim().toLowerCase();
|
|
778
|
+
for (const noise of ['mailto', 'u003e', 'email']) {
|
|
779
|
+
if (value.startsWith(noise)) value = value.slice(noise.length);
|
|
780
|
+
}
|
|
781
|
+
return value.replace(/^[>._+-]+/, '');
|
|
782
|
+
}
|
|
783
|
+
|
|
688
784
|
export function issue(severity, path, code, message) {
|
|
689
785
|
return { severity, path, code, message };
|
|
690
786
|
}
|
package/modes/_shared.md
CHANGED
|
@@ -28,17 +28,21 @@ Required fields:
|
|
|
28
28
|
- Prioritize home, contact, about, team, leadership, people, press, blog, careers, and legal pages.
|
|
29
29
|
- Respect robots.txt, paywalls, login walls, and obvious anti-scraping notices.
|
|
30
30
|
- Do not infer email formats. Do not brute-force guessed addresses.
|
|
31
|
+
- Use coding-agent judgment for every email candidate. Only emit an email lead when the source evidence identifies one specific human behind that address.
|
|
32
|
+
- Prefer named people over organizational inboxes. Do not emit generic catch-all emails such as `info@`, `hello@`, `contact@`, `support@`, `team@`, or similar aliases. If only a general contact path exists, emit `contact_path` instead.
|
|
33
|
+
- Reject email records that are role-based, shared, departmental, unknown ownership, blocked operational inboxes, or person-like but missing a visible human name in the source evidence.
|
|
31
34
|
- Keep contact forms as `emailType: "contact_path"` with empty `email`.
|
|
32
35
|
- Mark operational no-contact inboxes such as `noreply`, `abuse`, `security`, and `legal` as `blocked` with confidence `0`.
|
|
33
36
|
|
|
34
37
|
## Quality Heuristics
|
|
35
38
|
|
|
36
|
-
- `
|
|
37
|
-
- `
|
|
39
|
+
- `goodLeadCount`: counts only `person` email records with a non-generic email and named `contactName` visible in the evidence. Generic, role, unknown, blocked, unnamed, unsupported, and `contact_path` records are not good leads.
|
|
40
|
+
- `person`: named human with source context tying that person to the email address.
|
|
41
|
+
- `role`: legacy/review-only classification. Do not emit role email records in new artifacts.
|
|
38
42
|
- `contact_path`: public form or page where no email is available.
|
|
39
43
|
- `blocked`: public address that should not be used for outbound.
|
|
40
44
|
|
|
41
|
-
Confidence should reflect source quality, person specificity, domain match, and verification. Low-confidence
|
|
45
|
+
Confidence should reflect source quality, person specificity, domain match, and verification. Low-confidence contact paths are allowed if they preserve warnings and evidence; email leads should be high-quality named humans only.
|
|
42
46
|
|
|
43
47
|
## Local Commands
|
|
44
48
|
|
package/modes/batch.md
CHANGED
|
@@ -10,7 +10,7 @@ Prefer:
|
|
|
10
10
|
batch/batch-runner.sh --parallel 2
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The runner delegates to `scripts/batch-orchestrator.mjs`, which uses `@
|
|
13
|
+
The runner delegates to `scripts/batch-orchestrator.mjs`, which uses `@agent-pattern-labs/iso-orchestrator` for durable workflow records in `.public-leads-runs/`, bounded fan-out, and state updates.
|
|
14
14
|
|
|
15
15
|
## Input
|
|
16
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-pattern-labs/leads-rig",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Agentic public-web lead discovery harness with portable ingest artifacts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Razroo",
|
|
@@ -155,32 +155,32 @@
|
|
|
155
155
|
"fast-uri": "3.1.2"
|
|
156
156
|
},
|
|
157
157
|
"dependencies": {
|
|
158
|
-
"@
|
|
159
|
-
"@
|
|
160
|
-
"@
|
|
161
|
-
"@
|
|
162
|
-
"@
|
|
163
|
-
"@
|
|
164
|
-
"@
|
|
165
|
-
"@
|
|
166
|
-
"@
|
|
167
|
-
"@
|
|
168
|
-
"@
|
|
169
|
-
"@
|
|
170
|
-
"@
|
|
171
|
-
"@
|
|
172
|
-
"@
|
|
173
|
-
"@
|
|
174
|
-
"@
|
|
175
|
-
"@
|
|
176
|
-
"@
|
|
158
|
+
"@agent-pattern-labs/iso-cache": "^0.1.1",
|
|
159
|
+
"@agent-pattern-labs/iso-canon": "^0.1.1",
|
|
160
|
+
"@agent-pattern-labs/iso-capabilities": "^0.1.1",
|
|
161
|
+
"@agent-pattern-labs/iso-context": "^0.1.1",
|
|
162
|
+
"@agent-pattern-labs/iso-contract": "^0.1.1",
|
|
163
|
+
"@agent-pattern-labs/iso-facts": "^0.1.1",
|
|
164
|
+
"@agent-pattern-labs/iso-guard": "^0.1.1",
|
|
165
|
+
"@agent-pattern-labs/iso-index": "^0.1.1",
|
|
166
|
+
"@agent-pattern-labs/iso-ledger": "^0.1.1",
|
|
167
|
+
"@agent-pattern-labs/iso-lineage": "^0.1.1",
|
|
168
|
+
"@agent-pattern-labs/iso-migrate": "^0.1.1",
|
|
169
|
+
"@agent-pattern-labs/iso-orchestrator": "^0.2.1",
|
|
170
|
+
"@agent-pattern-labs/iso-postflight": "^0.1.1",
|
|
171
|
+
"@agent-pattern-labs/iso-preflight": "^0.1.1",
|
|
172
|
+
"@agent-pattern-labs/iso-prioritize": "^0.1.1",
|
|
173
|
+
"@agent-pattern-labs/iso-redact": "^0.1.1",
|
|
174
|
+
"@agent-pattern-labs/iso-score": "^0.1.1",
|
|
175
|
+
"@agent-pattern-labs/iso-timeline": "^0.1.1",
|
|
176
|
+
"@agent-pattern-labs/iso-trace": "^0.5.1",
|
|
177
177
|
"playwright": "^1.58.1"
|
|
178
178
|
},
|
|
179
179
|
"devDependencies": {
|
|
180
|
-
"@
|
|
181
|
-
"@
|
|
182
|
-
"@
|
|
183
|
-
"@
|
|
184
|
-
"@
|
|
180
|
+
"@agent-pattern-labs/agentmd": "^0.3.1",
|
|
181
|
+
"@agent-pattern-labs/iso": "^0.3.2",
|
|
182
|
+
"@agent-pattern-labs/iso-eval": "^0.4.1",
|
|
183
|
+
"@agent-pattern-labs/iso-harness": "^0.8.1",
|
|
184
|
+
"@agent-pattern-labs/iso-route": "^0.6.1"
|
|
185
185
|
}
|
|
186
186
|
}
|
|
@@ -6,7 +6,7 @@ import { existsSync } from 'fs';
|
|
|
6
6
|
import { mkdir, readFile, rm, writeFile } from 'fs/promises';
|
|
7
7
|
import { dirname, join, resolve } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { runWorkflow } from '@
|
|
9
|
+
import { runWorkflow } from '@agent-pattern-labs/iso-orchestrator';
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const PKG_ROOT = resolve(__dirname, '..');
|
package/scripts/crawl.mjs
CHANGED
|
@@ -57,7 +57,7 @@ async function main() {
|
|
|
57
57
|
console.log(JSON.stringify({ output: out, validation, summary: validation.summary }, null, 2));
|
|
58
58
|
} else {
|
|
59
59
|
console.log(`crawl: wrote ${relativeProjectPath(resolveProjectPath(out))}`);
|
|
60
|
-
console.log(`domains=${validation.summary.domainCount} leads=${validation.summary.leadCount} results=${validation.summary.resultCount} errors=${payload.errors.length}`);
|
|
60
|
+
console.log(`domains=${validation.summary.domainCount} leads=${validation.summary.leadCount} goodLeads=${validation.summary.goodLeadCount} results=${validation.summary.resultCount} errors=${payload.errors.length}`);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
if (!validation.ok) {
|
package/scripts/manifest.mjs
CHANGED
|
@@ -50,6 +50,7 @@ try {
|
|
|
50
50
|
batchCount: manifest.batches.length,
|
|
51
51
|
readyForIngest: manifest.batches.filter((item) => item.readyForIngest).length,
|
|
52
52
|
leadCount: manifest.batches.reduce((sum, item) => sum + item.leadCount, 0),
|
|
53
|
+
goodLeadCount: manifest.batches.reduce((sum, item) => sum + (item.goodLeadCount || 0), 0),
|
|
53
54
|
errorCount: manifest.batches.reduce((sum, item) => sum + item.validation.errors, 0),
|
|
54
55
|
warningCount: manifest.batches.reduce((sum, item) => sum + item.validation.warnings, 0),
|
|
55
56
|
};
|
|
@@ -60,8 +61,8 @@ try {
|
|
|
60
61
|
console.log(JSON.stringify({ manifest: relativeProjectPath(manifestPath), record, summary: manifest.summary }, null, 2));
|
|
61
62
|
} else {
|
|
62
63
|
console.log(`manifest: ${relativeProjectPath(manifestPath)}`);
|
|
63
|
-
console.log(`batch: ${record.id} leads=${record.leadCount} ready=${record.readyForIngest}`);
|
|
64
|
-
console.log(`summary: batches=${manifest.summary.batchCount} ready=${manifest.summary.readyForIngest} leads=${manifest.summary.leadCount}`);
|
|
64
|
+
console.log(`batch: ${record.id} leads=${record.leadCount} goodLeads=${record.goodLeadCount} ready=${record.readyForIngest}`);
|
|
65
|
+
console.log(`summary: batches=${manifest.summary.batchCount} ready=${manifest.summary.readyForIngest} leads=${manifest.summary.leadCount} goodLeads=${manifest.summary.goodLeadCount}`);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
process.exit(validation.ok ? 0 : 1);
|
package/scripts/pipeline.mjs
CHANGED
|
@@ -66,7 +66,7 @@ try {
|
|
|
66
66
|
const manifest = upsertManifest(manifestPath, out, payload, validation);
|
|
67
67
|
console.log(`pipeline: wrote ${relativeProjectPath(resolveProjectPath(out))}`);
|
|
68
68
|
console.log(`manifest: ${relativeProjectPath(resolveProjectPath(manifestPath))}`);
|
|
69
|
-
console.log(`domains=${validation.summary.domainCount} leads=${validation.summary.leadCount} results=${validation.summary.resultCount} errors=${payload.errors.length}`);
|
|
69
|
+
console.log(`domains=${validation.summary.domainCount} leads=${validation.summary.leadCount} goodLeads=${validation.summary.goodLeadCount} results=${validation.summary.resultCount} errors=${payload.errors.length}`);
|
|
70
70
|
|
|
71
71
|
if (opts.ingest || opts.upload) {
|
|
72
72
|
const ingestResult = await ingestPayload(payload, {
|
|
@@ -110,6 +110,7 @@ function upsertManifest(manifestPath, inputPath, payload, validation) {
|
|
|
110
110
|
batchCount: manifest.batches.length,
|
|
111
111
|
readyForIngest: manifest.batches.filter((item) => item.readyForIngest).length,
|
|
112
112
|
leadCount: manifest.batches.reduce((sum, item) => sum + item.leadCount, 0),
|
|
113
|
+
goodLeadCount: manifest.batches.reduce((sum, item) => sum + (item.goodLeadCount || 0), 0),
|
|
113
114
|
errorCount: manifest.batches.reduce((sum, item) => sum + item.validation.errors, 0),
|
|
114
115
|
warningCount: manifest.batches.reduce((sum, item) => sum + item.validation.warnings, 0),
|
|
115
116
|
};
|
|
@@ -58,7 +58,7 @@ try {
|
|
|
58
58
|
function printReport(report) {
|
|
59
59
|
const rel = relativeProjectPath(report.input);
|
|
60
60
|
console.log(`${report.ok ? 'OK' : 'ERROR'} ${rel}`);
|
|
61
|
-
console.log(`domains=${report.summary.domainCount} leads=${report.summary.leadCount} results=${report.summary.resultCount} avgConfidence=${report.summary.averageConfidence}`);
|
|
61
|
+
console.log(`domains=${report.summary.domainCount} leads=${report.summary.leadCount} goodLeads=${report.summary.goodLeadCount} results=${report.summary.resultCount} avgConfidence=${report.summary.averageConfidence}`);
|
|
62
62
|
if (Object.keys(report.summary.byType).length > 0) {
|
|
63
63
|
console.log(`types=${Object.entries(report.summary.byType).map(([type, count]) => `${type}:${count}`).join(', ')}`);
|
|
64
64
|
}
|