@stage5/lumine 0.2.25 → 0.2.26

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/README.md CHANGED
@@ -180,6 +180,7 @@ lumine admin featured list --json
180
180
  lumine admin subject feature 123 --json
181
181
  lumine admin subject unfeature 123 --json
182
182
  lumine admin featured reorder --subject-ids 30,20,10 --json
183
+ lumine admin brief --days 3 --json
183
184
  lumine admin post recommend comment:456 --anyone-can-reward --reward-twinkles 3 --json
184
185
  lumine admin post reward comment:456 --twinkles 3 --json
185
186
  lumine admin daily-run complete --json
package/lib/admin.js CHANGED
@@ -580,6 +580,19 @@ export function parseAdminOperation(options) {
580
580
  );
581
581
  }
582
582
 
583
+ if (namespace === "brief" && !action) {
584
+ if (options.adminDays) {
585
+ const days = Number(options.adminDays);
586
+ if (!Number.isInteger(days) || days < 1 || days > 30) {
587
+ throw cliValidationError("--days must be an integer between 1 and 30.");
588
+ }
589
+ }
590
+ return readOperation(
591
+ "insights.brief",
592
+ withQuery("/cli/admin/insights/brief", { days: options.adminDays }),
593
+ );
594
+ }
595
+
583
596
  if (namespace === "audit" && (!action || action === "list")) {
584
597
  const runFilter = String(options.adminRun || "").trim();
585
598
  if (runFilter && !["current", "last"].includes(runFilter)) {
@@ -641,7 +654,7 @@ export function parseAdminOperation(options) {
641
654
  }
642
655
 
643
656
  throw cliValidationError(
644
- "Usage: lumine admin identity|daily-run|recommendations|post|subjects|subject|featured|comment|news|audit ...",
657
+ "Usage: lumine admin identity|daily-run|recommendations|post|subjects|subject|featured|comment|news|audit|brief ...",
645
658
  );
646
659
  }
647
660
 
package/lib/commands.js CHANGED
@@ -2188,6 +2188,7 @@ export function parseArgs(args) {
2188
2188
  adminTarget: raw.target ? String(raw.target) : "",
2189
2189
  adminActions: raw.actions ? String(raw.actions) : "",
2190
2190
  adminDate: raw.date ? String(raw.date) : "",
2191
+ adminDays: raw.days ? String(raw.days) : "",
2191
2192
  adminEditionId: raw.editionId ? String(raw.editionId) : "",
2192
2193
  adminLeaseToken: raw.leaseToken ? String(raw.leaseToken) : "",
2193
2194
  adminFile: raw.file ? String(raw.file) : "",
@@ -2525,6 +2526,7 @@ export function printHelp() {
2525
2526
  lumine admin comment draft <target> [--type subject|comment|aiStory|dailyReflection] [--identity zero|ciel|auto] [--json]
2526
2527
  lumine admin comment reply comment:<id> [--identity zero|ciel|auto] [--json]
2527
2528
  lumine admin comment post --draft-id <id> [--json]
2529
+ lumine admin brief [--days <1..30>] [--json]
2528
2530
  lumine admin audit [list] [--run current|last|<run-id>] [--target <target>] [--actions <a,b>] [--full] [--cursor <cursor>] [--json]
2529
2531
 
2530
2532
  Examples:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stage5/lumine",
3
- "version": "0.2.25",
3
+ "version": "0.2.26",
4
4
  "description": "Command line tools for launching Lumine builds on Twinkle.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1036,6 +1036,116 @@ type NewsClaim = Success<{
1036
1036
  type NewsSubmit = NewsStatus; // "success"; newspaper includes revisionNumber
1037
1037
  ```
1038
1038
 
1039
+ ## Daily brief (management insights)
1040
+
1041
+ ```bash
1042
+ lumine admin brief --json
1043
+ lumine admin brief --days 3 --json
1044
+ ```
1045
+
1046
+ Read-only management insights for the delegated workflow, windowed since the
1047
+ operator's last completed run by default (`--days 1..30` overrides; capped at
1048
+ 30 days). Call it early in every run — right after the newspaper check — and
1049
+ end every run report with an **"Insights for Mikey"** section carrying only
1050
+ the deltas and anomalies worth his time, next to the escalation list. Never
1051
+ dump raw sections at him.
1052
+
1053
+ Four sections (Mikey's chosen cut, 2026-08-10):
1054
+
1055
+ - `economy` — `topGainers` (coin-ledger aggregation over the window: gained,
1056
+ spent, net, current balance per user, Zero/Ciel excluded) and `topBalances`
1057
+ (current top-ten holders, also excluding Zero/Ciel). This is where
1058
+ alt-account farming, sudden windfalls, and "someone got a million coins in a
1059
+ week" surface with real numbers instead of secondhand kid gossip;
1060
+ cross-check outliers against the
1061
+ economy-manipulation escalation category.
1062
+ - `aiSpending` — a compact projection of the management AI-cost report:
1063
+ `summary`, top spending accounts, top risk groups. Unlike the other sections'
1064
+ exact `window.sinceTs`, this existing report is bucketed into whole UTC days;
1065
+ `aiSpending.days` includes today and may begin up to one day before the exact
1066
+ brief window. Flag accounts that jumped tiers or dominate that report period.
1067
+ May be `{ unavailable: true }` if the cost report fails; say so rather than
1068
+ guessing.
1069
+ - `notableCandidates` — kids (never bots, staff `userType`s, or users already
1070
+ on the Notable Users list) ranked by authored activity in the window, with
1071
+ `isNewUser` marking window-new signups. Use it to find the overlooked and
1072
+ rising users the editorial priorities exist for, and propose additions to
1073
+ Mikey's Notable Users list in the report — the run never edits that list
1074
+ itself.
1075
+ - `teachers` — every `userType='supermod'` account with per-window
1076
+ `subjectsPosted`, `commentsPosted`, `recommendationsGiven`, `rewardsGiven`,
1077
+ `rewardTwinklesGiven`, `lastActive`/`daysSinceActive`, ordered by an
1078
+ engagement score. Mikey's standing question here: which teachers genuinely
1079
+ use the website to its fullest and which only work through it. Authored
1080
+ posts and comments signal personal engagement; recommendations and rewards
1081
+ are the "work" verbs — report the contrast, not just the totals, and treat
1082
+ it as notable-users-but-for-teachers.
1083
+
1084
+ The command needs only an active run's `content:read` scope and mutates
1085
+ nothing; reading the brief is not audited content action. Window boundaries
1086
+ on the big append-only ledgers are found by binary-searching the PRIMARY key
1087
+ (several tables have no timeStamp index), avoiding lifetime scans; aggregation
1088
+ is still bounded to the selected 1–30 day window.
1089
+
1090
+ ```ts
1091
+ type InsightsBrief = Success<{
1092
+ window: {
1093
+ sinceTs: number;
1094
+ days: number;
1095
+ source: 'requested' | 'since-last-completed-run' | 'default';
1096
+ generatedAt: number;
1097
+ };
1098
+ economy: {
1099
+ topGainers: Array<{
1100
+ userId: number;
1101
+ username: string | null;
1102
+ userType: string | null;
1103
+ gained: number;
1104
+ spent: number;
1105
+ net: number;
1106
+ currentCoins: number;
1107
+ joinedAt: number | null;
1108
+ }>;
1109
+ topBalances: Array<{
1110
+ userId: number;
1111
+ username: string | null;
1112
+ userType: string | null;
1113
+ coins: number;
1114
+ }>;
1115
+ };
1116
+ notableCandidates: Array<{
1117
+ userId: number;
1118
+ username: string | null;
1119
+ subjectsPosted: number;
1120
+ commentsPosted: number;
1121
+ activityScore: number;
1122
+ joinedAt: number | null;
1123
+ isNewUser: boolean;
1124
+ lastActive: number | null;
1125
+ }>;
1126
+ teachers: Array<{
1127
+ userId: number;
1128
+ username: string | null;
1129
+ lastActive: number | null;
1130
+ daysSinceActive: number | null;
1131
+ subjectsPosted: number;
1132
+ commentsPosted: number;
1133
+ recommendationsGiven: number;
1134
+ rewardsGiven: number;
1135
+ rewardTwinklesGiven: number;
1136
+ engagementScore: number;
1137
+ }>;
1138
+ aiSpending:
1139
+ | {
1140
+ days: number;
1141
+ summary: unknown;
1142
+ topAccounts: unknown[];
1143
+ topRiskGroups: unknown[];
1144
+ }
1145
+ | { unavailable: true; error: string };
1146
+ }>;
1147
+ ```
1148
+
1039
1149
  ## Audit history
1040
1150
 
1041
1151
  ```bash