@enerlence/suntropy-cli 0.11.5 → 0.11.7
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/dist/bin/suntropy.js +101 -7
- package/dist/bin/suntropy.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/suntropy.js
CHANGED
|
@@ -7,7 +7,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
|
-
import { Command as
|
|
10
|
+
import { Command as Command4 } from "commander";
|
|
11
11
|
|
|
12
12
|
// src/config.ts
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -68,14 +68,16 @@ var SERVICE_PATHS = {
|
|
|
68
68
|
solar: "/solar",
|
|
69
69
|
templates: "/templates",
|
|
70
70
|
profiles: "/profiles",
|
|
71
|
-
periods: "/periods"
|
|
71
|
+
periods: "/periods",
|
|
72
|
+
notifications: "/notifications"
|
|
72
73
|
};
|
|
73
74
|
var LOCAL_PORTS = {
|
|
74
75
|
security: 8080,
|
|
75
76
|
solar: 8086,
|
|
76
77
|
templates: 8090,
|
|
77
78
|
profiles: 8085,
|
|
78
|
-
periods: 8084
|
|
79
|
+
periods: 8084,
|
|
80
|
+
notifications: 8093
|
|
79
81
|
};
|
|
80
82
|
function getServiceUrl(baseServer, service) {
|
|
81
83
|
if (baseServer.includes("localhost") || baseServer.match(/:\d+$/)) {
|
|
@@ -4475,6 +4477,96 @@ function registerGeocodeCommands(program2) {
|
|
|
4475
4477
|
});
|
|
4476
4478
|
}
|
|
4477
4479
|
|
|
4480
|
+
// src/commands/notifications/index.ts
|
|
4481
|
+
import { Option as Option2 } from "commander";
|
|
4482
|
+
function getGlobalOpts16(cmd) {
|
|
4483
|
+
let root = cmd;
|
|
4484
|
+
while (root.parent) root = root.parent;
|
|
4485
|
+
return root.opts();
|
|
4486
|
+
}
|
|
4487
|
+
var ALEXANDRIA_USER_UID = "alexandria";
|
|
4488
|
+
var SEVERITIES = ["info", "warning", "urgent"];
|
|
4489
|
+
function registerNotificationsCommands(program2) {
|
|
4490
|
+
const notifications = program2.command("notifications").description(
|
|
4491
|
+
"Send in-app (and email) notifications to Suntropy users.\nUseful for Alexandria to proactively tell a user a task is done, since a\ndirect/email execution leaves no study comment (and thus no auto-notification)."
|
|
4492
|
+
);
|
|
4493
|
+
notifications.command("send").description(
|
|
4494
|
+
`Send a notification to a user. It appears in the recipient's notification
|
|
4495
|
+
bell and, if enabled in their config, is also emailed. Sent FROM Alexandria
|
|
4496
|
+
by default so it is not shown as a self-notification.
|
|
4497
|
+
Examples:
|
|
4498
|
+
suntropy notifications send --to-user <userUID> --message "He terminado el estudio."
|
|
4499
|
+
suntropy notifications send --to-user <userUID> --title "Estudio listo" \\
|
|
4500
|
+
--message "Revisa los resultados." --study <solarStudyId> --mention`
|
|
4501
|
+
).requiredOption("--to-user <userUID>", "Recipient userUID (who gets notified)").requiredOption("--message <text>", "Notification body (supports Markdown)").option("--title <text>", "Notification title", "Alexandria").option("--severity <severity>", `Severity: ${SEVERITIES.join(" | ")}`, "info").option(
|
|
4502
|
+
"--mention",
|
|
4503
|
+
`Send as a mention (type new_mention) instead of an update (new_comment). Mentions are gated by the user's "mention" notification setting.`
|
|
4504
|
+
).option(
|
|
4505
|
+
"--study <solarStudyId>",
|
|
4506
|
+
"Link the notification to a solar study: makes it click-through to that study"
|
|
4507
|
+
).option("--link <url>", "Custom link for the email call-to-action").option(
|
|
4508
|
+
"--from-user <userUID>",
|
|
4509
|
+
"Sender userUID shown as the author (default: the authenticated user)"
|
|
4510
|
+
).addOption(new Option2("--as-alexandria").hideHelp()).action(async (opts) => {
|
|
4511
|
+
try {
|
|
4512
|
+
const global = getGlobalOpts16(notifications);
|
|
4513
|
+
const severity = opts.severity;
|
|
4514
|
+
if (!SEVERITIES.includes(severity)) {
|
|
4515
|
+
throw new Error(
|
|
4516
|
+
`Invalid --severity "${opts.severity}". Use one of: ${SEVERITIES.join(", ")}.`
|
|
4517
|
+
);
|
|
4518
|
+
}
|
|
4519
|
+
if (opts.study) assertStudyObjectId(opts.study);
|
|
4520
|
+
const client = createServiceClient("notifications", global);
|
|
4521
|
+
const profile = getActiveProfile(loadConfig());
|
|
4522
|
+
const fromUserUid = opts.fromUser ? opts.fromUser : opts.asAlexandria ? ALEXANDRIA_USER_UID : profile.userUID;
|
|
4523
|
+
const notification = {
|
|
4524
|
+
notificationType: opts.mention ? "new_mention" : "new_comment",
|
|
4525
|
+
severity,
|
|
4526
|
+
origin: opts.asAlexandria ? "ALEXANDRIA" : "CLI",
|
|
4527
|
+
fromUserUid,
|
|
4528
|
+
toUserUid: opts.toUser,
|
|
4529
|
+
notificationContent: {
|
|
4530
|
+
contentType: "COMMENT",
|
|
4531
|
+
name: opts.title,
|
|
4532
|
+
description: opts.message,
|
|
4533
|
+
...opts.study ? { externalId: opts.study } : {},
|
|
4534
|
+
...opts.link ? { link: opts.link } : {},
|
|
4535
|
+
// The notifications backend only persists notificationContent when a
|
|
4536
|
+
// `data` payload is present (the OneToOne isn't cascaded), so without
|
|
4537
|
+
// this the notification renders blank in the bell. Always send a
|
|
4538
|
+
// small data object; harmless once the backend also persists content
|
|
4539
|
+
// without it. Not read by the front for these types.
|
|
4540
|
+
data: {
|
|
4541
|
+
source: opts.asAlexandria ? "alexandria" : "cli",
|
|
4542
|
+
...opts.study ? { studyId: opts.study } : {}
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
4545
|
+
};
|
|
4546
|
+
const res = await client.post("/notifications", notification);
|
|
4547
|
+
if (typeof res.data === "string") {
|
|
4548
|
+
output(
|
|
4549
|
+
{ sent: false, reason: res.data, toUser: opts.toUser },
|
|
4550
|
+
global
|
|
4551
|
+
);
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4554
|
+
output(
|
|
4555
|
+
{
|
|
4556
|
+
sent: true,
|
|
4557
|
+
notificationId: res.data?.idNotification,
|
|
4558
|
+
toUser: opts.toUser,
|
|
4559
|
+
type: notification.notificationType,
|
|
4560
|
+
severity
|
|
4561
|
+
},
|
|
4562
|
+
global
|
|
4563
|
+
);
|
|
4564
|
+
} catch (err) {
|
|
4565
|
+
outputError(handleApiError(err));
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4478
4570
|
// src/access.ts
|
|
4479
4571
|
var COMMAND_TIERS = ["read", "write", "delete"];
|
|
4480
4572
|
var TIER_VALUE = { read: 0, write: 1, delete: 2 };
|
|
@@ -4525,6 +4617,7 @@ var WRITE_VERBS = /* @__PURE__ */ new Set([
|
|
|
4525
4617
|
"init-default",
|
|
4526
4618
|
"add-comment",
|
|
4527
4619
|
"comment",
|
|
4620
|
+
"send",
|
|
4528
4621
|
"calculate-results",
|
|
4529
4622
|
"optimize-peakpower"
|
|
4530
4623
|
]);
|
|
@@ -4573,7 +4666,7 @@ function keepCommand(cmd, segs, max) {
|
|
|
4573
4666
|
}
|
|
4574
4667
|
|
|
4575
4668
|
// src/commands/command-profile.ts
|
|
4576
|
-
function
|
|
4669
|
+
function getGlobalOpts17(cmd) {
|
|
4577
4670
|
let root = cmd;
|
|
4578
4671
|
while (root.parent) root = root.parent;
|
|
4579
4672
|
return root.opts();
|
|
@@ -4581,7 +4674,7 @@ function getGlobalOpts16(cmd) {
|
|
|
4581
4674
|
function registerCommandProfileCommand(program2) {
|
|
4582
4675
|
program2.command("command-profile [tier]", { hidden: true }).description("Admin: get/set the command access profile (read | write | delete | reset)").action((tier) => {
|
|
4583
4676
|
try {
|
|
4584
|
-
const global =
|
|
4677
|
+
const global = getGlobalOpts17(program2);
|
|
4585
4678
|
if (!tier) {
|
|
4586
4679
|
const resolved = getActiveCommandProfile();
|
|
4587
4680
|
output(
|
|
@@ -4636,9 +4729,9 @@ function registerCommandProfileCommand(program2) {
|
|
|
4636
4729
|
}
|
|
4637
4730
|
|
|
4638
4731
|
// src/index.ts
|
|
4639
|
-
var CLI_VERSION = true ? "0.11.
|
|
4732
|
+
var CLI_VERSION = true ? "0.11.7" : "0.0.0-dev";
|
|
4640
4733
|
function createProgram() {
|
|
4641
|
-
const program2 = new
|
|
4734
|
+
const program2 = new Command4();
|
|
4642
4735
|
program2.name("suntropy").description("Agent-first CLI for Suntropy solar platform. Optimized for programmatic data manipulation and progressive exploration.").version(CLI_VERSION).option("--format <format>", "Output format: json (default), human, csv", "json").option("--fields <fields>", "Comma-separated fields to include in output").option("--server <url>", "Override API server URL").option("--token <jwt>", "Override authentication token").option("--profile <name>", "Use a specific config profile").option("--verbose", "Show HTTP request/response details on stderr").option("--quiet", "Suppress non-data output").option("--save <file>", "Save output to file (also writes to stdout)");
|
|
4643
4736
|
registerAuthCommands(program2);
|
|
4644
4737
|
registerConfigCommands(program2);
|
|
@@ -4651,6 +4744,7 @@ function createProgram() {
|
|
|
4651
4744
|
registerShareableCommands(program2);
|
|
4652
4745
|
registerTemplatesCommands(program2);
|
|
4653
4746
|
registerGeocodeCommands(program2);
|
|
4747
|
+
registerNotificationsCommands(program2);
|
|
4654
4748
|
registerCommandProfileCommand(program2);
|
|
4655
4749
|
applyCommandProfile(program2);
|
|
4656
4750
|
return program2;
|