@commonlyai/cli 0.1.220 → 0.1.221
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/package.json +1 -1
- package/src/commands/inbox.js +43 -6
package/package.json
CHANGED
package/src/commands/inbox.js
CHANGED
|
@@ -188,22 +188,58 @@ export const runInboxAck = async (itemId, opts = {}, deps = {}) => {
|
|
|
188
188
|
}
|
|
189
189
|
};
|
|
190
190
|
|
|
191
|
+
// `value` is either a 1-based option index (position in the decision's options,
|
|
192
|
+
// shown on refusal) or an option label. The server stores whatever string it is sent, so
|
|
193
|
+
// the label is resolved here against the open queue and only the label is posted:
|
|
194
|
+
// a bare "2" recorded in the ruling would mean nothing to anyone reading it later.
|
|
195
|
+
export const resolveDecisionChoice = (options, value) => {
|
|
196
|
+
const choices = (Array.isArray(options) ? options : [])
|
|
197
|
+
.map((option) => String(option?.label ?? '').trim())
|
|
198
|
+
.filter(Boolean);
|
|
199
|
+
const listing = choices.map((label, i) => ` ${i + 1}. ${label}`).join('\n');
|
|
200
|
+
const raw = String(value).trim();
|
|
201
|
+
if (/^\d+$/.test(raw)) {
|
|
202
|
+
const index = Number(raw);
|
|
203
|
+
const labelled = choices.findIndex((label) => label === raw);
|
|
204
|
+
// A digit-only label is also a position in the list. When the two point at
|
|
205
|
+
// different options, neither reading is safe to guess, so refuse.
|
|
206
|
+
if (labelled !== -1 && labelled !== index - 1) {
|
|
207
|
+
throw new InboxRefusal(`"${raw}" is both option ${labelled + 1}'s label and position ${raw}; refusing to guess. Choose by position (1-${choices.length}) or by a label that is not a number:\n${listing}`);
|
|
208
|
+
}
|
|
209
|
+
if (index < 1 || index > choices.length) {
|
|
210
|
+
throw new InboxRefusal(`option ${raw} is out of range; choose 1-${choices.length}:\n${listing}`);
|
|
211
|
+
}
|
|
212
|
+
return choices[index - 1];
|
|
213
|
+
}
|
|
214
|
+
const match = choices.find((label) => label.toLocaleLowerCase() === raw.toLocaleLowerCase());
|
|
215
|
+
if (!match) throw new InboxRefusal(`"${raw}" is not an option; the options are:\n${listing}`);
|
|
216
|
+
return match;
|
|
217
|
+
};
|
|
218
|
+
|
|
191
219
|
export const runInboxChoose = async (decisionId, value, opts = {}, deps = {}) => {
|
|
192
220
|
const {
|
|
193
221
|
env = process.env, fetchImpl = fetch, log = console.log, error = console.error, sleep = undefined,
|
|
194
222
|
} = deps;
|
|
195
223
|
try {
|
|
196
|
-
if (!decisionId) throw new InboxRefusal('a decision id is required: commonly inbox choose <decisionId> <
|
|
197
|
-
if (value === undefined) throw new InboxRefusal('a value is required: commonly inbox choose <decisionId> <
|
|
224
|
+
if (!decisionId) throw new InboxRefusal('a decision id is required: commonly inbox choose <decisionId> <n|label>');
|
|
225
|
+
if (value === undefined) throw new InboxRefusal('a value is required: commonly inbox choose <decisionId> <n|label>');
|
|
198
226
|
const {
|
|
199
227
|
baseUrl, request, account,
|
|
200
228
|
} = await connect(opts, { env, fetchImpl, sleep });
|
|
201
229
|
log(formatAccountLine({ account, baseUrl }));
|
|
230
|
+
// The options live on the open queue, not on the decision route, so the
|
|
231
|
+
// choice is resolved against the same queue this account would see in `list`.
|
|
232
|
+
const { items } = await fetchQueue(request);
|
|
233
|
+
const open = items.find((item) => String(item?.id) === String(decisionId) && item?.kind === 'decision');
|
|
234
|
+
if (!open) {
|
|
235
|
+
throw new InboxRefusal(`decision ${decisionId} is not open on this account's queue; nothing to choose`);
|
|
236
|
+
}
|
|
237
|
+
const label = resolveDecisionChoice(open.options, value);
|
|
202
238
|
const result = await request(`/api/activity/decisions/${encodeURIComponent(decisionId)}/choose`, {
|
|
203
239
|
method: 'POST',
|
|
204
|
-
body: { value },
|
|
240
|
+
body: { value: label },
|
|
205
241
|
});
|
|
206
|
-
log(`chose ${decisionId} = ${
|
|
242
|
+
log(`chose ${decisionId} = ${label}`);
|
|
207
243
|
log(`-> ${JSON.stringify(result)}`);
|
|
208
244
|
return 0;
|
|
209
245
|
} catch (err) {
|
|
@@ -237,7 +273,8 @@ Examples:
|
|
|
237
273
|
$ commonly inbox list --cursor-file ~/.commonly/inbox/connector-ops.cursor # only what is new
|
|
238
274
|
$ commonly inbox list --cursor-file ~/.commonly/inbox/c.cursor --window 300 # widen the re-read to 5m
|
|
239
275
|
$ commonly inbox ack <attentionItemId>
|
|
240
|
-
$ commonly inbox choose <decisionId> 2
|
|
276
|
+
$ commonly inbox choose <decisionId> 2 # second option of the card, by position
|
|
277
|
+
$ commonly inbox choose <decisionId> "Ship it" # or by its label
|
|
241
278
|
|
|
242
279
|
Cost: with no cursor, \`list\` reads the WHOLE queue, one request per 50 items —
|
|
243
280
|
550 open items is 11 requests. /api/activity is limited to 60 a minute **keyed on
|
|
@@ -285,7 +322,7 @@ their attention as runtime events, not from this queue.
|
|
|
285
322
|
|
|
286
323
|
inbox
|
|
287
324
|
.command('choose <decisionId> <value>')
|
|
288
|
-
.description('Rule a decision card (the source= id from `list`)')
|
|
325
|
+
.description('Rule a decision card (the source= id from `list`). <value> is an option number (1-based) or its label')
|
|
289
326
|
.option('--token-file <path>', INBOX_TOKEN_HELP)
|
|
290
327
|
.option('--instance <url>', 'Target Commonly instance')
|
|
291
328
|
.action(async (decisionId, value, opts) => { process.exit(await runInboxChoose(decisionId, value, opts)); });
|