@audienti/cli 0.2.0-exora.31 → 0.2.0-exora.32
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/cli/audienti.mjs
CHANGED
|
@@ -95,7 +95,7 @@ Discovery: prospects list|get ID|timeline ID [--limit N]|observation create|cita
|
|
|
95
95
|
Qualification: campaigns qualification submit --file INPUT.json
|
|
96
96
|
Campaign summary: campaign summary [--workspace ID] (campaign counts per state, and per campaign its audience, offer, playbook, goal stage, people, engaged and at-goal counts)
|
|
97
97
|
Find prospects: campaign find CAMPAIGN_ID --count N --max-credits C (searches with the audience filters, checks each person, admits only fits; stops at N fits or the credit cap and reports the spend)
|
|
98
|
-
campaign check CAMPAIGN_ID --url LINKEDIN_URL [--request-id UUID] (checks one person the same way; reuse the request ID after an interruption)
|
|
98
|
+
campaign check CAMPAIGN_ID --url LINKEDIN_URL [--request-id UUID] [--source-url URL --source-industry TEXT [--source-kind website|register|other] [--source-location TEXT] [--source-note TEXT]] (checks one person the same way; reuse the request ID after an interruption; a source confirms a company with no LinkedIn page)
|
|
99
99
|
Target companies: campaign targets CAMPAIGN_ID [--limit N --after CURSOR] (reads the companies people must work at to join)
|
|
100
100
|
campaign targets CAMPAIGN_ID --add acme.com,linkedin.com/company/globex [--remove old.com] | --set FILE|- (one company per line; saves a new revision)
|
|
101
101
|
Playbooks: playbook list [--archived] [--limit N --cursor ID]|actions|show ID [--revision N]|save --file REQUEST.json|archive ID|restore ID|draft show ID|save ID --file REQUEST.json|discard ID [--expected-updated-at T]|publish ID [--request-id UUID]|delete ID|progress PARTICIPATION_ID|record --file REQUEST.json|event PARTICIPATION_ID --kind KIND --reason TEXT (audienti playbook SUBCOMMAND --help for the request shape)
|
|
@@ -25,6 +25,6 @@ export const campaignOperations={
|
|
|
25
25
|
campaign_pace_set:{schema:z.object({...locator,perDay:z.union([z.number().int().min(1).max(1000),z.literal('derived')]).optional(),maxCredits:z.number().int().min(1).max(100000).nullable().optional()}).strict().refine(a=>a.perDay!==undefined||a.maxCredits!==undefined,{message:'Send perDay, maxCredits or both.'}),method:'POST',path:a=>detail(a)+'/pace',body:a=>({...(a.perDay===undefined?{}:{perDay:a.perDay}),...(a.maxCredits===undefined?{}:{maxCredits:a.maxCredits})}),scoped:true,description:'Save a Campaign pace. Pass the number the user gave, or "derived" to follow the confirmed sending accounts. An owner number stays until changed and is still capped by LinkedIn account and mailbox limits. maxCredits saves the credits a day the user approved for finding (null removes it); each day\'s find task carries it.'},
|
|
26
26
|
campaign_targets_get:{schema:z.object({...locator,limit:z.number().int().min(1).max(500).optional(),after:z.string().regex(/^\d{1,7}$/).optional()}).strict(),method:'GET',path:a=>detail(a)+'/targets?'+qs(a),scoped:true,description:'Read a Campaign\'s target companies in pages of up to 500: domains and LinkedIn company URLs. Only people whose current company is one of them can join.'},
|
|
27
27
|
campaign_targets_change:{schema:z.object({...locator,expectedRevision:z.number().int().positive(),add:z.array(z.string()).optional(),remove:z.array(z.string()).optional(),set:z.array(z.string()).optional()}).strict().refine(a=>(a.set===undefined)!==(a.add===undefined&&a.remove===undefined),{message:'Send set, or add and or remove.'}),method:'POST',path:a=>detail(a)+'/targets',body:a=>({expectedRevision:a.expectedRevision,...Object.fromEntries(['add','remove','set'].filter(k=>a[k]!==undefined).map(k=>[k,a[k]]))}),scoped:true,description:'Change a Campaign\'s target companies: add or remove domains (acme.com) and LinkedIn company URLs, or replace them all with set. Saves a new Campaign revision; an empty set removes the targets.'},
|
|
28
|
-
campaign_prospect_check:{schema:z.object({...locator,url:z.string().max(1024),requestId:uuid,maxCharge:z.string().regex(/^\d{1,20}$/).optional()}).strict(),method:'POST',path:a=>detail(a)+'/prospect-checks',body:a=>({url:a.url,requestId:a.requestId,...(a.maxCharge!==undefined?{maxCharge:a.maxCharge}:{})}),scoped:true,recoverable:true,timeoutMs:90000,description:'Check one LinkedIn person URL for a Campaign and record the result. Fetches the person and current company (saved profiles are reused free; otherwise each fetch spends hosted credits), runs the pinned Audience rules and records a qualification with the profiles as evidence. outcome fit: admitted, or shortlisted while the Campaign is a Draft. held: an agent must judge a smart rule, a signal or an undecided rule. not_fit: a rule failed. already_found: already in or shortlisted for this Campaign; nothing written. charged and balance are pico USD (1 credit = 10,000,000,000). Generate requestId once and reuse it after an interruption so a retry never pays twice.'},
|
|
28
|
+
campaign_prospect_check:{schema:z.object({...locator,url:z.string().max(1024),requestId:uuid,maxCharge:z.string().regex(/^\d{1,20}$/).optional(),companySource:z.object({kind:z.enum(['website','register','other']),url:z.string().max(2048),industry:z.string().max(200),location:z.string().max(200).optional(),note:z.string().max(500).optional()}).strict().optional()}).strict(),method:'POST',path:a=>detail(a)+'/prospect-checks',body:a=>({url:a.url,requestId:a.requestId,...(a.maxCharge!==undefined?{maxCharge:a.maxCharge}:{}),...(a.companySource!==undefined?{companySource:a.companySource}:{})}),scoped:true,recoverable:true,timeoutMs:90000,description:'Check one LinkedIn person URL for a Campaign and record the result. Fetches the person and current company (saved profiles are reused free; otherwise each fetch spends hosted credits), runs the pinned Audience rules and records a qualification with the profiles as evidence. outcome fit: admitted, or shortlisted while the Campaign is a Draft. held: an agent must judge a smart rule, a signal or an undecided rule. not_fit: a rule failed. already_found: already in or shortlisted for this Campaign; nothing written. charged and balance are pico USD (1 credit = 10,000,000,000). Generate requestId once and reuse it after an interruption so a retry never pays twice. A company with no LinkedIn page cannot be read, so its industry rules stay undecided (reason company_page_missing). Send companySource {kind website|register|other, url, industry, location?, note?} from a page you fetched (its website, or a regulator register such as a central bank list of banks) to confirm it. The industry rule still applies to what the page states, and the receipt records the source.'},
|
|
29
29
|
campaign_successor:{schema:z.object({...locator,requestId:uuid,expectedRevision:z.number().int(),fields}).strict(),method:'POST',path:a=>detail(a)+'/successors',body:a=>({requestId:a.requestId,expectedRevision:a.expectedRevision,fields:a.fields}),scoped:true},
|
|
30
30
|
};
|
package/cli/campaigns.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {readJsonFile} from './json-file.mjs';
|
|
|
3
3
|
export async function campaignCli(args){
|
|
4
4
|
const position=[],flags={};for(let i=0;i<args.length;i++){
|
|
5
5
|
if(!args[i].startsWith('--')){position.push(args[i]);continue}
|
|
6
|
-
const key=args[i].slice(2);if(!['profile','workspace','file','request-id','expected-revision','revision','archived','limit','after','q','state','operation','expected-state','reason','per-day','count','max-credits','url','add','remove','set'].includes(key)||!args[i+1]||args[i+1].startsWith('--')||Object.hasOwn(flags,key))throw new Error('Unknown or incomplete campaign option.');
|
|
6
|
+
const key=args[i].slice(2);if(!['profile','workspace','file','request-id','expected-revision','revision','archived','limit','after','q','state','operation','expected-state','reason','per-day','count','max-credits','url','add','remove','set','source-url','source-kind','source-industry','source-location','source-note'].includes(key)||!args[i+1]||args[i+1].startsWith('--')||Object.hasOwn(flags,key))throw new Error('Unknown or incomplete campaign option.');
|
|
7
7
|
flags[key]=args[++i];
|
|
8
8
|
}
|
|
9
9
|
const command=position[1];
|
|
@@ -17,9 +17,13 @@ export async function campaignCli(args){
|
|
|
17
17
|
console.log(JSON.stringify({data:report}));return;
|
|
18
18
|
}
|
|
19
19
|
if(command==='check'){
|
|
20
|
-
if(position.length!==3||!flags.url)throw new Error('Use campaign check ID --url LINKEDIN_URL [--request-id UUID].');
|
|
20
|
+
if(position.length!==3||!flags.url)throw new Error('Use campaign check ID --url LINKEDIN_URL [--request-id UUID] [--source-url URL [--source-kind website|register|other] --source-industry TEXT [--source-location TEXT] [--source-note TEXT]].');
|
|
21
|
+
const sourceFlags=['source-url','source-kind','source-industry','source-location','source-note'].filter(key=>flags[key]!==undefined);
|
|
22
|
+
const missing=[['source-url','--source-url URL'],['source-industry','--source-industry TEXT']].filter(([key])=>flags[key]===undefined).map(([,text])=>text);
|
|
23
|
+
if(sourceFlags.length&&missing.length)throw new Error(`A company source needs its web address and the industry it states. Add ${missing.join(' and ')}.`);
|
|
24
|
+
const companySource=sourceFlags.length?{kind:String(flags['source-kind']??'website').toLowerCase(),url:flags['source-url'],industry:flags['source-industry'],...(flags['source-location']!==undefined?{location:flags['source-location']}:{}),...(flags['source-note']!==undefined?{note:flags['source-note']}:{})}:undefined;
|
|
21
25
|
const {randomUUID}=await import('node:crypto');
|
|
22
|
-
console.log(JSON.stringify(await callWorkspace('campaign_prospect_check',{workspaceId:flags.workspace,campaignId:position[2],url:flags.url,requestId:flags['request-id']??randomUUID()},configuration(flags.profile))));return;
|
|
26
|
+
console.log(JSON.stringify(await callWorkspace('campaign_prospect_check',{workspaceId:flags.workspace,campaignId:position[2],url:flags.url,requestId:flags['request-id']??randomUUID(),...(companySource?{companySource}:{})},configuration(flags.profile))));return;
|
|
23
27
|
}
|
|
24
28
|
if(command==='targets'){
|
|
25
29
|
if(position.length!==3)throw new Error('Use campaign targets ID [--add a.com,b.com] [--remove a.com] [--set FILE|-] [--expected-revision N].');
|
|
@@ -7,6 +7,7 @@ const subject=z.object({kind:z.enum(['person','company']),prospectId:uuid}).stri
|
|
|
7
7
|
const text=z.string().nullable().optional();
|
|
8
8
|
const fields=z.object({name:text,title:text,companyName:text,location:text,bio:text,domain:text,description:text,imageUrl:text}).strict();
|
|
9
9
|
const status=(values)=>z.object({status:z.enum(values),evidenceIds:z.array(uuid)}).strict();
|
|
10
|
+
const companyStatus=(values)=>z.object({status:z.enum(values),evidenceIds:z.array(uuid),source:z.object({kind:z.enum(['website','register','other']),url:z.string().max(2048),industry:z.string().max(200),location:z.string().max(200).optional(),note:z.string().max(500).optional()}).strict().optional()}).strict();
|
|
10
11
|
const root=a=>`/workspaces/${a.workspaceId}/prospects`;
|
|
11
12
|
const body=a=>Object.fromEntries(Object.entries(a).filter(([k])=>k!=='workspaceId'));
|
|
12
13
|
function qs(a){const values={};for(const[k,v]of Object.entries(a)){if(['workspaceId','prospectId'].includes(k)||v===undefined)continue;if(v&&typeof v==='object')for(const[s,x]of Object.entries(v))values[k+s[0].toUpperCase()+s.slice(1)]=String(x);else values[k]=String(v);}return new URLSearchParams(values);}
|
|
@@ -24,5 +25,5 @@ export const discoveryOperations={
|
|
|
24
25
|
prospect_record_observation:{schema:z.object({...request,kind:z.enum(['person','company']),prospectId:uuid.optional(),source:z.object({provider:z.string(),providerId:z.string().optional(),url:z.string().optional()}).strict(),fields,provenance:z.object({url:z.string(),excerpt:z.string().optional()}).strict().optional(),observedAt:z.string().nullable().optional(),skill:skill.optional()}).strict(),method:'POST',path:a=>root(a)+'/observations',body,scoped:true},
|
|
25
26
|
prospect_record_citation:{schema:z.object({...request,source:endpoint,target:endpoint,edgeType:z.enum(['works_for','works_at','worked_at','references']),roles:z.array(z.object({roleId:z.string(),title:z.string(),current:z.boolean(),startDate:text,endDate:text,employmentType:text,observedAt:text}).strict()).optional(),evidenceIds:z.array(uuid).optional(),employmentSelection:z.object({action:z.enum(['set_primary','clear']),roleId:z.string().optional(),evidenceHash:z.string().optional()}).strict().optional()}).strict(),method:'POST',path:a=>root(a)+'/citations',body,scoped:true},
|
|
26
27
|
prospect_record_evidence:{schema:z.object({...request,subject,campaignId:uuid.optional(),campaignRevision:z.number().int().positive().optional(),kind:z.enum(['signal','interpretation']),data:z.record(z.string(),z.unknown()),sourceUrl:text,observedAt:text,skill}).strict(),method:'POST',path:a=>root(a)+'/evidence',body,scoped:true},
|
|
27
|
-
campaign_submit_qualification:{schema:z.object({...request,campaignId:uuid,campaignRevision:z.number().int().positive(),prospectId:uuid,companyProspectId:uuid.optional(),companyIcp:
|
|
28
|
+
campaign_submit_qualification:{schema:z.object({...request,campaignId:uuid,campaignRevision:z.number().int().positive(),prospectId:uuid,companyProspectId:uuid.optional(),companyIcp:companyStatus(['pass','fail','unverified']),personIcp:status(['pass','fail','unverified']),signal:status(['match','no_match','unverified','not_required']),fit:z.object({status:z.enum(['high','moderate','low','no_fit','unscored']),evidenceIds:z.array(uuid),reason:z.string().optional()}).strict(),skill}).strict(),method:'POST',path:a=>`/workspaces/${a.workspaceId}/campaigns/${a.campaignId}/qualifications`,body:a=>Object.fromEntries(Object.entries(body(a)).filter(([k])=>k!=='campaignId')),scoped:true},
|
|
28
29
|
};
|
package/package.json
CHANGED
package/skills/audienti/SKILL.md
CHANGED
|
@@ -127,6 +127,15 @@ To check one person, run `audienti campaign check CAMPAIGN_ID --url LINKEDIN_URL
|
|
|
127
127
|
--request-id UUID` (MCP tool `campaign_prospect_check`). Reuse the request ID after an
|
|
128
128
|
interruption so a retry never pays twice.
|
|
129
129
|
|
|
130
|
+
If the person's company has no LinkedIn page, the check holds with "No company page; add a
|
|
131
|
+
source to confirm the industry." Read another page that states the company's industry, such
|
|
132
|
+
as its website or a regulator's register. Run the check again with `--source-url URL
|
|
133
|
+
--source-industry INDUSTRY` (add `--source-kind website|register|other`, website by default; add `--source-location
|
|
134
|
+
PLACE` or `--source-note TEXT` if useful). MCP: `companySource` on `campaign_prospect_check`.
|
|
135
|
+
The industry rule still applies, and the source is recorded on the receipt. A company the
|
|
136
|
+
campaign names in its targets passes the industry rule without a source. A held person is
|
|
137
|
+
not offered again until new evidence, such as a source, arrives.
|
|
138
|
+
|
|
130
139
|
`campaign find` moves on to the next person only after a definite answer: fit, held, not
|
|
131
140
|
a fit, already found, or a refusal about that person (a bad URL or no LinkedIn profile).
|
|
132
141
|
If a check is still running, its response is lost or the server fails, the command retries
|
package/source-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repository": "https://github.com/omalab/exora",
|
|
3
|
-
"sourceCommit": "
|
|
3
|
+
"sourceCommit": "adcf2d781bfc17d9e92557d8072db185631d1a96",
|
|
4
4
|
"files": {
|
|
5
5
|
"LICENSE": "220f297cfcd5c38eb64e6b4b4a77cab4ebc7f4686d4d99c6260a475d02ca11e5",
|
|
6
6
|
"README.md": "7ff32cc8ac89dd54b64d7b39c0b41b1f37e154b7ea10ad5a7bceefc3df77d87f",
|
|
@@ -16,21 +16,21 @@
|
|
|
16
16
|
"cli/attachments.mjs": "2fee6b4abbf82da9847d4a927a3d4d3ca947a198a903a78927596a2ea858cbf4",
|
|
17
17
|
"cli/audience-operations.mjs": "133b72dc6b9e3a6b4f173ce28f1524163f9c7b049505b885115f83b9e4af7170",
|
|
18
18
|
"cli/audiences.mjs": "3c377346efc1a8bdde432a16c2d19a3f51f34f3333d344d3a2bfa94c188a017d",
|
|
19
|
-
"cli/audienti.mjs": "
|
|
19
|
+
"cli/audienti.mjs": "b9aa625543270cd9104d7f2fc11aac5a65c419c4371fea4008c1a2b95ceeea03",
|
|
20
20
|
"cli/audit-operations.mjs": "afaf87d592a1e5f6bff2a8649a6a64a8f471950b7d99e98995d9205aa5910398",
|
|
21
21
|
"cli/audit.mjs": "a7becaed67c58b063e668b5e66844b6dc15c11a63b428faa171b542ad922c001",
|
|
22
22
|
"cli/budget-operations.mjs": "d74916551ef393e29734c6e13cf9021251e0ed126eeaa529e18cf2332146e1e0",
|
|
23
23
|
"cli/budgets.mjs": "683e06cb4d410c851286fbd1cdd4fb9f1902726c60fd4fcddb2c13d164786525",
|
|
24
24
|
"cli/campaign-find.mjs": "9c0a44c69ab7ad3e24a0a2edc97b8f3a14f602e3b6caf7e1943b8e1b93609c4a",
|
|
25
|
-
"cli/campaign-operations.mjs": "
|
|
26
|
-
"cli/campaigns.mjs": "
|
|
25
|
+
"cli/campaign-operations.mjs": "65c3576df673fee2a23bfbc9f56210973d17f0c882ebeeb27008a56090adb54f",
|
|
26
|
+
"cli/campaigns.mjs": "35aced0c07073ac82a48f6fe4fb2b9ba98ef48559c1ca19345f8ad061b115b19",
|
|
27
27
|
"cli/cohort-operations.mjs": "91b1d1fc48e75581bb315f42d735ef94e21687dc216f352337d8a5d180bb691e",
|
|
28
28
|
"cli/cohorts.mjs": "c71940903430f3e6834608f113534910b75a98b3e410a5942f04051607488485",
|
|
29
29
|
"cli/connection-registry-operations.mjs": "888ea440d00ffc9ed68d4cc084ff73a5a00d0e60bd6293baba8bb4539a25ae62",
|
|
30
30
|
"cli/content.mjs": "139dee5fd37fd89669c39e2120ac70a2e0286b207b055ff666f54ba3512ab061",
|
|
31
31
|
"cli/decision-operations.mjs": "0c4c2134c9615678def2b50f2a5254218b14f1174f1ce4e8ba7db78c751661af",
|
|
32
32
|
"cli/decision.mjs": "3d89d48b333e2620bce0191cf528ef25541ee841a7f8ae6d60249aead434b651",
|
|
33
|
-
"cli/discovery-operations.mjs": "
|
|
33
|
+
"cli/discovery-operations.mjs": "072a85a0c88de6cbef3c683da632b96f98ad2417f9100d94f58e430c7d046375",
|
|
34
34
|
"cli/discovery.mjs": "34b3794ee6ca539dbbccef77ec2085fd5411023046bdfb9b83e2537414542a41",
|
|
35
35
|
"cli/duplicate-operations.mjs": "118f067e2753887ba41b41d59b92c6b54c57eeff47f4adf662e3e1fc490f9ac3",
|
|
36
36
|
"cli/duplicates.mjs": "341e5c8dae67a819340abdad3502470577cf8b6375bf60acb00068c7188344a7",
|
|
@@ -88,10 +88,10 @@
|
|
|
88
88
|
"cli/work-operations.mjs": "66a6155964d1af264b4aa3851cf43b9373155887ee2f9bcac3eb97d9f4680157",
|
|
89
89
|
"cli/work.mjs": "751107ecc3de5a6be9db4a068cddc41f3ad8e77c87e59686eaf522862caf9e9f",
|
|
90
90
|
"cli/workspaces.mjs": "7de635a78f80d75421447cc62686ab4cde7779a9dd7d0bb55e48143a5e4c8365",
|
|
91
|
-
"package.json": "
|
|
91
|
+
"package.json": "f7f1104806bf78056b69ba9de55ba339d969a590befc5213cfb414512896b99f",
|
|
92
92
|
"skills/agent-rooms/SKILL.md": "08f917ff85fee1d23499a4499056ce845b39ce6727029b104819dad41ee87cc2",
|
|
93
93
|
"skills/agent-rooms/references/commands.md": "ef5afa5543ca9da967a147f638774647998ea1c1a2a821959f3bf87d54c292bd",
|
|
94
|
-
"skills/audienti/SKILL.md": "
|
|
94
|
+
"skills/audienti/SKILL.md": "7307267df9b9b0bd5c02d20f15eb12e206ca81d7fea95fe0a3f81ed197e5b40e",
|
|
95
95
|
"skills/audienti/references/helpers.md": "e27aff0aa07b92f575d617612ed3def824765bac6ce1304cf227a4aca223369a",
|
|
96
96
|
"skills/audienti/references/profile-workflows.md": "80669b75eb5e8aeb614ce55ac046236d671af0de3ddd238853324579d5a3b251",
|
|
97
97
|
"skills/audienti/references/workflow-receipt.md": "349f9a85472832b8bdc6a5d16c5b10b8e32d48d3e81523ad8d42f9a03b3655ff",
|