@audienti/cli 0.1.57 → 0.1.59
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/CHANGELOG.md +16 -0
- package/README.md +12 -1
- package/package.json +1 -1
- package/src/cli.js +131 -23
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.59] - 2026-09-06
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Read eligible Operator queues from their latest published state while changes process, retaining current ownership checks and twenty-row API pagination.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Restore ordinary Prospect, Content, Visibility, Network, and Inbox priority order while preserving urgent reply and planner precedence.
|
|
16
|
+
|
|
17
|
+
## [0.1.58] - 2026-09-06
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Continue Operator and Inbox queue reads with the exact returned offset or cursor, preserving account and filters even after an empty page. Report incomplete scans without claiming the queue is empty, and keep pagination separate from outcome and requeue operations.
|
|
22
|
+
|
|
7
23
|
## [0.1.57] - 2026-09-05
|
|
8
24
|
|
|
9
25
|
### Added
|
package/README.md
CHANGED
|
@@ -218,12 +218,23 @@ audienti operator next --plan
|
|
|
218
218
|
audienti operator next --done --note "Connection request sent."
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
+
`operator queue`, `operator failed-drafts`, and `inbox-ops queue` print a
|
|
222
|
+
continuation command when more rows remain. Read-only `operator next` (including
|
|
223
|
+
`--plan`) also prints one when its page has no focal move but more rows remain;
|
|
224
|
+
when a move is present, inspect or act on it and rerun `operator next`.
|
|
225
|
+
Follow the continuation command even when the current page has no ready
|
|
226
|
+
rows. It preserves the account and filters and uses the API's exact `--page` and
|
|
227
|
+
`--offset` (which can be zero), or its opaque `--cursor`. Do not combine a cursor
|
|
228
|
+
with an offset. If the scan limit is reached, narrow the filters; an incomplete
|
|
229
|
+
scan does not mean the queue is empty. JSON output preserves the API response.
|
|
230
|
+
Pagination flags are not accepted when recording outcomes or requeueing drafts.
|
|
231
|
+
|
|
221
232
|
Inbox Ops has its own owner-scoped CLI surface. Queue rows expose the stable row
|
|
222
233
|
id used by the row-based rule command. Rules can also be set or removed directly
|
|
223
234
|
by sender or domain; the server normalizes and validates every supplied key:
|
|
224
235
|
|
|
225
236
|
```bash
|
|
226
|
-
audienti inbox-ops queue [--page <n>]
|
|
237
|
+
audienti inbox-ops queue [--page <n>] [--offset <n>|--cursor <token>]
|
|
227
238
|
audienti inbox-ops filters
|
|
228
239
|
audienti inbox-ops rule <row_id> --scope sender --disposition filter
|
|
229
240
|
audienti inbox-ops rule <row_id> --scope domain --disposition allow
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -65,7 +65,16 @@ const PROSPECTS_CHECK_USAGE = "Usage: audienti prospects check [--json|--csv] [f
|
|
|
65
65
|
const PROSPECTS_IMPORT_BATCH_USAGE = "Usage: audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--assigned-user <id|me>] [--json] [--account <acct_id>]";
|
|
66
66
|
const OPERATOR_FAILED_DRAFTS_USAGE = "Usage: audienti operator failed-drafts [--json] [filters] [--account <acct_id>]";
|
|
67
67
|
const OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE = "Usage: audienti operator failed-drafts requeue (--all | <row_id> [row_id...]) [--limit <n>] [--json] [filters] [--account <acct_id>]";
|
|
68
|
-
const INBOX_OPS_QUEUE_USAGE = "Usage: audienti inbox-ops queue [--page <n>] [--json] [--account <acct_id>]";
|
|
68
|
+
const INBOX_OPS_QUEUE_USAGE = "Usage: audienti inbox-ops queue [--page <n>] [--offset <n>|--cursor <token>] [--json] [--account <acct_id>]";
|
|
69
|
+
const OPERATOR_PAGINATION_HELP = [
|
|
70
|
+
"Read pagination:",
|
|
71
|
+
" --page <n> Positive page number",
|
|
72
|
+
" --offset <n> Exact returned next_offset, including zero",
|
|
73
|
+
" --cursor <token> Opaque returned next_cursor; cannot be combined with --offset",
|
|
74
|
+
" Follow the printed continuation with the same account and filters, even after an empty page.",
|
|
75
|
+
" Pagination is not accepted with outcome or requeue operations.",
|
|
76
|
+
""
|
|
77
|
+
];
|
|
69
78
|
const INBOX_OPS_FILTERS_USAGE = "Usage: audienti inbox-ops filters [--json] [--account <acct_id>]";
|
|
70
79
|
const INBOX_OPS_RULE_USAGE = "Usage: audienti inbox-ops rule <row_id> --scope <sender|domain> --disposition <allow|filter> [--json] [--account <acct_id>]";
|
|
71
80
|
const INBOX_OPS_RULE_SET_USAGE = "Usage: audienti inbox-ops rule set --scope <sender|domain> --key <email|domain> --disposition <allow|filter> [--json] [--account <acct_id>]";
|
|
@@ -3240,32 +3249,30 @@ async function toolsLinkedinReviewStatus(args, context, { accountOverride } = {}
|
|
|
3240
3249
|
}
|
|
3241
3250
|
|
|
3242
3251
|
async function operatorQueue(args, context, { accountOverride } = {}) {
|
|
3243
|
-
const { values, positionals } = parseCommandArgs(args, operatorFilterOptions());
|
|
3252
|
+
const { values, positionals } = parseCommandArgs(args, operatorFilterOptions(operatorPaginationOptions()));
|
|
3244
3253
|
if (positionals.length > 0) throw new CommandError("Usage: audienti operator queue [--json] [filters] [--account <acct_id>]");
|
|
3245
3254
|
|
|
3255
|
+
const query = { ...operatorQuery(values), ...operatorPaginationQuery(values) };
|
|
3246
3256
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3247
|
-
const payload = await client.operatorQueue(accountId,
|
|
3257
|
+
const payload = await client.operatorQueue(accountId, query);
|
|
3248
3258
|
if (values.json) return writeJson(context.stdout, payload);
|
|
3249
3259
|
|
|
3250
|
-
renderOperatorQueue(payload, context);
|
|
3260
|
+
renderOperatorRead(payload, context, { command: "operator queue", accountId, query }, () => renderOperatorQueue(payload, context));
|
|
3251
3261
|
}
|
|
3252
3262
|
|
|
3253
3263
|
async function inboxOpsQueue(args, context, { accountOverride } = {}) {
|
|
3254
3264
|
const { values, positionals } = parseCommandArgs(args, {
|
|
3255
3265
|
...jsonOptions(),
|
|
3256
|
-
|
|
3266
|
+
...operatorPaginationOptions()
|
|
3257
3267
|
});
|
|
3258
3268
|
if (positionals.length > 0) throw new CommandError(INBOX_OPS_QUEUE_USAGE);
|
|
3259
3269
|
|
|
3260
|
-
const
|
|
3270
|
+
const query = { opportunity_kind: "inbox", ...operatorPaginationQuery(values) };
|
|
3261
3271
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3262
|
-
const payload = await client.operatorQueue(accountId,
|
|
3263
|
-
opportunity_kind: "inbox",
|
|
3264
|
-
operator_page: page
|
|
3265
|
-
}));
|
|
3272
|
+
const payload = await client.operatorQueue(accountId, query);
|
|
3266
3273
|
if (values.json) return writeJson(context.stdout, payload);
|
|
3267
3274
|
|
|
3268
|
-
renderInboxOpsQueue(payload, context);
|
|
3275
|
+
renderOperatorRead(payload, context, { command: "inbox-ops queue", accountId, query }, () => renderInboxOpsQueue(payload, context));
|
|
3269
3276
|
}
|
|
3270
3277
|
|
|
3271
3278
|
async function inboxOpsFilters(args, context, { accountOverride } = {}) {
|
|
@@ -3345,14 +3352,15 @@ async function operatorFailedDrafts(args, context, { accountOverride } = {}) {
|
|
|
3345
3352
|
return operatorFailedDraftsRequeue(args.slice(1), context, { accountOverride });
|
|
3346
3353
|
}
|
|
3347
3354
|
|
|
3348
|
-
const { values, positionals } = parseCommandArgs(args, operatorFailedDraftOptions());
|
|
3355
|
+
const { values, positionals } = parseCommandArgs(args, operatorFailedDraftOptions(operatorPaginationOptions()));
|
|
3349
3356
|
if (positionals.length > 0) throw new CommandError(OPERATOR_FAILED_DRAFTS_USAGE);
|
|
3350
3357
|
|
|
3358
|
+
const query = { ...operatorFailedDraftQuery(values), ...operatorPaginationQuery(values) };
|
|
3351
3359
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3352
|
-
const payload = await client.operatorQueue(accountId,
|
|
3360
|
+
const payload = await client.operatorQueue(accountId, query);
|
|
3353
3361
|
if (values.json) return writeJson(context.stdout, payload);
|
|
3354
3362
|
|
|
3355
|
-
renderOperatorFailedDrafts(payload, context);
|
|
3363
|
+
renderOperatorRead(payload, context, { command: "operator failed-drafts", accountId, query }, () => renderOperatorFailedDrafts(payload, context));
|
|
3356
3364
|
}
|
|
3357
3365
|
|
|
3358
3366
|
async function operatorFailedDraftsRequeue(args, context, { accountOverride } = {}) {
|
|
@@ -3381,12 +3389,16 @@ async function operatorNext(args, context, { accountOverride } = {}) {
|
|
|
3381
3389
|
if (values.json && values.plan) throw new CommandError("Choose one output format: use either --json or --plan.");
|
|
3382
3390
|
const outcomeStatus = operatorNextOutcomeStatus(values);
|
|
3383
3391
|
if (values.plan && outcomeStatus) throw new CommandError("Choose one mode: use either --plan or an outcome flag.");
|
|
3392
|
+
if (outcomeStatus && [values.page, values.offset, values.cursor].some((value) => value !== undefined)) {
|
|
3393
|
+
throw new CommandError("Pagination is only available for reads; omit --page, --offset, and --cursor when recording an outcome.");
|
|
3394
|
+
}
|
|
3384
3395
|
if (!outcomeStatus && (values.note !== undefined || values["occurred-at"] !== undefined)) {
|
|
3385
3396
|
throw new CommandError("--note and --occurred-at require an outcome flag: --done, --skip, --fail, or --return.");
|
|
3386
3397
|
}
|
|
3387
3398
|
|
|
3399
|
+
const query = { ...operatorQuery(values), ...operatorPaginationQuery(values) };
|
|
3388
3400
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3389
|
-
const payload = await client.operatorNext(accountId,
|
|
3401
|
+
const payload = await client.operatorNext(accountId, query);
|
|
3390
3402
|
if (outcomeStatus) {
|
|
3391
3403
|
const response = await client.operatorOutcome(accountId, operatorNextOutcomePayload(payload?.next_move, {
|
|
3392
3404
|
status: outcomeStatus,
|
|
@@ -3399,9 +3411,10 @@ async function operatorNext(args, context, { accountOverride } = {}) {
|
|
|
3399
3411
|
return renderOperatorOutcome(response, context);
|
|
3400
3412
|
}
|
|
3401
3413
|
if (values.json) return writeJson(context.stdout, payload);
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3414
|
+
renderOperatorRead(payload, context, { command: "operator next", accountId, query, plan: values.plan }, () => {
|
|
3415
|
+
if (values.plan) return renderOperatorPlan(payload?.next_move, context);
|
|
3416
|
+
renderOperatorNext(payload?.next_move, context);
|
|
3417
|
+
});
|
|
3405
3418
|
}
|
|
3406
3419
|
|
|
3407
3420
|
async function operatorOutcome(args, context, { accountOverride } = {}) {
|
|
@@ -3760,6 +3773,7 @@ function operatorFilterOptions(extra = {}) {
|
|
|
3760
3773
|
|
|
3761
3774
|
function operatorNextOptions() {
|
|
3762
3775
|
return operatorFilterOptions({
|
|
3776
|
+
...operatorPaginationOptions(),
|
|
3763
3777
|
plan: { type: "boolean" },
|
|
3764
3778
|
done: { type: "boolean" },
|
|
3765
3779
|
skip: { type: "boolean" },
|
|
@@ -3770,6 +3784,28 @@ function operatorNextOptions() {
|
|
|
3770
3784
|
});
|
|
3771
3785
|
}
|
|
3772
3786
|
|
|
3787
|
+
function operatorPaginationOptions() {
|
|
3788
|
+
return { page: { type: "string" }, offset: { type: "string" }, cursor: { type: "string" } };
|
|
3789
|
+
}
|
|
3790
|
+
|
|
3791
|
+
function operatorPaginationQuery(values) {
|
|
3792
|
+
const page = normalizeOptionalPositiveInteger(values.page, "--page");
|
|
3793
|
+
if (values.page !== undefined && page === undefined) throw new CommandError("--page must be a positive integer.");
|
|
3794
|
+
if (page !== undefined && !Number.isSafeInteger(page)) throw new CommandError("--page must be a safe positive integer.");
|
|
3795
|
+
|
|
3796
|
+
let offset;
|
|
3797
|
+
if (values.offset !== undefined) {
|
|
3798
|
+
offset = Number(values.offset);
|
|
3799
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || String(offset) !== values.offset.trim()) {
|
|
3800
|
+
throw new CommandError("--offset must be a nonnegative integer.");
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
if (values.cursor !== undefined && !values.cursor.trim()) throw new CommandError("--cursor must not be blank.");
|
|
3804
|
+
if (values.cursor !== undefined && offset !== undefined) throw new CommandError("Choose either --cursor or --offset, not both.");
|
|
3805
|
+
|
|
3806
|
+
return compactObject({ operator_page: page, operator_offset: offset, operator_cursor: values.cursor });
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3773
3809
|
function operatorFailedDraftOptions(extra = {}) {
|
|
3774
3810
|
return {
|
|
3775
3811
|
...jsonOptions(),
|
|
@@ -6332,6 +6368,75 @@ function renderOperatorQueue(payload, context) {
|
|
|
6332
6368
|
queue.forEach((row) => renderPlannerQuestion(row, context));
|
|
6333
6369
|
}
|
|
6334
6370
|
|
|
6371
|
+
function renderOperatorRead(payload, context, continuation, renderRows) {
|
|
6372
|
+
if (["reset_to_legacy", "cursor_stale"].includes(payload?.metrics?.cursor_status)) {
|
|
6373
|
+
writeLine(context.stdout, "Queue changed; restarted at the first page.");
|
|
6374
|
+
}
|
|
6375
|
+
const hasRows = payload?.next_move || payload?.decision_queue?.length > 0;
|
|
6376
|
+
if (!hasRows && (payload?.has_more === true || payload?.metrics?.scan_ceiling_reached === true)) {
|
|
6377
|
+
writeLine(context.stdout, "No ready rows in this page.");
|
|
6378
|
+
} else {
|
|
6379
|
+
renderRows();
|
|
6380
|
+
}
|
|
6381
|
+
if (payload?.metrics?.scan_ceiling_reached === true) {
|
|
6382
|
+
writeLine(context.stdout, "Queue scan limit reached; more work may remain. Narrow the filters to inspect it.");
|
|
6383
|
+
}
|
|
6384
|
+
// /next exposes one focal move, while next_offset covers the whole scanned page.
|
|
6385
|
+
const focalMoveShown = continuation.command === "operator next" && payload?.next_move;
|
|
6386
|
+
if (payload?.has_more === true && !focalMoveShown) {
|
|
6387
|
+
const command = operatorContinuationCommand(payload, continuation);
|
|
6388
|
+
writeLine(context.stdout, command ? `More rows: ${command}` : "More work may remain; narrow the filters to continue.");
|
|
6389
|
+
}
|
|
6390
|
+
}
|
|
6391
|
+
|
|
6392
|
+
function operatorContinuationCommand(payload, { command, accountId, query, plan }) {
|
|
6393
|
+
const args = ["audienti", ...command.split(" ")];
|
|
6394
|
+
const cursor = payload?.metrics?.next_cursor;
|
|
6395
|
+
if (payload.next_page) args.push(...operatorCommandOption("page", payload.next_page));
|
|
6396
|
+
if (cursor) {
|
|
6397
|
+
args.push(...operatorCommandOption("cursor", cursor));
|
|
6398
|
+
} else {
|
|
6399
|
+
if (!payload.next_page) return null;
|
|
6400
|
+
if (payload?.metrics?.next_offset !== undefined && payload.metrics.next_offset !== null) {
|
|
6401
|
+
args.push(...operatorCommandOption("offset", payload.metrics.next_offset));
|
|
6402
|
+
}
|
|
6403
|
+
}
|
|
6404
|
+
args.push(...operatorCommandOption("account", accountId));
|
|
6405
|
+
args.push(...operatorContinuationFilters(command, query, payload.filters));
|
|
6406
|
+
if (plan) args.push("--plan");
|
|
6407
|
+
return args.map(operatorCommandArgument).join(" ");
|
|
6408
|
+
}
|
|
6409
|
+
|
|
6410
|
+
function operatorContinuationFilters(command, query, resolvedFilters = {}) {
|
|
6411
|
+
if (command === "inbox-ops queue") return [];
|
|
6412
|
+
|
|
6413
|
+
const filters = { ...resolvedFilters, ...query };
|
|
6414
|
+
const flags = {
|
|
6415
|
+
principal_account_user_id: "principal", motion_id: "motion", list_id: "list",
|
|
6416
|
+
stage: "stage", opportunity_kind: "opportunity-kind", writing_status: "writing-status"
|
|
6417
|
+
};
|
|
6418
|
+
filters.stage ||= filters.pipeline_stage;
|
|
6419
|
+
if (command === "operator failed-drafts") {
|
|
6420
|
+
delete flags.opportunity_kind;
|
|
6421
|
+
delete flags.writing_status;
|
|
6422
|
+
flags.query = "query";
|
|
6423
|
+
}
|
|
6424
|
+
return Object.entries(flags).flatMap(([key, flag]) => {
|
|
6425
|
+
const value = filters[key];
|
|
6426
|
+
return value === undefined || value === null || value === "" ? [] : operatorCommandOption(flag, Array.isArray(value) ? value.join(",") : value);
|
|
6427
|
+
});
|
|
6428
|
+
}
|
|
6429
|
+
|
|
6430
|
+
function operatorCommandOption(flag, value) {
|
|
6431
|
+
const text = String(value);
|
|
6432
|
+
return text.startsWith("-") ? [`--${flag}=${text}`] : [`--${flag}`, text];
|
|
6433
|
+
}
|
|
6434
|
+
|
|
6435
|
+
function operatorCommandArgument(value) {
|
|
6436
|
+
const text = String(value);
|
|
6437
|
+
return /^[a-zA-Z0-9_./:@=-]+$/.test(text) ? text : `'${text.replaceAll("'", "'\\''")}'`;
|
|
6438
|
+
}
|
|
6439
|
+
|
|
6335
6440
|
function renderInboxOpsQueue(payload, context) {
|
|
6336
6441
|
const decisionQueue = Array.isArray(payload?.decision_queue) ? payload.decision_queue : [];
|
|
6337
6442
|
const rows = decisionQueue.length > 0 ? decisionQueue : [payload?.next_move].filter(Boolean);
|
|
@@ -6344,10 +6449,6 @@ function renderInboxOpsQueue(payload, context) {
|
|
|
6344
6449
|
display(row?.inbox_ops?.subject),
|
|
6345
6450
|
display(row?.inbox_ops?.connected_account)
|
|
6346
6451
|
]));
|
|
6347
|
-
if (payload?.has_more === true && payload?.next_page) {
|
|
6348
|
-
writeLine(context.stdout, "");
|
|
6349
|
-
writeLine(context.stdout, `More rows: audienti inbox-ops queue --page ${payload.next_page}`);
|
|
6350
|
-
}
|
|
6351
6452
|
}
|
|
6352
6453
|
|
|
6353
6454
|
function renderInboxOpsFilters(payload, context) {
|
|
@@ -10663,9 +10764,10 @@ const HELP_TOPICS = new Map([
|
|
|
10663
10764
|
"",
|
|
10664
10765
|
"Status: implemented",
|
|
10665
10766
|
"",
|
|
10767
|
+
...OPERATOR_PAGINATION_HELP,
|
|
10666
10768
|
"Purpose:",
|
|
10667
10769
|
" List one page of the authenticated owner's current private Inbox Ops rows with the authoritative sender/domain rule identity, subject, and connected inbox.",
|
|
10668
|
-
" When more rows exist, the plain output prints the
|
|
10770
|
+
" When more rows exist, the plain output prints the exact continuation command with the same account.",
|
|
10669
10771
|
"",
|
|
10670
10772
|
"API:",
|
|
10671
10773
|
" GET /api/v1/accounts/:account_id/operator.json?opportunity_kind=inbox"
|
|
@@ -10733,6 +10835,7 @@ const HELP_TOPICS = new Map([
|
|
|
10733
10835
|
"",
|
|
10734
10836
|
"Status: implemented",
|
|
10735
10837
|
"",
|
|
10838
|
+
...OPERATOR_PAGINATION_HELP,
|
|
10736
10839
|
"Options:",
|
|
10737
10840
|
" --plan Render a deterministic static plan from the existing next-action coach payload, CTA, and operator draft state",
|
|
10738
10841
|
" --done Mark the current next prospect move completed through the operator outcome API",
|
|
@@ -10763,12 +10866,16 @@ const HELP_TOPICS = new Map([
|
|
|
10763
10866
|
"",
|
|
10764
10867
|
"Status: implemented",
|
|
10765
10868
|
"",
|
|
10869
|
+
...OPERATOR_PAGINATION_HELP,
|
|
10766
10870
|
"Output shape:",
|
|
10767
10871
|
" next_move: focal operator row",
|
|
10768
10872
|
" decision_queue[]: ordered operator rows",
|
|
10769
10873
|
" daily_progress: pacing counters",
|
|
10770
10874
|
" outcome_rollups: queue rollups",
|
|
10771
10875
|
" options: motions, principals, lists, stages",
|
|
10876
|
+
" has_more/next_page: continuation state",
|
|
10877
|
+
" metrics.next_offset/next_cursor: exact continuation position",
|
|
10878
|
+
" metrics.scan_ceiling_reached: incomplete scan; narrow the filters",
|
|
10772
10879
|
"",
|
|
10773
10880
|
"API:",
|
|
10774
10881
|
" GET /api/v1/accounts/:account_id/operator.json"
|
|
@@ -10781,6 +10888,7 @@ const HELP_TOPICS = new Map([
|
|
|
10781
10888
|
"",
|
|
10782
10889
|
"Status: implemented",
|
|
10783
10890
|
"",
|
|
10891
|
+
...OPERATOR_PAGINATION_HELP,
|
|
10784
10892
|
"Purpose:",
|
|
10785
10893
|
" Lists failed prospect operator drafts and queues selected drafts for rewriting.",
|
|
10786
10894
|
"",
|