@audienti/cli 0.2.0-exora.26 → 0.2.0-exora.28
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 +5 -2
- package/cli/duplicate-operations.mjs +22 -0
- package/cli/duplicates.mjs +22 -0
- package/cli/workspaces.mjs +10 -4
- package/package.json +1 -1
- package/source-manifest.json +6 -4
package/cli/audienti.mjs
CHANGED
|
@@ -70,6 +70,7 @@ Discovery: prospects list|get ID|timeline ID [--limit N]|observation create|cita
|
|
|
70
70
|
prospects contacts list|record PERSON [--file INPUT.json] [--request-id UUID] --workspace ID
|
|
71
71
|
prospects contacts get|retire PERSON CONTACT --workspace ID
|
|
72
72
|
prospects suppression get|set ID --workspace ID
|
|
73
|
+
prospects duplicates list --workspace ID | get|merge|dismiss PERSON --workspace ID [--primary PROFILE_ID] (same name and photo: the newer record is held until you decide)
|
|
73
74
|
guardrails show|pause|resume --workspace ID
|
|
74
75
|
dnc list|add VALUE|remove VALUE --workspace ID
|
|
75
76
|
dnc import --file LIST.csv --workspace ID (at most 5,000 rows; reports added, skipped and invalid rows)
|
|
@@ -114,7 +115,8 @@ Search: workspace search --workspace ID --query TEXT [--people-only true] [--rec
|
|
|
114
115
|
Invitation commands: workspace invitation show|accept|decline|retry|cancel ID
|
|
115
116
|
Options: --workspace ID --name NAME --request-id UUID --email EMAIL --generation N
|
|
116
117
|
Optional private profile: --profile PATH (outside this repository), or the AUDIENTI_PROFILE variable. --profile wins.
|
|
117
|
-
Save an environment token: profile save --scope account:read|workspace:access|agents:manage --profile PATH
|
|
118
|
+
Save an environment token: profile save --scope account:read|workspace:read|workspace:access|agents:manage --profile PATH
|
|
119
|
+
Tokens: token show [--profile PATH] (what the token can do; workspace:read can look but is refused on every change)
|
|
118
120
|
Start local MCP stdio server: mcp (audienti mcp --help for the settings)
|
|
119
121
|
--json writes the API response envelope.
|
|
120
122
|
`;
|
|
@@ -177,6 +179,7 @@ async function main() {
|
|
|
177
179
|
if(args[0]==='budgets'){const {budgetsCli}=await import('./budgets.mjs');await budgetsCli(args);return;}
|
|
178
180
|
if(args[0]==='guardrails'||args[0]==='dnc'){const {guardrailsCli}=await import('./guardrails.mjs');await guardrailsCli(args);return;}
|
|
179
181
|
if(args[0]==='prospects'&&args[1]==='suppression'){const {suppressionCli}=await import('./suppression.mjs');await suppressionCli(args);return;}
|
|
182
|
+
if(args[0]==='prospects'&&args[1]==='duplicates'){const {duplicatesCli}=await import('./duplicates.mjs');await duplicatesCli(args);return;}
|
|
180
183
|
if(args[0]==='call'){const {callCli}=await import('./tools.mjs');await callCli(args);return;}
|
|
181
184
|
if(args[0]==='tools'){const {toolsCli}=await import('./tools.mjs');await toolsCli(args);return;}
|
|
182
185
|
if(['topics','posts'].includes(args[0])){const {contentCli}=await import('./content.mjs');await contentCli(args);return;}
|
|
@@ -201,7 +204,7 @@ async function main() {
|
|
|
201
204
|
if(args[0]==='offer'){const {offerCli}=await import('./offers.mjs');await offerCli(args);return;}
|
|
202
205
|
if (args[0] === 'agent') { const { agentCli } = await import('./agents.mjs'); await agentCli(args); return; }
|
|
203
206
|
if (isAssignmentCommand(args)) { await assignmentCli(args); return; }
|
|
204
|
-
if (['workspace', 'profile'].includes(args[0])) { const { workspaceCli } = await import('./workspaces.mjs'); await workspaceCli(args); return; }
|
|
207
|
+
if (['workspace', 'profile', 'token'].includes(args[0])) { const { workspaceCli } = await import('./workspaces.mjs'); await workspaceCli(args); return; }
|
|
205
208
|
if (args[0] === 'profiles') { const { profilesCli } = await import('./profiles.mjs'); await profilesCli(args); return; }
|
|
206
209
|
if (args[0] === 'skills') { const { skillsCli } = await import('./skills.mjs'); await skillsCli(args); return; }
|
|
207
210
|
if (args[0] === 'mcp' && args.length === 1) { await import('./mcp.mjs'); return; }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const uuid = z.string().uuid();
|
|
3
|
+
const located = { workspaceId: uuid.optional(), prospectId: uuid };
|
|
4
|
+
const path = a => `/workspaces/${a.workspaceId}/prospects/${a.prospectId}/duplicate`;
|
|
5
|
+
export const duplicateOperations = {
|
|
6
|
+
workspace_possible_duplicates: {
|
|
7
|
+
description: 'List the people in a workspace that look like the same real person as another record (same name and the same profile photo, or the same name, company and title). The newer record is held: no outreach until a decision. Open flags only.',
|
|
8
|
+
schema: z.object({ workspaceId: uuid.optional() }).strict(), method: 'GET', path: a => `/workspaces/${a.workspaceId}/possible-duplicates`, scoped: true,
|
|
9
|
+
},
|
|
10
|
+
workspace_prospect_duplicate: {
|
|
11
|
+
description: 'Read the possible-duplicate flag of one person: the other record, why they match, and whether this person is held. duplicate is null when there is no open flag.',
|
|
12
|
+
schema: z.object(located).strict(), method: 'GET', path, scoped: true,
|
|
13
|
+
},
|
|
14
|
+
workspace_prospect_duplicate_merge: {
|
|
15
|
+
description: 'Merge a possible duplicate into one person. The older record survives and keeps both LinkedIn profiles, the email, the observations and the timelines. The LinkedIn profile that outreach uses is the main channel and the other LinkedIn channel is retired. Set primaryProfileId to choose it; without a choice the suggestedPrimary of the flag applies (the profile of the person who has an email, else the newest). Set keepBoth to true to leave both channels active.',
|
|
16
|
+
schema: z.object({ ...located, primaryProfileId: uuid.optional(), keepBoth: z.boolean().optional() }).strict(), method: 'POST', path: a => `${path(a)}/merge`, body: ({ workspaceId, prospectId, ...body }) => body, scoped: true,
|
|
17
|
+
},
|
|
18
|
+
workspace_prospect_duplicate_dismiss: {
|
|
19
|
+
description: 'Say these two records are not the same person. The hold lifts and the pair is never flagged again.',
|
|
20
|
+
schema: z.object(located).strict(), method: 'POST', path: a => `${path(a)}/dismiss`, body: () => ({}), scoped: true,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { callWorkspace, configuration } from './workspaces.mjs';
|
|
2
|
+
// audienti prospects duplicates list | get ID | merge ID [--primary PROFILE_ID | --keep-both] | dismiss ID (all with --workspace ID)
|
|
3
|
+
export async function duplicatesCli(args) {
|
|
4
|
+
const flags = {}, positions = [], allowed = ['workspace', 'profile', 'primary'];
|
|
5
|
+
for (let i = 0; i < args.length; i++) {
|
|
6
|
+
const arg = args[i];
|
|
7
|
+
if (arg === '--json') continue;
|
|
8
|
+
if (arg === '--keep-both') { if (Object.hasOwn(flags, 'keepBoth')) throw Error('Unknown, repeated or incomplete duplicates option.'); flags.keepBoth = true; continue; }
|
|
9
|
+
if (!arg.startsWith('--')) { positions.push(arg); continue; }
|
|
10
|
+
const key = arg.slice(2);
|
|
11
|
+
if (!allowed.includes(key) || Object.hasOwn(flags, key) || args[i + 1] === undefined || args[i + 1].startsWith('--')) throw Error('Unknown, repeated or incomplete duplicates option.');
|
|
12
|
+
flags[key] = args[++i];
|
|
13
|
+
}
|
|
14
|
+
const verb = positions[2];
|
|
15
|
+
const usage = 'Use prospects duplicates list --workspace ID, or prospects duplicates get|merge|dismiss PERSON --workspace ID [--primary PROFILE_ID | --keep-both].';
|
|
16
|
+
if (positions[0] !== 'prospects' || positions[1] !== 'duplicates' || !['list', 'get', 'merge', 'dismiss'].includes(verb) || positions.length !== (verb === 'list' ? 3 : 4)) throw Error(usage);
|
|
17
|
+
if ((flags.primary !== undefined || flags.keepBoth) && verb !== 'merge') throw Error('--primary and --keep-both apply to merge only.');
|
|
18
|
+
if (flags.primary !== undefined && flags.keepBoth) throw Error('Use --primary or --keep-both, not both.');
|
|
19
|
+
const tool = { list: 'workspace_possible_duplicates', get: 'workspace_prospect_duplicate', merge: 'workspace_prospect_duplicate_merge', dismiss: 'workspace_prospect_duplicate_dismiss' }[verb];
|
|
20
|
+
const input = { workspaceId: flags.workspace, ...(verb === 'list' ? {} : { prospectId: positions[3] }), ...(flags.primary === undefined ? {} : { primaryProfileId: flags.primary }), ...(flags.keepBoth ? { keepBoth: true } : {}) };
|
|
21
|
+
console.log(JSON.stringify(await callWorkspace(tool, input, configuration(flags.profile))));
|
|
22
|
+
}
|
package/cli/workspaces.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import { accountReplyOperations } from './account-reply-operations.mjs';
|
|
|
20
20
|
import { accountIntakeOperations } from './account-intake-operations.mjs';
|
|
21
21
|
import { recipientOperations } from './recipient-operations.mjs';
|
|
22
22
|
import { suppressionOperations } from './suppression-operations.mjs';
|
|
23
|
+
import { duplicateOperations } from './duplicate-operations.mjs';
|
|
23
24
|
import { guardrailsOperations } from './guardrails-operations.mjs';
|
|
24
25
|
import { auditOperations } from './audit-operations.mjs';
|
|
25
26
|
import { intentOperations } from './intent-operations.mjs';
|
|
@@ -61,6 +62,7 @@ export const operations = {
|
|
|
61
62
|
...managedAccountOperations,
|
|
62
63
|
...workFeedbackOperations,
|
|
63
64
|
...suppressionOperations,
|
|
65
|
+
...duplicateOperations,
|
|
64
66
|
...guardrailsOperations,
|
|
65
67
|
...auditOperations,
|
|
66
68
|
...intentOperations,
|
|
@@ -85,6 +87,7 @@ export const operations = {
|
|
|
85
87
|
workspace_member: {schema:z.object({...workspace,userId:uuid}).strict(),method:'GET',path:a=>`/workspaces/${a.workspaceId}/members/${a.userId}`,scoped:true},
|
|
86
88
|
workspace_agent_access: { schema:z.object(workspace).strict(), method:'GET', path:a=>`/workspaces/${a.workspaceId}/agent-access`, scoped:true },
|
|
87
89
|
workspace_agent_access_set: { schema:z.object({...workspace,userId:uuid,blocked:z.boolean()}).strict(), method:'POST', path:a=>`/workspaces/${a.workspaceId}/members/${a.userId}/agent-access`, body:a=>({blocked:a.blocked}), scoped:true },
|
|
90
|
+
token_show: { schema: z.object({}).strict(), method: 'GET', path: () => '/token', description: 'Say what the credential you are using can do: its permission and whether it can change things. Works with any valid user API token or agent credential. A read-only token (workspace:read) is refused on every change; ask your user for a workspace:access token to change things.' },
|
|
88
91
|
workspace_initialize: { schema: z.object({}).strict(), method: 'POST', path: () => '/workspaces/bootstrap' },
|
|
89
92
|
workspace_list: { schema: z.object({}).strict(), method: 'GET', path: () => '/workspaces' },
|
|
90
93
|
workspace_create: { schema: z.object({ name: z.string().trim().min(1).max(80), requestId: uuid }).strict(), method: 'POST', path: () => '/workspaces', body: a => a },
|
|
@@ -134,7 +137,7 @@ export function configuration(path, scope='workspace:access') {
|
|
|
134
137
|
path=profileFrom(path);
|
|
135
138
|
const profile=readProfile(path);
|
|
136
139
|
const agentProfile = Boolean(profile.agent || profile.pendingAgent || profile.connectionSecret);
|
|
137
|
-
return { url:agentProfile ? profile.url : process.env.AUDIENTI_API_URL ?? profile.url, token:agentProfile ? (scope === 'workspace:access' ? profile.tokens?.['workspace:read'] : undefined) : process.env.AUDIENTI_API_TOKEN ?? (scope === 'workspace:access' ? profile.tokens?.['workspace:
|
|
140
|
+
return { url:agentProfile ? profile.url : process.env.AUDIENTI_API_URL ?? profile.url, token:agentProfile ? (scope === 'workspace:access' ? profile.tokens?.['workspace:read'] : undefined) : process.env.AUDIENTI_API_TOKEN ?? (scope === 'workspace:access' ? profile.tokens?.['workspace:access'] ?? profile.tokens?.['workspace:read'] : profile.tokens?.[scope]), workspaceId:profile.workspaceId, profile };
|
|
138
141
|
}
|
|
139
142
|
export function validateUrl(value) {
|
|
140
143
|
let url;try {url=new URL(value);}catch{throw new Error('Set AUDIENTI_API_URL to an API URL ending with /api/v1.');}
|
|
@@ -201,7 +204,7 @@ export async function callWorkspace(name, args, config) {
|
|
|
201
204
|
if(operation.localUpload)return uploadFileContent(input,(operationName,fields)=>callWorkspace(operationName,fields,config));
|
|
202
205
|
// #333: an agent's own queue covers all its workspaces; a user's reads the selected workspace, as before.
|
|
203
206
|
if(operation.scoped || (operation.agentWide && !/^agt_/.test(config.token ?? ''))) { input.workspaceId ??= config.workspaceId;if(!uuid.safeParse(input.workspaceId).success) throw new Error(config.interface==='mcp'?`Pass workspaceId in the tool input, or call workspace_select once. ${config.profile&&Object.keys(config.profile).length?'':profileHint}`.trim():`Select a workspace or supply --workspace ID. ${config.profile&&Object.keys(config.profile).length?'Run workspace use WORKSPACE_ID once for this profile.':`${profileHint} An agent that is not connected yet runs agent connect first; then run workspace use WORKSPACE_ID once.`}`); }
|
|
204
|
-
const url=validateUrl(config.url); if(!config.token) throw new Error(`A workspace
|
|
207
|
+
const url=validateUrl(config.url); if(!config.token) throw new Error(`A workspace token is required: workspace:access to read and change, or workspace:read to only read. ${profileHint} Or set AUDIENTI_API_URL and AUDIENTI_API_TOKEN.`);
|
|
205
208
|
const target=new URL(`/api/v1${operation.path(input)}`,url);
|
|
206
209
|
let response;try {response=await fetch(target,{method:operation.method,headers:{Authorization:`Bearer ${config.token}`,Accept:'application/json','Content-Type':'application/json',...((operation.traced||name.startsWith('tools_'))?{'X-Audienti-Interface':config.interface==='mcp'?'mcp':'cli'}:{})},...(['POST','PUT','PATCH'].includes(operation.method)?{body:JSON.stringify(operation.body?.(input)??{})}:{}),redirect:'error',signal:AbortSignal.timeout(operation.timeoutMs ?? 10000)});}catch(error){if(isPaidToolOperation(name,input)||operation.recoverable)throw new HostedResponseUnknown(input.requestId,['TimeoutError','AbortError'].includes(error?.name)?'timeout':'transport_failure');throw new Error('Could not reach the API. Redirects are not followed.');}
|
|
207
210
|
const headerTrace=(operation.traced||name.startsWith('tools_'))&&uuid.safeParse(response.headers.get('x-request-trace-id')).success?response.headers.get('x-request-trace-id'):undefined;
|
|
@@ -210,7 +213,7 @@ export async function callWorkspace(name, args, config) {
|
|
|
210
213
|
if(!response.ok) {
|
|
211
214
|
const code = typeof result?.error?.code==='string' && /^[a-z_]+$/.test(result.error.code) ? result.error.code : 'request_failed';
|
|
212
215
|
const retryAt = typeof result?.error?.retryAt === 'string' && /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(result.error.retryAt) ? result.error.retryAt : undefined;
|
|
213
|
-
const detail = (INTENT_REFUSALS.has(code) || (name.startsWith('decision_') && DECISION_REFUSALS.has(code)) || (response.status===400 && (code==='invalid_fields' || code==='validation_error' || code==='secret_rejected')) || (response.status===404 && (code==='not_found' || code==='no_draft')) || (response.status===422 && code==='playbook_cannot_work') || (response.status===409 && (code==='revision_conflict' || code==='draft_conflict' || code==='playbook_in_use' || code==='definition_archived' || code==='playbook_archived' || code==='starter_playbook' || code==='identity_conflict' || code==='task_not_for_you' || code==='version_conflict' || code==='request_conflict' || code==='campaign_not_ready' || code==='campaign_not_paced' || code==='wrong_event_name' || code==='mark_task_done_first' || code==='no_event' || code==='prepare_first' || code==='task_closed' || code==='not_claimed'))) && typeof result?.error?.message==='string' && result.error.message.length<=(code==='playbook_cannot_work'?2000:1000) && !/[\u0000-\u001f\u007f]/.test(result.error.message) && !/^Workspace request failed/.test(result.error.message) && !(config.token && result.error.message.includes(config.token)) ? result.error.message.trim() : '';
|
|
216
|
+
const detail = (INTENT_REFUSALS.has(code) || (name.startsWith('decision_') && DECISION_REFUSALS.has(code)) || (response.status===400 && (code==='invalid_fields' || code==='validation_error' || code==='secret_rejected')) || (response.status===403 && code==='insufficient_scope' && /^This API token can read but not change\./.test(result?.error?.message ?? '')) || (response.status===404 && (code==='not_found' || code==='no_draft')) || (response.status===422 && code==='playbook_cannot_work') || (response.status===409 && (code==='revision_conflict' || code==='draft_conflict' || code==='playbook_in_use' || code==='definition_archived' || code==='playbook_archived' || code==='starter_playbook' || code==='identity_conflict' || code==='task_not_for_you' || code==='version_conflict' || code==='request_conflict' || code==='campaign_not_ready' || code==='campaign_not_paced' || code==='wrong_event_name' || code==='mark_task_done_first' || code==='no_event' || code==='prepare_first' || code==='task_closed' || code==='not_claimed'))) && typeof result?.error?.message==='string' && result.error.message.length<=(code==='playbook_cannot_work'?2000:1000) && !/[\u0000-\u001f\u007f]/.test(result.error.message) && !/^Workspace request failed/.test(result.error.message) && !(config.token && result.error.message.includes(config.token)) ? result.error.message.trim() : '';
|
|
214
217
|
const blockers = (code==='execution_blocked' || code==='campaign_not_ready') && Array.isArray(result?.error?.blockers) && result.error.blockers.length<=28 && result.error.blockers.every(v=>typeof v==='string' && /^[a-z_]+$/.test(v)) ? result.error.blockers : undefined;
|
|
215
218
|
const error = new WorkspaceRequestError(response.status, code, name==='intent_record' && (INTENT_REFUSALS.has(code) || code==='invalid_fields') && detail ? surfaceWording(detail, config) : `Workspace request failed: ${code} (HTTP ${response.status}).${detail ? ` ${surfaceWording(detail, config)}` : ''}${retryAt ? ` Retry after ${retryAt}.` : ''}`, retryAt, blockers, requestTraceId, errorGuidance(result?.error, config.token, config));
|
|
216
219
|
if(code==='playbook_cannot_work'&&Array.isArray(result?.error?.errors)&&result.error.errors.length<=30)error.errors=result.error.errors.filter(item=>item&&typeof item.id==='string'&&typeof item.message==='string').map(item=>({id:item.id,level:item.level,message:item.message,...(typeof item.stageKey==='string'?{stageKey:item.stageKey}:{}),...(item.fix&&typeof item.fix.label==='string'?{fix:{id:item.fix.id,label:item.fix.label}}:{})}));
|
|
@@ -237,11 +240,13 @@ export async function workspaceCli(args) {
|
|
|
237
240
|
else position.push(args[i]);
|
|
238
241
|
}
|
|
239
242
|
if(position[0]==='profile' && position[1]==='save') {
|
|
240
|
-
if(!['account:read','workspace:access','agents:manage'].includes(flags.scope)) throw new Error('Specify --scope account:read, workspace:access or agents:manage.');
|
|
243
|
+
if(!['account:read','workspace:read','workspace:access','agents:manage'].includes(flags.scope)) throw new Error('Specify --scope account:read, workspace:read, workspace:access or agents:manage.');
|
|
241
244
|
const url=validateUrl(process.env.AUDIENTI_API_URL).toString().replace(/\/$/,'');const token=process.env.AUDIENTI_API_TOKEN;if(!token) throw new Error('Set AUDIENTI_API_TOKEN.');
|
|
242
245
|
const profile=readProfile(profileFrom(flags.profile));if(profile.agent || profile.pendingAgent || profile.connectionSecret) throw new Error('Use a separate user profile; agent profiles cannot store user API tokens.');writeProfile(profileFrom(flags.profile),{...profile,url,tokens:{...profile.tokens,[flags.scope]:token}});console.log('Profile saved.');return;
|
|
243
246
|
}
|
|
244
247
|
const config=configuration(flags.profile);const command=position.slice(1).join(' ');
|
|
248
|
+
// token show works with any saved user token, so it also tries the other slots when there is no workspace token.
|
|
249
|
+
if(position[0]==='token'&&!config.token&&!process.env.AUDIENTI_API_TOKEN&&!(config.profile.agent||config.profile.pendingAgent||config.profile.connectionSecret))config.token=config.profile.tokens?.['agents:manage']??config.profile.tokens?.['account:read'];
|
|
245
250
|
let name, input={};
|
|
246
251
|
if(command==='sending-settings') {name='workspace_sending_settings_get';input={workspaceId:flags.workspace,...(flags.user?{userId:flags.user}:{})};}
|
|
247
252
|
else if(command==='sending-settings save') {if(!flags.file) throw new Error('Supply the settings with --file PATH.');const body=readJsonFile(flags.file,65536,'Settings file');if(!body||typeof body!=='object'||Array.isArray(body)) throw new Error('Settings must be an object.');name='workspace_sending_settings_save';input={...body,workspaceId:flags.workspace??body.workspaceId,...(flags.user?{userId:flags.user}:{})};}
|
|
@@ -251,6 +256,7 @@ export async function workspaceCli(args) {
|
|
|
251
256
|
else if(position[1]==='usage'&&position[2]==='call'&&position.length===4) {name='workspace_usage_call';input={workspaceId:flags.workspace,callId:position[3]};}
|
|
252
257
|
else if(command==='agent-access') {name='workspace_agent_access';input={workspaceId:flags.workspace};}
|
|
253
258
|
else if(['agent-access block','agent-access restore'].includes(command)) {name='workspace_agent_access_set';input={workspaceId:flags.workspace,userId:flags.user,blocked:command.endsWith('block')};}
|
|
259
|
+
else if(position[0]==='token'&&command==='show') name='token_show';
|
|
254
260
|
else if(command==='init') name='workspace_initialize';
|
|
255
261
|
else if(command==='list') name='workspace_list';
|
|
256
262
|
else if(command==='notifications') {if(flags['unread-only']&&!['true','false'].includes(flags['unread-only']))throw new Error('--unread-only must be true or false.');name='workspace_notifications_list';input={workspaceId:flags.workspace,unreadOnly:flags['unread-only']==='true',...(flags.cursor?{cursor:readJsonFile(flags.cursor,4096,'Notification cursor')}:{})};}
|
package/package.json
CHANGED
package/source-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repository": "https://github.com/omalab/exora",
|
|
3
|
-
"sourceCommit": "
|
|
3
|
+
"sourceCommit": "3ace57bf9aaff4acbeb92b8bbb5216495011eead",
|
|
4
4
|
"files": {
|
|
5
5
|
"LICENSE": "220f297cfcd5c38eb64e6b4b4a77cab4ebc7f4686d4d99c6260a475d02ca11e5",
|
|
6
6
|
"README.md": "7ff32cc8ac89dd54b64d7b39c0b41b1f37e154b7ea10ad5a7bceefc3df77d87f",
|
|
@@ -16,7 +16,7 @@
|
|
|
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": "7f081c32c0ad5abf84fb5dc6dc504ebd2371e530e50828767f2f0470bca509a7",
|
|
20
20
|
"cli/audit-operations.mjs": "afaf87d592a1e5f6bff2a8649a6a64a8f471950b7d99e98995d9205aa5910398",
|
|
21
21
|
"cli/audit.mjs": "a7becaed67c58b063e668b5e66844b6dc15c11a63b428faa171b542ad922c001",
|
|
22
22
|
"cli/budget-operations.mjs": "d74916551ef393e29734c6e13cf9021251e0ed126eeaa529e18cf2332146e1e0",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
"cli/decision.mjs": "3d89d48b333e2620bce0191cf528ef25541ee841a7f8ae6d60249aead434b651",
|
|
33
33
|
"cli/discovery-operations.mjs": "9b6873d586d27bf67106a592db8ced75da1abf1a1330f192e69d34f81b2d080f",
|
|
34
34
|
"cli/discovery.mjs": "34b3794ee6ca539dbbccef77ec2085fd5411023046bdfb9b83e2537414542a41",
|
|
35
|
+
"cli/duplicate-operations.mjs": "a07ba6ff411bc27246a454ee43b0508e024974d2fa2b4258c709583767c17950",
|
|
36
|
+
"cli/duplicates.mjs": "341e5c8dae67a819340abdad3502470577cf8b6375bf60acb00068c7188344a7",
|
|
35
37
|
"cli/file-operations.mjs": "564f334dd9d52e9c56f44d58b5c3b0bda59ff72f54126b755bc472144069349e",
|
|
36
38
|
"cli/files.mjs": "2221b067d6ade7ef5cc8965929aea2eb485781953d3f2b50600995b65fbdedae",
|
|
37
39
|
"cli/guardrails-operations.mjs": "aa5a911663133b3287bea805df9e2a5d8b5bbc4a3df972c52f91fee315954ded",
|
|
@@ -85,8 +87,8 @@
|
|
|
85
87
|
"cli/work-feedback.mjs": "f3b77ecfd7ea1aba9c9f03c9d894137547e9c5575d9daa359ed94505ad025852",
|
|
86
88
|
"cli/work-operations.mjs": "8b3a84ca15e8e4ad79ef92ced4c5adaffd5129f630e3bfc2c74a844a90867600",
|
|
87
89
|
"cli/work.mjs": "751107ecc3de5a6be9db4a068cddc41f3ad8e77c87e59686eaf522862caf9e9f",
|
|
88
|
-
"cli/workspaces.mjs": "
|
|
89
|
-
"package.json": "
|
|
90
|
+
"cli/workspaces.mjs": "b2621958f426ed12db6ac7e7484c9c7d4eb84d25474d3090d1f75c667ebcd36f",
|
|
91
|
+
"package.json": "853558fe662b32288defea4af0e62aa05922eccb1ff32fc7e11273fd0cd6d5b2",
|
|
90
92
|
"skills/agent-rooms/SKILL.md": "08f917ff85fee1d23499a4499056ce845b39ce6727029b104819dad41ee87cc2",
|
|
91
93
|
"skills/agent-rooms/references/commands.md": "ef5afa5543ca9da967a147f638774647998ea1c1a2a821959f3bf87d54c292bd",
|
|
92
94
|
"skills/audienti/SKILL.md": "8f2124065bfc3a005b44e194e7dcce9bbf14062ab332e7db66d441eeccb518ed",
|