@arbidocs/cli 0.4.32 → 0.4.37
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 +201 -2
- package/SKILL.md +20 -0
- package/dist/index.js +281 -16
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3694,7 +3694,7 @@ function getLatestVersion(skipCache = false) {
|
|
|
3694
3694
|
}
|
|
3695
3695
|
}
|
|
3696
3696
|
function getCurrentVersion() {
|
|
3697
|
-
return "0.4.
|
|
3697
|
+
return "0.4.37";
|
|
3698
3698
|
}
|
|
3699
3699
|
function readChangelog(fromVersion, toVersion) {
|
|
3700
3700
|
try {
|
|
@@ -3747,17 +3747,17 @@ function showChangelog(fromVersion, toVersion) {
|
|
|
3747
3747
|
async function checkForUpdates(autoUpdate) {
|
|
3748
3748
|
try {
|
|
3749
3749
|
const latest = getLatestVersion();
|
|
3750
|
-
if (!latest || latest === "0.4.
|
|
3750
|
+
if (!latest || latest === "0.4.37") return;
|
|
3751
3751
|
if (autoUpdate) {
|
|
3752
3752
|
warn(`
|
|
3753
|
-
Your arbi version is out of date (${"0.4.
|
|
3753
|
+
Your arbi version is out of date (${"0.4.37"} \u2192 ${latest}). Updating...`);
|
|
3754
3754
|
child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
|
|
3755
|
-
showChangelog("0.4.
|
|
3755
|
+
showChangelog("0.4.37", latest);
|
|
3756
3756
|
console.log(`Updated to ${latest}.`);
|
|
3757
3757
|
} else {
|
|
3758
3758
|
warn(
|
|
3759
3759
|
`
|
|
3760
|
-
Your arbi version is out of date (${"0.4.
|
|
3760
|
+
Your arbi version is out of date (${"0.4.37"} \u2192 ${latest}).
|
|
3761
3761
|
Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
3762
3762
|
);
|
|
3763
3763
|
}
|
|
@@ -3789,10 +3789,10 @@ function markNagShown(latest) {
|
|
|
3789
3789
|
function hintUpdateOnError() {
|
|
3790
3790
|
try {
|
|
3791
3791
|
const cached = readCache();
|
|
3792
|
-
if (!cached || cached.latest === "0.4.
|
|
3792
|
+
if (!cached || cached.latest === "0.4.37") return;
|
|
3793
3793
|
if (!shouldShowNag(cached.latest)) return;
|
|
3794
3794
|
warn(
|
|
3795
|
-
`Your arbi version is out of date (${"0.4.
|
|
3795
|
+
`Your arbi version is out of date (${"0.4.37"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3796
3796
|
);
|
|
3797
3797
|
markNagShown(cached.latest);
|
|
3798
3798
|
} catch {
|
|
@@ -9583,7 +9583,7 @@ function resolveTaskId(taskIdArg) {
|
|
|
9583
9583
|
}
|
|
9584
9584
|
function statusColor2(s) {
|
|
9585
9585
|
if (s === "completed") return chalk2__default.default.green(s);
|
|
9586
|
-
if (s === "failed") return chalk2__default.default.red(s);
|
|
9586
|
+
if (s === "failed" || s === "cancelled") return chalk2__default.default.red(s);
|
|
9587
9587
|
if (s === "queued" || s === "in_progress") return chalk2__default.default.yellow(s);
|
|
9588
9588
|
return s;
|
|
9589
9589
|
}
|
|
@@ -9633,7 +9633,7 @@ function registerTaskCommand(program2) {
|
|
|
9633
9633
|
const id = resolveTaskId(taskId);
|
|
9634
9634
|
const { accessToken, config } = await resolveWorkspace(opts?.workspace);
|
|
9635
9635
|
const result = await sdk.responses.getResponse({ baseUrl: config.baseUrl, accessToken }, id);
|
|
9636
|
-
if (result.status === "completed" || result.status === "failed") {
|
|
9636
|
+
if (result.status === "completed" || result.status === "failed" || result.status === "cancelled") {
|
|
9637
9637
|
updateTaskStatus(id, result.status);
|
|
9638
9638
|
}
|
|
9639
9639
|
if (opts?.json) {
|
|
@@ -9653,7 +9653,7 @@ function registerTaskCommand(program2) {
|
|
|
9653
9653
|
const id = resolveTaskId(taskId);
|
|
9654
9654
|
const { accessToken, config } = await resolveWorkspace(opts?.workspace);
|
|
9655
9655
|
const result = await sdk.responses.getResponse({ baseUrl: config.baseUrl, accessToken }, id);
|
|
9656
|
-
if (result.status === "completed" || result.status === "failed") {
|
|
9656
|
+
if (result.status === "completed" || result.status === "failed" || result.status === "cancelled") {
|
|
9657
9657
|
updateTaskStatus(id, result.status);
|
|
9658
9658
|
}
|
|
9659
9659
|
if (opts?.json) {
|
|
@@ -9675,8 +9675,12 @@ function registerTaskCommand(program2) {
|
|
|
9675
9675
|
);
|
|
9676
9676
|
}
|
|
9677
9677
|
function registerWorkflowCommand(program2) {
|
|
9678
|
-
const workflow = program2.command("workflow").description("Workflows (/v1/workflow): create, list, resume, pause, run, delete");
|
|
9679
|
-
workflow.command("create").description("Create a workflow with exactly one trigger").requiredOption("--name <name>", "Workflow name (required)").option("--rrule <RRULE>", "Trigger: RFC-5545 recurrence rule").option("--run-at <ISO>", "Trigger: run once at this time (ISO-8601)").option("--event-kind <kind>", "Trigger: a notification type to react to").option("--after <con-id>", "Trigger: when this task (conversation) is done").option("--timezone <tz>", "IANA timezone for --rrule", "UTC").option("--
|
|
9678
|
+
const workflow = program2.command("workflow").alias("automation").description("Workflows (/v1/workflow): create, list, resume, pause, run, delete");
|
|
9679
|
+
workflow.command("create").description("Create a workflow with exactly one trigger").requiredOption("--name <name>", "Workflow name (required)").option("--rrule <RRULE>", "Trigger: RFC-5545 recurrence rule").option("--run-at <ISO>", "Trigger: run once at this time (ISO-8601)").option("--event-kind <kind>", "Trigger: a notification type to react to").option("--after <con-id>", "Trigger: when this task (conversation) is done").option("--timezone <tz>", "IANA timezone for --rrule", "UTC").option("--action <type>", "Action: annotate_documents or email_documents").option("--documents <ids>", "Comma-separated document IDs").option("--labels <ids>", "Select documents matching these label IDs at execution time").option("--latest", "Select documents uploaded since the previous successful run").option("--tags <ids>", "Annotation field IDs for AI review").option("--overwrite", "Regenerate existing annotation answers").option(
|
|
9680
|
+
"--auth-mode <mode>",
|
|
9681
|
+
"scheduled_require_auth or scheduled_permanent",
|
|
9682
|
+
"scheduled_require_auth"
|
|
9683
|
+
).option("--event-filter <json>", "Notification attribute filters as a JSON object").option("--prompt <text>", "Instruction the agent runs").option("--skill <ref>", "Skill reference to run").option("--agent <agt-id>", "Agent to run it as (external id)").option("--workspace <wrk-id>", "Workspace to scope the workflow to (default: the current one)").option("--shared", "Share it with the workspace").option("--json", "Output as JSON").action(
|
|
9680
9684
|
(opts) => runAction(async () => {
|
|
9681
9685
|
const { arbi, workspaceId } = await resolveWorkspace();
|
|
9682
9686
|
const body = {
|
|
@@ -9688,9 +9692,31 @@ function registerWorkflowCommand(program2) {
|
|
|
9688
9692
|
timezone: opts.timezone,
|
|
9689
9693
|
prompt: opts.prompt ?? "",
|
|
9690
9694
|
// Unattended runs ask the owner for access each time unless the workflow is made permanent.
|
|
9691
|
-
auth_mode:
|
|
9695
|
+
auth_mode: opts.authMode,
|
|
9692
9696
|
workspace_ext_id: opts.workspace ?? workspaceId
|
|
9693
9697
|
};
|
|
9698
|
+
if (!["scheduled_require_auth", "scheduled_permanent"].includes(opts.authMode)) {
|
|
9699
|
+
throw new Error(
|
|
9700
|
+
"Invalid --auth-mode: use scheduled_require_auth or scheduled_permanent"
|
|
9701
|
+
);
|
|
9702
|
+
}
|
|
9703
|
+
if (opts.action) {
|
|
9704
|
+
if (!["annotate_documents", "email_documents"].includes(opts.action)) {
|
|
9705
|
+
throw new Error("Invalid --action: use annotate_documents or email_documents");
|
|
9706
|
+
}
|
|
9707
|
+
const ids = (value) => value?.split(",").map((id) => id.trim()).filter(Boolean) ?? [];
|
|
9708
|
+
body.action = {
|
|
9709
|
+
type: opts.action,
|
|
9710
|
+
documents: {
|
|
9711
|
+
doc_ext_ids: ids(opts.documents),
|
|
9712
|
+
label_ext_ids: ids(opts.labels),
|
|
9713
|
+
latest: !!opts.latest
|
|
9714
|
+
},
|
|
9715
|
+
tag_ext_ids: ids(opts.tags),
|
|
9716
|
+
overwrite: !!opts.overwrite
|
|
9717
|
+
};
|
|
9718
|
+
}
|
|
9719
|
+
if (opts.eventFilter) body.event_filter = JSON.parse(opts.eventFilter);
|
|
9694
9720
|
if (opts.rrule) body.rrule = opts.rrule;
|
|
9695
9721
|
if (opts.runAt) body.run_at = opts.runAt;
|
|
9696
9722
|
if (opts.eventKind) body.event_kind = opts.eventKind;
|
|
@@ -9735,7 +9761,7 @@ function registerWorkflowCommand(program2) {
|
|
|
9735
9761
|
})()
|
|
9736
9762
|
);
|
|
9737
9763
|
}
|
|
9738
|
-
workflow.command("run <id>").description("
|
|
9764
|
+
workflow.command("run <id>").description("Start the saved action now (document actions do not create a thread)").option("--json", "Output as JSON").action(
|
|
9739
9765
|
(id, opts) => runAction(async () => {
|
|
9740
9766
|
const { arbi } = await resolveAuth();
|
|
9741
9767
|
const data = await sdk.workflows.runWorkflow(arbi, id);
|
|
@@ -9743,7 +9769,47 @@ function registerWorkflowCommand(program2) {
|
|
|
9743
9769
|
printJson(data);
|
|
9744
9770
|
return;
|
|
9745
9771
|
}
|
|
9746
|
-
|
|
9772
|
+
if (data.error) throw new Error(data.error);
|
|
9773
|
+
success(
|
|
9774
|
+
`${data.started ? "Started" : "Submitted"} automation ${ref(id)}${data.execution_id ? ` \u2014 execution ${data.execution_id}` : ""}${data.conversation_ext_id ? ` \u2014 thread ${ref(data.conversation_ext_id)}` : ""}`
|
|
9775
|
+
);
|
|
9776
|
+
})()
|
|
9777
|
+
);
|
|
9778
|
+
workflow.command("get <id>").description("Read the complete saved automation configuration").action(
|
|
9779
|
+
(id) => runAction(async () => {
|
|
9780
|
+
const { arbi } = await resolveAuth();
|
|
9781
|
+
printJson(await sdk.workflows.getWorkflow(arbi, id));
|
|
9782
|
+
})()
|
|
9783
|
+
);
|
|
9784
|
+
workflow.command("runs <id>").alias("executions").description("Show persisted document-action runs, results and failures").option("--json", "Output as JSON").action(
|
|
9785
|
+
(id, opts) => runAction(async () => {
|
|
9786
|
+
const { arbi } = await resolveAuth();
|
|
9787
|
+
const data = await sdk.workflows.listWorkflowRuns(arbi, id);
|
|
9788
|
+
if (!emitListOrTable(data, opts, "This automation has not run yet.")) return;
|
|
9789
|
+
printTable(
|
|
9790
|
+
[
|
|
9791
|
+
{ header: "RUN", width: 10, value: (r) => String(r.id) },
|
|
9792
|
+
{ header: "STATUS", width: 14, value: (r) => String(r.status) },
|
|
9793
|
+
{ header: "ACTION", width: 22, value: (r) => String(r.action_type) },
|
|
9794
|
+
{
|
|
9795
|
+
header: "DOCUMENTS",
|
|
9796
|
+
width: 12,
|
|
9797
|
+
value: (r) => String(r.document_ext_ids.length)
|
|
9798
|
+
},
|
|
9799
|
+
{ header: "CREATED", width: 26, value: (r) => String(r.created_at) },
|
|
9800
|
+
{ header: "ERROR", width: 40, value: (r) => String(r.error ?? "") }
|
|
9801
|
+
],
|
|
9802
|
+
data
|
|
9803
|
+
);
|
|
9804
|
+
})()
|
|
9805
|
+
);
|
|
9806
|
+
workflow.command("update <id>").description("Update any saved automation settings from a JSON file").requiredOption("--file <path>", "JSON UpdateWorkflowRequest file").option("--json", "Output as JSON").action(
|
|
9807
|
+
(id, opts) => runAction(async () => {
|
|
9808
|
+
const { arbi } = await resolveAuth();
|
|
9809
|
+
const body = JSON.parse(fs5.readFileSync(opts.file, "utf8"));
|
|
9810
|
+
const data = await sdk.workflows.updateWorkflow(arbi, id, body);
|
|
9811
|
+
if (opts.json) printJson(data);
|
|
9812
|
+
else success(`Updated automation ${ref(id)}`);
|
|
9747
9813
|
})()
|
|
9748
9814
|
);
|
|
9749
9815
|
workflow.command("delete <id>").description("Delete a workflow (tasks it already created stay)").action(
|
|
@@ -10045,6 +10111,204 @@ function registerSessionCommand(program2) {
|
|
|
10045
10111
|
await session.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
10046
10112
|
});
|
|
10047
10113
|
}
|
|
10114
|
+
function parseAddress(value) {
|
|
10115
|
+
const match = /^\s*(.*?)\s*<([^<>\s]+)>\s*$/.exec(value);
|
|
10116
|
+
const email = (match ? match[2] : value).trim();
|
|
10117
|
+
if (!/^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/.test(email)) {
|
|
10118
|
+
throw new Error(`Not an email address: ${value}`);
|
|
10119
|
+
}
|
|
10120
|
+
const name = match?.[1].replace(/^"|"$/g, "");
|
|
10121
|
+
return name ? { email, name } : { email };
|
|
10122
|
+
}
|
|
10123
|
+
function collect(value, previous = []) {
|
|
10124
|
+
return [...previous, ...value.split(",").filter((v) => v.trim())];
|
|
10125
|
+
}
|
|
10126
|
+
var readTextFile = (path7) => fs5__default.default.readFileSync(path7 === "-" ? 0 : path7, "utf8");
|
|
10127
|
+
function buildCompose(options) {
|
|
10128
|
+
const read = options.readText ?? readTextFile;
|
|
10129
|
+
if (options.text !== void 0 && options.textFile) {
|
|
10130
|
+
throw new Error("Use either --text or --text-file, not both");
|
|
10131
|
+
}
|
|
10132
|
+
if (options.html !== void 0 && options.htmlFile) {
|
|
10133
|
+
throw new Error("Use either --html or --html-file, not both");
|
|
10134
|
+
}
|
|
10135
|
+
const html = options.html ?? (options.htmlFile ? read(options.htmlFile) : void 0);
|
|
10136
|
+
return {
|
|
10137
|
+
to: (options.to ?? []).map(parseAddress),
|
|
10138
|
+
cc: (options.cc ?? []).map(parseAddress),
|
|
10139
|
+
bcc: (options.bcc ?? []).map(parseAddress),
|
|
10140
|
+
subject: options.subject ?? "",
|
|
10141
|
+
text: options.text ?? (options.textFile ? read(options.textFile) : ""),
|
|
10142
|
+
...html ? { html } : {},
|
|
10143
|
+
secure_delivery: false,
|
|
10144
|
+
attachments: (options.attach ?? []).map((file) => sdk.mailNode.attachmentFromFile(file))
|
|
10145
|
+
};
|
|
10146
|
+
}
|
|
10147
|
+
function addComposeOptions(command) {
|
|
10148
|
+
return command.option("--to <addresses>", "Recipient(s), comma-separated or repeated", collect).option("--cc <addresses>", "Cc recipient(s)", collect).option("--bcc <addresses>", "Bcc recipient(s)", collect).option("-s, --subject <subject>", "Subject").option("--text <text>", "Plain-text body").option("--text-file <path>", "Read the plain-text body from a file (- for stdin)").option("--html <html>", "HTML body (the plain text stays as the fallback)").option("--html-file <path>", "Read the HTML body from a file (- for stdin)").option("-a, --attach <path>", "Attach a file (repeatable)", (v, prev = []) => [
|
|
10149
|
+
...prev,
|
|
10150
|
+
v
|
|
10151
|
+
]).option("--json", "Output as JSON (recommended for scripting / agents)");
|
|
10152
|
+
}
|
|
10153
|
+
function registerMailCommand(program2) {
|
|
10154
|
+
const mail = program2.command("mail").enablePositionalOptions().description("Your ARBI mailbox: read, draft and send (an agent can only draft)");
|
|
10155
|
+
async function connect() {
|
|
10156
|
+
const { loginResult, config } = await resolveAuth();
|
|
10157
|
+
return {
|
|
10158
|
+
fetch: sdk.mail.createMailFetch({
|
|
10159
|
+
baseUrl: config.baseUrl,
|
|
10160
|
+
accessToken: loginResult.accessToken
|
|
10161
|
+
}),
|
|
10162
|
+
login: loginResult,
|
|
10163
|
+
isAgent: Boolean(loginResult.parentExtId)
|
|
10164
|
+
};
|
|
10165
|
+
}
|
|
10166
|
+
async function connectToRead() {
|
|
10167
|
+
const ctx = await connect();
|
|
10168
|
+
if (ctx.isAgent) {
|
|
10169
|
+
error("Agents can only create drafts. Use: arbi mail draft --to <address> ...");
|
|
10170
|
+
process.exit(1);
|
|
10171
|
+
}
|
|
10172
|
+
await sdk.mail.unlockNativeMail(ctx.fetch, {
|
|
10173
|
+
signingPrivateKey: ctx.login.signingPrivateKey,
|
|
10174
|
+
serverSessionKey: ctx.login.serverSessionKey
|
|
10175
|
+
});
|
|
10176
|
+
return ctx;
|
|
10177
|
+
}
|
|
10178
|
+
mail.command("alias <name>").description("Claim your ARBI address, name@<deployment domain> (one per user)").action(
|
|
10179
|
+
(name) => runAction(async () => {
|
|
10180
|
+
const { fetch: fetch2 } = await connect();
|
|
10181
|
+
success(`Your ARBI email is ${await sdk.mail.claimNativeAlias(fetch2, name.toLowerCase())}`);
|
|
10182
|
+
})()
|
|
10183
|
+
);
|
|
10184
|
+
mail.command("folders").description("List folders with unread counts").option("--json", "Output as JSON").action(
|
|
10185
|
+
(opts) => runAction(async () => {
|
|
10186
|
+
const { fetch: fetch2 } = await connectToRead();
|
|
10187
|
+
const folders = await sdk.mail.listFolders(fetch2);
|
|
10188
|
+
if (opts.json) return printJson(folders);
|
|
10189
|
+
printTable(
|
|
10190
|
+
[
|
|
10191
|
+
{ header: "ID", width: 14, value: (f) => f.id },
|
|
10192
|
+
{ header: "NAME", width: 20, value: (f) => f.name },
|
|
10193
|
+
{ header: "UNREAD", width: 8, value: (f) => String(f.unread ?? 0) }
|
|
10194
|
+
],
|
|
10195
|
+
folders
|
|
10196
|
+
);
|
|
10197
|
+
})()
|
|
10198
|
+
);
|
|
10199
|
+
mail.command("list").description("List messages in a folder (default: inbox)").option("-f, --folder <id>", "Folder id: inbox, sent, drafts, archive, trash", "inbox").option("-q, --query <text>", "Filter by subject, sender or recipient").option("-l, --limit <n>", "Messages per page", (v) => parseInt(v, 10), 30).option("--cursor <cursor>", "Continue from a previous page (its next_cursor)").option("--json", "Output as JSON (includes next_cursor)").action(
|
|
10200
|
+
(opts) => runAction(async () => {
|
|
10201
|
+
const { fetch: fetch2 } = await connectToRead();
|
|
10202
|
+
const page = await sdk.mail.listMessages(fetch2, {
|
|
10203
|
+
folderId: opts.folder,
|
|
10204
|
+
query: opts.query,
|
|
10205
|
+
limit: opts.limit,
|
|
10206
|
+
cursor: opts.cursor
|
|
10207
|
+
});
|
|
10208
|
+
if (opts.json) return printJson(page);
|
|
10209
|
+
if (page.messages.length === 0) {
|
|
10210
|
+
process.stderr.write("No messages.\n");
|
|
10211
|
+
return;
|
|
10212
|
+
}
|
|
10213
|
+
const people = (m) => (["sent", "drafts"].includes(opts.folder) ? m.to : m.sender).map((a) => a.name || a.email).join(", ");
|
|
10214
|
+
printTable(
|
|
10215
|
+
[
|
|
10216
|
+
{ header: "ID", width: 38, value: (m) => m.id },
|
|
10217
|
+
{ header: "WHO", width: 24, value: (m) => truncate(people(m), 23) },
|
|
10218
|
+
{
|
|
10219
|
+
header: "SUBJECT",
|
|
10220
|
+
width: 40,
|
|
10221
|
+
value: (m) => truncate(m.subject || "(no subject)", 39)
|
|
10222
|
+
},
|
|
10223
|
+
{
|
|
10224
|
+
header: "FLAGS",
|
|
10225
|
+
width: 14,
|
|
10226
|
+
value: (m) => [
|
|
10227
|
+
m.unread ? "unread" : "",
|
|
10228
|
+
m.attachments.length ? "attach" : "",
|
|
10229
|
+
m.drafted_by ? `by ${m.drafted_by}` : ""
|
|
10230
|
+
].filter(Boolean).join(" ")
|
|
10231
|
+
}
|
|
10232
|
+
],
|
|
10233
|
+
page.messages
|
|
10234
|
+
);
|
|
10235
|
+
if (page.next_cursor) dim(`More: --cursor ${page.next_cursor}`);
|
|
10236
|
+
})()
|
|
10237
|
+
);
|
|
10238
|
+
mail.command("read <id>").description("Read a message, or save one of its attachments with --attachment").option("--attachment <id>", "Save this attachment (id from the attachment list) instead").option("-o, --output <path>", "Where to save the attachment (default: its file name)").option("--json", "Output the full message as JSON").action(
|
|
10239
|
+
(id, opts) => runAction(async () => {
|
|
10240
|
+
const { fetch: fetch2 } = await connectToRead();
|
|
10241
|
+
const message = await sdk.mail.getMessage(fetch2, id);
|
|
10242
|
+
if (opts.attachment !== void 0) {
|
|
10243
|
+
const meta = message.attachments.find((a) => a.id === opts.attachment);
|
|
10244
|
+
if (!meta) throw new Error(`No attachment ${opts.attachment} on this message`);
|
|
10245
|
+
const bytes = await sdk.mail.downloadAttachment(fetch2, id, meta.id);
|
|
10246
|
+
const target = opts.output ?? meta.name;
|
|
10247
|
+
fs5__default.default.writeFileSync(target, bytes);
|
|
10248
|
+
success(`Saved ${target} (${bytes.length} bytes)`);
|
|
10249
|
+
return;
|
|
10250
|
+
}
|
|
10251
|
+
if (opts.json) return printJson(message);
|
|
10252
|
+
const who = (list) => list.map((a) => a.name ? `${a.name} <${a.email}>` : a.email).join(", ");
|
|
10253
|
+
console.log(`From: ${who(message.sender)}`);
|
|
10254
|
+
console.log(`To: ${who(message.to)}`);
|
|
10255
|
+
if (message.cc.length) console.log(`Cc: ${who(message.cc)}`);
|
|
10256
|
+
console.log(`Subject: ${message.subject}`);
|
|
10257
|
+
if (message.received_at) console.log(`Date: ${message.received_at}`);
|
|
10258
|
+
if (message.drafted_by) console.log(`Drafted by: ${message.drafted_by}`);
|
|
10259
|
+
if (message.attachments.length) {
|
|
10260
|
+
console.log(
|
|
10261
|
+
`Attachments: ${message.attachments.map((a) => `${a.name} (id ${a.id}, ${a.size} bytes)`).join("; ")}`
|
|
10262
|
+
);
|
|
10263
|
+
}
|
|
10264
|
+
console.log(`
|
|
10265
|
+
${message.text}`);
|
|
10266
|
+
})()
|
|
10267
|
+
);
|
|
10268
|
+
addComposeOptions(
|
|
10269
|
+
mail.command("draft").description(
|
|
10270
|
+
"Save a draft. Run by an agent, it goes to its owner's Drafts, from their address, for them to review and send"
|
|
10271
|
+
)
|
|
10272
|
+
).action(
|
|
10273
|
+
(opts) => runAction(async () => {
|
|
10274
|
+
const compose = buildCompose(opts);
|
|
10275
|
+
const { fetch: fetch2, isAgent } = await connect();
|
|
10276
|
+
const saved = await sdk.mail.saveDraft(fetch2, compose);
|
|
10277
|
+
if (opts.json) return printJson(saved);
|
|
10278
|
+
success(
|
|
10279
|
+
isAgent ? `Draft ${saved.id} saved to your owner's Drafts. They review it and send.` : `Draft ${saved.id} saved to Drafts.`
|
|
10280
|
+
);
|
|
10281
|
+
})()
|
|
10282
|
+
);
|
|
10283
|
+
addComposeOptions(
|
|
10284
|
+
mail.command("send").description("Send a message from your ARBI address (not available to agents)")
|
|
10285
|
+
).option("--request-id <id>", "Idempotency key: retrying with the same id never sends twice").action(
|
|
10286
|
+
(opts) => runAction(async () => {
|
|
10287
|
+
const compose = buildCompose(opts);
|
|
10288
|
+
if (compose.to?.length === 0 && compose.cc?.length === 0 && compose.bcc?.length === 0) {
|
|
10289
|
+
throw new Error("Add at least one recipient with --to, --cc or --bcc");
|
|
10290
|
+
}
|
|
10291
|
+
const { fetch: fetch2, isAgent } = await connect();
|
|
10292
|
+
if (isAgent) {
|
|
10293
|
+
error("Agents cannot send mail. Save a draft instead: arbi mail draft ...");
|
|
10294
|
+
process.exit(1);
|
|
10295
|
+
}
|
|
10296
|
+
const result = await sdk.mail.sendMessage(fetch2, { ...compose, request_id: opts.requestId });
|
|
10297
|
+
if (opts.json) return printJson(result);
|
|
10298
|
+
success(`Sent (${result.id}).`);
|
|
10299
|
+
})()
|
|
10300
|
+
);
|
|
10301
|
+
mail.arguments("[maybeSubcommand]").action((maybe) => {
|
|
10302
|
+
if (maybe) {
|
|
10303
|
+
suggestSubcommandAndExit(
|
|
10304
|
+
"mail",
|
|
10305
|
+
maybe,
|
|
10306
|
+
mail.commands.map((c) => c.name())
|
|
10307
|
+
);
|
|
10308
|
+
}
|
|
10309
|
+
mail.outputHelp();
|
|
10310
|
+
});
|
|
10311
|
+
}
|
|
10048
10312
|
function registerNotificationsCommand(program2) {
|
|
10049
10313
|
const notif = program2.command("notifications").enablePositionalOptions().description("Non-DM notifications");
|
|
10050
10314
|
notif.command("list").description("List non-DM notifications (workspace invites, contact accepts, \u2026)").option("--unread", "Only show unread notifications").option("--type <comma-list>", "Filter to specific type(s), e.g. workspaceuser_invited").option("-l, --limit <n>", "Cap to N most-recent", (v) => parseInt(v, 10)).option("--json", "Output as JSON (recommended for scripting / agents)").action(
|
|
@@ -10610,7 +10874,7 @@ console.info = (...args) => {
|
|
|
10610
10874
|
_origInfo(...args);
|
|
10611
10875
|
};
|
|
10612
10876
|
var program = new commander.Command();
|
|
10613
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.4.
|
|
10877
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.4.37").showHelpAfterError(true).showSuggestionAfterError(true);
|
|
10614
10878
|
registerConfigCommand(program);
|
|
10615
10879
|
registerLoginCommand(program);
|
|
10616
10880
|
registerRegisterCommand(program);
|
|
@@ -10645,6 +10909,7 @@ registerListenCommand(program);
|
|
|
10645
10909
|
registerSessionCommand(program);
|
|
10646
10910
|
registerLocalCommand(program);
|
|
10647
10911
|
registerNotificationsCommand(program);
|
|
10912
|
+
registerMailCommand(program);
|
|
10648
10913
|
registerProjectCommand(program);
|
|
10649
10914
|
registerFilesCommand(program);
|
|
10650
10915
|
registerUsageCommand(program);
|