@stage5/lumine 0.2.52 → 0.2.54
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 +63 -1
- package/lib/admin.js +421 -7
- package/lib/agent/providers/claude-code.js +104 -3
- package/lib/agent/providers/codex.js +118 -14
- package/lib/agent.js +9 -1
- package/lib/commands.js +77 -27
- package/lib/constants.js +1 -0
- package/lib/sdk.js +39 -0
- package/lib/sponsor.js +1291 -0
- package/package.json +1 -1
- package/sdk/BUILD_SDK_INDEX.md +122 -7
- package/sdk/LUMINE_ADMIN.md +264 -6
package/README.md
CHANGED
|
@@ -139,6 +139,10 @@ methods. The JSON args are sent as the request body (shapes follow
|
|
|
139
139
|
```bash
|
|
140
140
|
lumine sdk call aiStories.chapters '{"limit": 5}'
|
|
141
141
|
lumine sdk call aiStories.list '{"difficulty": 1}' --repeat 5 --build 1374
|
|
142
|
+
lumine sdk call live.list '{}'
|
|
143
|
+
lumine sdk call live.get '{"sessionId": "..."}'
|
|
144
|
+
lumine sdk call live.listReplays '{"limit": 20}'
|
|
145
|
+
lumine sdk call live.getReplay '{"replayId": "..."}'
|
|
142
146
|
```
|
|
143
147
|
|
|
144
148
|
It targets the build in the current workspace, or pass `--build <id>`. Add
|
|
@@ -146,6 +150,13 @@ It targets the build in the current workspace, or pass `--build <id>`. Add
|
|
|
146
150
|
which can differ from a method's `Twinkle.*` SDK return shape — check
|
|
147
151
|
`TWINKLE_BUILD_SDK.md` for SDK return shapes. Methods that change data require
|
|
148
152
|
`--allow-write`.
|
|
153
|
+
Stopping a hosted stream is available as
|
|
154
|
+
`lumine sdk call live.stop '{"sessionId":"..."}' --allow-write`; the command
|
|
155
|
+
prints canonical server state and refuses to mint `live:write` without the
|
|
156
|
+
explicit write flag.
|
|
157
|
+
Replay listing and status are available without exposing private playback
|
|
158
|
+
grants. A creator or app owner can remove one with
|
|
159
|
+
`lumine sdk call live.deleteReplay '{"replayId":"..."}' --allow-write`.
|
|
149
160
|
|
|
150
161
|
## Assets and AI image generation
|
|
151
162
|
|
|
@@ -218,6 +229,46 @@ claude "Read CLAUDE.md, then make the requested change."
|
|
|
218
229
|
The login command uses a browser approval code and stores a scoped token and the
|
|
219
230
|
selected project at `~/.twinkle/lumine-cli-auth.json`.
|
|
220
231
|
|
|
232
|
+
## Sponsoring Zero or Ciel Build Workshop duty
|
|
233
|
+
|
|
234
|
+
Sponsorship is an approved contribution role, not an open switch and not a
|
|
235
|
+
website-management role. Applications are submitted only through Lumine CLI;
|
|
236
|
+
the Twinkle website provides instructions, but no application form.
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
lumine sponsor agreement
|
|
240
|
+
lumine sponsor apply --providers codex --motivation "Why I want to help" \
|
|
241
|
+
--availability "My usual duty window" --accept-agreement
|
|
242
|
+
lumine sponsor status
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
After Mikey approves an application, configure conservative limits based on
|
|
246
|
+
the subscription you are contributing, then start one foreground duty:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
lumine sponsor capacity --concurrency 1 --helpers 0 \
|
|
250
|
+
--daily-limit 3 --weekly-limit 10
|
|
251
|
+
lumine sponsor duty start zero --provider codex \
|
|
252
|
+
--model gpt-5.6-sol --effort max --service-tier priority
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
While that foreground process has a fresh server lease, Zero or Ciel exposes a
|
|
256
|
+
Build Workshop in chat and users may see the named sponsor and canonical queue.
|
|
257
|
+
With no live duty, the website stays in its ordinary chat state and shows none
|
|
258
|
+
of the Workshop UI. Press Ctrl-C to stop accepting work and drain already
|
|
259
|
+
claimed jobs before duty ends; `pause`, `resume`, and `stop` are also available.
|
|
260
|
+
|
|
261
|
+
Zero or Ciel remains the user-facing teammate. The local coding agent receives
|
|
262
|
+
only the initial relay and active-job Build follow-ups covered by the user’s
|
|
263
|
+
explicit Workshop consent, the assigned contribution branch, and its scoped
|
|
264
|
+
Build Forum—not the raw assistant chat. It
|
|
265
|
+
cannot merge into Main, publish, or use website-management APIs. Lumine records
|
|
266
|
+
the requested and provider-reported model, effort, service tier, runtime/usage
|
|
267
|
+
evidence, coordinator/helper tree, saved artifact, and branch notice. Every
|
|
268
|
+
completed handoff enters the daily integrity flow; probationary, hard-flagged,
|
|
269
|
+
and sampled work requires review. Each unique cleared handoff earns a flat 50
|
|
270
|
+
Karma Points, while retries and helper agents do not multiply the award.
|
|
271
|
+
|
|
221
272
|
## Privileged website administration
|
|
222
273
|
|
|
223
274
|
`lumine admin` reuses Mikey's saved CLI login while keeping the visible public
|
|
@@ -237,6 +288,13 @@ lumine admin economy trace lock --days 3 \
|
|
|
237
288
|
lumine admin rescue wordle-audit --days 30 \
|
|
238
289
|
--reason "Identify recorded Wordle breaks and rescue status" --json
|
|
239
290
|
lumine admin daily-run start --identity auto --comment-mode off --json
|
|
291
|
+
lumine admin sponsor applications list --status pending --json
|
|
292
|
+
lumine admin sponsor applications review 12 --decision approve \
|
|
293
|
+
--note "Approved for probationary duty" --json
|
|
294
|
+
lumine admin sponsor integrity scan --json
|
|
295
|
+
lumine admin sponsor integrity cases --status open --json
|
|
296
|
+
lumine admin sponsor integrity get 34 --json
|
|
297
|
+
lumine admin sponsor integrity review 34 --decision clear --json
|
|
240
298
|
lumine admin todo list --json
|
|
241
299
|
lumine admin todo add --kind experiment --status in_progress \
|
|
242
300
|
--title "Validate Zero/Ciel cost optimization" \
|
|
@@ -344,7 +402,11 @@ with `todo update`; completing a run does not complete its todos. Experiments
|
|
|
344
402
|
must meet their stated acceptance criteria—lower AI cost with weaker user
|
|
345
403
|
responses is not a successful optimization. `daily-run report` summarizes
|
|
346
404
|
confirmed mutations, completed queue coverage, explicitly recorded escalations,
|
|
347
|
-
unfinished todos, and the run brief before the run is
|
|
405
|
+
unfinished todos, sponsor-integrity state, and the run brief before the run is
|
|
406
|
+
completed. A run cannot complete until its bounded sponsor-integrity snapshot
|
|
407
|
+
has been scanned and every selected case is cleared or disqualified. `hold` and
|
|
408
|
+
`flag` deliberately keep the run open for human judgment; scans never suspend,
|
|
409
|
+
revoke, or disqualify a sponsor automatically.
|
|
348
410
|
|
|
349
411
|
Identity inspection, escalation dispositions, AI-bucket maintenance, and
|
|
350
412
|
approved Notable User additions and todos are private operator bookkeeping and
|
package/lib/admin.js
CHANGED
|
@@ -96,9 +96,7 @@ function readBuildReviewContextFile(filePath) {
|
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
98
|
const understanding =
|
|
99
|
-
typeof parsed.understanding === "string"
|
|
100
|
-
? parsed.understanding.trim()
|
|
101
|
-
: "";
|
|
99
|
+
typeof parsed.understanding === "string" ? parsed.understanding.trim() : "";
|
|
102
100
|
if (!understanding) {
|
|
103
101
|
throw cliValidationError(
|
|
104
102
|
"The Build review context understanding must be a non-empty string.",
|
|
@@ -816,6 +814,108 @@ export function parseAdminOperation(options) {
|
|
|
816
814
|
);
|
|
817
815
|
}
|
|
818
816
|
|
|
817
|
+
if (namespace === "sponsor" || namespace === "sponsors") {
|
|
818
|
+
if (action === "applications") {
|
|
819
|
+
if (!target || target === "list") {
|
|
820
|
+
return readOperation(
|
|
821
|
+
"sponsor.applications.list",
|
|
822
|
+
withQuery("/cli/admin/sponsors/applications", {
|
|
823
|
+
status: options.adminStatus || "pending",
|
|
824
|
+
limit: options.limit,
|
|
825
|
+
}),
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
if (target === "review") {
|
|
829
|
+
const applicationId = parseRequiredInteger(
|
|
830
|
+
extra,
|
|
831
|
+
"Sponsor application ID",
|
|
832
|
+
1,
|
|
833
|
+
);
|
|
834
|
+
const decision = parseChoice(
|
|
835
|
+
options.adminDecision || options.adminStatus,
|
|
836
|
+
"--decision",
|
|
837
|
+
["approve", "reject"],
|
|
838
|
+
);
|
|
839
|
+
return writeOperation(
|
|
840
|
+
"sponsor.application.review",
|
|
841
|
+
"POST",
|
|
842
|
+
`/cli/admin/sponsors/applications/${applicationId}/review`,
|
|
843
|
+
{ decision, note: options.note || undefined },
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (action === "status" && target === "set") {
|
|
848
|
+
const sponsorUserId = parseRequiredInteger(extra, "Sponsor user ID", 1);
|
|
849
|
+
const status = parseChoice(options.adminStatus, "--status", [
|
|
850
|
+
"probationary",
|
|
851
|
+
"trusted",
|
|
852
|
+
"suspended",
|
|
853
|
+
"revoked",
|
|
854
|
+
]);
|
|
855
|
+
return writeOperation(
|
|
856
|
+
"sponsor.status.set",
|
|
857
|
+
"PUT",
|
|
858
|
+
`/cli/admin/sponsors/${sponsorUserId}/status`,
|
|
859
|
+
{ status, note: options.note || undefined },
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
if (action === "integrity") {
|
|
863
|
+
if (target === "status") {
|
|
864
|
+
return readOperation(
|
|
865
|
+
"sponsor.integrity.status",
|
|
866
|
+
"/cli/admin/daily-runs/sponsor-integrity/status",
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
if (target === "scan") {
|
|
870
|
+
return writeOperation(
|
|
871
|
+
"sponsor.integrity.scan",
|
|
872
|
+
"POST",
|
|
873
|
+
"/cli/admin/daily-runs/sponsor-integrity/scan",
|
|
874
|
+
{},
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
if (target === "cases") {
|
|
878
|
+
return readOperation(
|
|
879
|
+
"sponsor.integrity.cases",
|
|
880
|
+
withQuery("/cli/admin/daily-runs/sponsor-integrity/cases", {
|
|
881
|
+
status: options.adminStatus || "open",
|
|
882
|
+
limit: options.limit,
|
|
883
|
+
}),
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
if (target === "get") {
|
|
887
|
+
const caseId = parseRequiredInteger(extra, "Integrity case ID", 1);
|
|
888
|
+
return readOperation(
|
|
889
|
+
"sponsor.integrity.get",
|
|
890
|
+
`/cli/admin/daily-runs/sponsor-integrity/cases/${caseId}`,
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
if (target === "review") {
|
|
894
|
+
const caseId = parseRequiredInteger(extra, "Integrity case ID", 1);
|
|
895
|
+
const decision = parseChoice(options.adminDecision, "--decision", [
|
|
896
|
+
"clear",
|
|
897
|
+
"hold",
|
|
898
|
+
"flag",
|
|
899
|
+
"disqualify",
|
|
900
|
+
]);
|
|
901
|
+
if (decision !== "clear" && !String(options.note || "").trim()) {
|
|
902
|
+
throw cliValidationError(
|
|
903
|
+
"Sponsor-integrity hold, flag, and disqualify decisions require --note <evidence>.",
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
return writeOperation(
|
|
907
|
+
"sponsor.integrity.review",
|
|
908
|
+
"POST",
|
|
909
|
+
`/cli/admin/daily-runs/sponsor-integrity/cases/${caseId}/review`,
|
|
910
|
+
{ decision, note: options.note || undefined },
|
|
911
|
+
);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
throw cliValidationError(
|
|
915
|
+
"Usage: lumine admin sponsor applications list|review | sponsor status set | sponsor integrity status|scan|cases|get|review.",
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
|
|
819
919
|
if (namespace === "daily-run") {
|
|
820
920
|
if (action === "start") {
|
|
821
921
|
return writeOperation(
|
|
@@ -1235,6 +1335,35 @@ export function parseAdminOperation(options) {
|
|
|
1235
1335
|
);
|
|
1236
1336
|
}
|
|
1237
1337
|
|
|
1338
|
+
if (namespace === "ai-costs") {
|
|
1339
|
+
if (action === "monthly" && !target && !extra) {
|
|
1340
|
+
if (options.adminDays) {
|
|
1341
|
+
throw cliValidationError(
|
|
1342
|
+
"ai-costs monthly uses UTC calendar months and does not accept --days.",
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
return readOperation("ai-costs.monthly", "/cli/admin/ai-costs/monthly");
|
|
1346
|
+
}
|
|
1347
|
+
throw cliValidationError("Usage: lumine admin ai-costs monthly [--json].");
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
if (namespace === "media-costs") {
|
|
1351
|
+
if (action === "monthly" && !target && !extra) {
|
|
1352
|
+
if (options.adminDays) {
|
|
1353
|
+
throw cliValidationError(
|
|
1354
|
+
"media-costs monthly uses the canonical UTC ledger and does not accept --days.",
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
return readOperation(
|
|
1358
|
+
"media-costs.monthly",
|
|
1359
|
+
"/cli/admin/media-costs/monthly",
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
throw cliValidationError(
|
|
1363
|
+
"Usage: lumine admin media-costs monthly [--json].",
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1238
1367
|
if (namespace === "brief" && !action) {
|
|
1239
1368
|
if (options.adminDays) {
|
|
1240
1369
|
const days = Number(options.adminDays);
|
|
@@ -1419,9 +1548,7 @@ export function parseAdminOperation(options) {
|
|
|
1419
1548
|
...(confirmedBuildReviewMethod
|
|
1420
1549
|
? { buildReviewMethod: confirmedBuildReviewMethod }
|
|
1421
1550
|
: {}),
|
|
1422
|
-
...(buildReviewUnderstanding
|
|
1423
|
-
? { buildReviewUnderstanding }
|
|
1424
|
-
: {}),
|
|
1551
|
+
...(buildReviewUnderstanding ? { buildReviewUnderstanding } : {}),
|
|
1425
1552
|
},
|
|
1426
1553
|
);
|
|
1427
1554
|
}
|
|
@@ -1465,7 +1592,7 @@ export function parseAdminOperation(options) {
|
|
|
1465
1592
|
}
|
|
1466
1593
|
|
|
1467
1594
|
throw cliValidationError(
|
|
1468
|
-
"Usage: lumine admin identity|economy|rescue|daily-run|escalation|todo|recommendations|builds|post|subjects|subject|featured|comment|announcement|chat|news|audit|brief|bot-output|notable ...",
|
|
1595
|
+
"Usage: lumine admin identity|economy|rescue|sponsor|daily-run|escalation|todo|recommendations|builds|post|subjects|subject|featured|comment|announcement|chat|news|audit|brief|ai-costs|media-costs|bot-output|notable ...",
|
|
1469
1596
|
);
|
|
1470
1597
|
}
|
|
1471
1598
|
|
|
@@ -2024,6 +2151,16 @@ function parseRequiredInteger(
|
|
|
2024
2151
|
return number;
|
|
2025
2152
|
}
|
|
2026
2153
|
|
|
2154
|
+
function parseChoice(value, label, choices) {
|
|
2155
|
+
const normalized = String(value || "")
|
|
2156
|
+
.trim()
|
|
2157
|
+
.toLowerCase();
|
|
2158
|
+
if (!choices.includes(normalized)) {
|
|
2159
|
+
throw cliValidationError(`${label} must be ${choices.join(", ")}.`);
|
|
2160
|
+
}
|
|
2161
|
+
return normalized;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2027
2164
|
function defaultDailyRunKey() {
|
|
2028
2165
|
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
2029
2166
|
timeZone: "Asia/Bangkok",
|
|
@@ -2047,8 +2184,272 @@ function adminValueFingerprint(value) {
|
|
|
2047
2184
|
return createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
2048
2185
|
}
|
|
2049
2186
|
|
|
2187
|
+
function formatAdminUsd(value) {
|
|
2188
|
+
const amount = Number(value);
|
|
2189
|
+
if (!Number.isFinite(amount)) return "unavailable";
|
|
2190
|
+
return `$${amount.toLocaleString("en-US", {
|
|
2191
|
+
minimumFractionDigits: 2,
|
|
2192
|
+
maximumFractionDigits: 2,
|
|
2193
|
+
})}`;
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
function formatAdminMonthlyCostComparison(projection, previousMonthKey) {
|
|
2197
|
+
const rawPercent = projection?.comparisonToPreviousMonth?.percentChange;
|
|
2198
|
+
const percent = rawPercent === null ? NaN : Number(rawPercent);
|
|
2199
|
+
if (!Number.isFinite(percent)) {
|
|
2200
|
+
return `comparison with ${previousMonthKey} unavailable`;
|
|
2201
|
+
}
|
|
2202
|
+
if (percent === 0) return `even with ${previousMonthKey}`;
|
|
2203
|
+
return `${Math.abs(percent).toFixed(2)}% ${percent < 0 ? "below" : "above"} ${previousMonthKey}`;
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
function printAdminMonthlyAiCosts(monthlyAiCosts) {
|
|
2207
|
+
const previous = monthlyAiCosts.previousMonth;
|
|
2208
|
+
const current = monthlyAiCosts.currentMonth;
|
|
2209
|
+
const generatedAt = new Date(
|
|
2210
|
+
Number(monthlyAiCosts.generatedAt) * 1000,
|
|
2211
|
+
).toISOString();
|
|
2212
|
+
console.log(`Application AI-cost ledger (UTC; generated ${generatedAt}).`);
|
|
2213
|
+
console.log(
|
|
2214
|
+
`${previous.monthKey} closed month: ${formatAdminUsd(previous.estimatedCostUsd)} estimated cost.`,
|
|
2215
|
+
);
|
|
2216
|
+
if (current.completed.dayCount > 0) {
|
|
2217
|
+
console.log(
|
|
2218
|
+
`${current.monthKey} completed-day MTD through ${current.completed.throughDayKey}: ${formatAdminUsd(current.completed.estimatedCostUsd)} across ${current.completed.dayCount} completed UTC day(s).`,
|
|
2219
|
+
);
|
|
2220
|
+
} else {
|
|
2221
|
+
console.log(
|
|
2222
|
+
`${current.monthKey} completed-day MTD: ${formatAdminUsd(current.completed.estimatedCostUsd)}; no UTC day has completed yet.`,
|
|
2223
|
+
);
|
|
2224
|
+
}
|
|
2225
|
+
console.log(
|
|
2226
|
+
`${current.inProgressDay.dayKey} in progress: ${formatAdminUsd(current.inProgressDay.estimatedCostUsd)} so far (excluded from completed-day MTD and both projections).`,
|
|
2227
|
+
);
|
|
2228
|
+
|
|
2229
|
+
const allPace = current.projections.allCompletedDaysPace;
|
|
2230
|
+
if (allPace) {
|
|
2231
|
+
console.log(
|
|
2232
|
+
`All-completed-days pace full-month projection: ${formatAdminUsd(allPace.estimatedMonthTotalUsd)} (${formatAdminUsd(allPace.dailyAverageUsd)}/day across ${allPace.basisDayCount} completed day(s); ${formatAdminMonthlyCostComparison(allPace, previous.monthKey)}).`,
|
|
2233
|
+
);
|
|
2234
|
+
} else {
|
|
2235
|
+
console.log(
|
|
2236
|
+
"All-completed-days pace full-month projection: unavailable until one UTC day has completed.",
|
|
2237
|
+
);
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
const recentPace = current.projections.recentSevenCompletedDaysPace;
|
|
2241
|
+
if (recentPace) {
|
|
2242
|
+
console.log(
|
|
2243
|
+
`Recent-seven-completed-day pace full-month projection: ${formatAdminUsd(recentPace.estimatedMonthTotalUsd)} (${formatAdminUsd(recentPace.dailyAverageUsd)}/day from ${recentPace.basisStartDayKey} through ${recentPace.basisEndDayKey}; ${formatAdminMonthlyCostComparison(recentPace, previous.monthKey)}).`,
|
|
2244
|
+
);
|
|
2245
|
+
} else {
|
|
2246
|
+
console.log(
|
|
2247
|
+
"Recent-seven-completed-day pace full-month projection: unavailable until seven UTC days have completed.",
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
function formatAdminMediaUsd(value) {
|
|
2253
|
+
const amount = Number(value);
|
|
2254
|
+
if (!Number.isFinite(amount)) return "unavailable";
|
|
2255
|
+
return `$${amount.toLocaleString("en-US", {
|
|
2256
|
+
minimumFractionDigits: 2,
|
|
2257
|
+
maximumFractionDigits: 6,
|
|
2258
|
+
})}`;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
function formatAdminMediaBytes(value) {
|
|
2262
|
+
const bytes = Number(value);
|
|
2263
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "unavailable";
|
|
2264
|
+
if (bytes < 1024) return `${Math.floor(bytes)} B`;
|
|
2265
|
+
const units = ["KB", "MB", "GB", "TB"];
|
|
2266
|
+
let amount = bytes / 1024;
|
|
2267
|
+
let unit = units[0];
|
|
2268
|
+
for (let index = 1; index < units.length && amount >= 1024; index += 1) {
|
|
2269
|
+
amount /= 1024;
|
|
2270
|
+
unit = units[index];
|
|
2271
|
+
}
|
|
2272
|
+
return `${amount.toFixed(amount >= 100 ? 0 : amount >= 10 ? 1 : 2)} ${unit}`;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
function printAdminMonthlyMediaCosts(monthlyMediaCosts) {
|
|
2276
|
+
const generatedAt = new Date(
|
|
2277
|
+
Number(monthlyMediaCosts.generatedAt) * 1000,
|
|
2278
|
+
).toISOString();
|
|
2279
|
+
const current = monthlyMediaCosts.currentMonth;
|
|
2280
|
+
const today = monthlyMediaCosts.currentUtcDay;
|
|
2281
|
+
const operations = monthlyMediaCosts.operations;
|
|
2282
|
+
const streamAttempts = today.streamAttempts || {
|
|
2283
|
+
attemptedCount: 0,
|
|
2284
|
+
reachedLiveCount: 0,
|
|
2285
|
+
endedCount: 0,
|
|
2286
|
+
failedCount: 0,
|
|
2287
|
+
cancelledCount: 0,
|
|
2288
|
+
inProgressCount: 0,
|
|
2289
|
+
failureCodeCounts: [],
|
|
2290
|
+
};
|
|
2291
|
+
console.log(
|
|
2292
|
+
`Lumine media-cost monitor (UTC; ${monthlyMediaCosts.status}; generated ${generatedAt}).`,
|
|
2293
|
+
);
|
|
2294
|
+
console.log(
|
|
2295
|
+
`${current.monthKey}: ${formatAdminMediaUsd(current.estimatedSpentUsd)} settled estimate + ${formatAdminMediaUsd(current.activeReservedUsd)} active reservations + ${formatAdminMediaUsd(current.carryoverUsd)} carryover = ${formatAdminMediaUsd(current.guardedTotalUsd)} guarded of ${formatAdminMediaUsd(current.limitUsd)} (${Number(current.percentUsed).toFixed(2)}% used; ${formatAdminMediaUsd(current.remainingUsd)} remaining).`,
|
|
2296
|
+
);
|
|
2297
|
+
console.log(
|
|
2298
|
+
`${today.dayKey} so far: ${today.reservationsCreated} action(s) reserved, ${today.commitmentsSettled} committed, ${today.cancellationsSettled} cancelled, ${formatAdminMediaUsd(today.estimatedCostSettledUsd)} settled estimate.`,
|
|
2299
|
+
);
|
|
2300
|
+
console.log(
|
|
2301
|
+
`Stream attempts created ${today.dayKey} UTC: ${streamAttempts.attemptedCount} attempted / ${streamAttempts.reachedLiveCount} reached live / ${streamAttempts.endedCount} ended after live / ${streamAttempts.failedCount} failed / ${streamAttempts.cancelledCount} cancelled before live / ${streamAttempts.inProgressCount} still in progress.`,
|
|
2302
|
+
);
|
|
2303
|
+
const streamFailureCodeCounts = Array.isArray(
|
|
2304
|
+
streamAttempts.failureCodeCounts,
|
|
2305
|
+
)
|
|
2306
|
+
? streamAttempts.failureCodeCounts
|
|
2307
|
+
: [];
|
|
2308
|
+
console.log(
|
|
2309
|
+
streamFailureCodeCounts.length > 0
|
|
2310
|
+
? `Stream failure codes: ${streamFailureCodeCounts
|
|
2311
|
+
.map((entry) => `${entry.code}=${entry.count}`)
|
|
2312
|
+
.join(", ")}.`
|
|
2313
|
+
: "Stream failure codes: none.",
|
|
2314
|
+
);
|
|
2315
|
+
const stillActiveOrCleanupPendingCount =
|
|
2316
|
+
operations.live.stillActiveOrCleanupPendingCount ??
|
|
2317
|
+
Number(operations.live.provisioningCount || 0) +
|
|
2318
|
+
Number(operations.live.readyCount || 0) +
|
|
2319
|
+
Number(operations.live.liveCount || 0) +
|
|
2320
|
+
Number(operations.live.endingCount || 0) +
|
|
2321
|
+
Number(operations.live.cleanupFailedCount || 0);
|
|
2322
|
+
const replayOperations = operations.replays || {
|
|
2323
|
+
pendingCount: 0,
|
|
2324
|
+
processingCount: 0,
|
|
2325
|
+
readyCount: 0,
|
|
2326
|
+
failedCount: 0,
|
|
2327
|
+
deletePendingCount: 0,
|
|
2328
|
+
deleteFailedCount: 0,
|
|
2329
|
+
expiredReadyCount: 0,
|
|
2330
|
+
finalizationOverdueCount: 0,
|
|
2331
|
+
deletionOverdueCount: 0,
|
|
2332
|
+
storedBytes: 0,
|
|
2333
|
+
storedObjectCount: 0,
|
|
2334
|
+
};
|
|
2335
|
+
const replayViewers = operations.replayViewers || {
|
|
2336
|
+
activeGrantCount: 0,
|
|
2337
|
+
expiredActiveGrantCount: 0,
|
|
2338
|
+
};
|
|
2339
|
+
const kindRows = [
|
|
2340
|
+
["Short clips", current.byKind.clip],
|
|
2341
|
+
["Live inputs", current.byKind.liveInput],
|
|
2342
|
+
["Live viewers", current.byKind.liveViewer],
|
|
2343
|
+
];
|
|
2344
|
+
if (current.byKind.replayViewer) {
|
|
2345
|
+
kindRows.push(["Replay viewers", current.byKind.replayViewer]);
|
|
2346
|
+
}
|
|
2347
|
+
for (const [label, cost] of kindRows) {
|
|
2348
|
+
console.log(
|
|
2349
|
+
`${label}: ${cost.actionCount} action(s), ${cost.committedCount} committed for ${formatAdminMediaUsd(cost.estimatedSpentUsd)}, ${cost.activeReservedCount} active reservation(s) holding ${formatAdminMediaUsd(cost.activeReservedUsd)}, ${cost.cancelledCount} cancelled.`,
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
console.log(
|
|
2353
|
+
`Ledger reconciliation: ${current.reconciliation.consistent ? "consistent" : "MISMATCH"}; spent delta ${formatAdminMediaUsd(current.reconciliation.spentDeltaUsd)}, reserved delta ${formatAdminMediaUsd(current.reconciliation.reservedDeltaUsd)}.`,
|
|
2354
|
+
);
|
|
2355
|
+
console.log(
|
|
2356
|
+
`Operations: clips ${operations.clips.completingCount} completing / ${operations.clips.processingCount} processing / ${operations.clips.staleCount} stale; live ${operations.live.liveCount} broadcasting / ${stillActiveOrCleanupPendingCount} active-or-cleanup-pending / ${operations.live.costBearingChannelCount} cost-bearing channel(s) / ${operations.live.possibleOrphanedCount ?? operations.live.cleanupOverdueCount} possible orphan(s); viewers ${operations.viewers.activeGrantCount} active / ${operations.viewers.expiredActiveGrantCount} expired-active.`,
|
|
2357
|
+
);
|
|
2358
|
+
console.log(
|
|
2359
|
+
`Replays: ${replayOperations.pendingCount} pending / ${replayOperations.processingCount} processing / ${replayOperations.readyCount} ready / ${replayOperations.failedCount} failed / ${replayOperations.deletePendingCount} deleting / ${replayOperations.deleteFailedCount} delete-failed; ${replayOperations.finalizationOverdueCount} finalization-overdue / ${replayOperations.deletionOverdueCount} deletion-overdue / ${replayOperations.expiredReadyCount} expired-ready; ${formatAdminMediaBytes(replayOperations.storedBytes)} across ${replayOperations.storedObjectCount} canonical object(s); viewers ${replayViewers.activeGrantCount} active / ${replayViewers.expiredActiveGrantCount} expired-active.`,
|
|
2360
|
+
);
|
|
2361
|
+
console.log(
|
|
2362
|
+
`Shared runtime storage context: ${operations.runtimeStorage.readyImages.assetCount} ready image(s), ${formatAdminMediaBytes(operations.runtimeStorage.readyImages.totalBytes)}; ${operations.runtimeStorage.readyClips.assetCount} ready clip(s), ${formatAdminMediaBytes(operations.runtimeStorage.readyClips.totalBytes)}. Images include all Build runtime image uploads, not only camera captures.`,
|
|
2363
|
+
);
|
|
2364
|
+
if (monthlyMediaCosts.alerts.length === 0) {
|
|
2365
|
+
console.log("Media-cost alerts: none.");
|
|
2366
|
+
} else {
|
|
2367
|
+
for (const alert of monthlyMediaCosts.alerts) {
|
|
2368
|
+
console.log(
|
|
2369
|
+
`Media-cost alert [${String(alert.severity).toUpperCase()}] ${alert.code}: ${alert.message}`,
|
|
2370
|
+
);
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
console.log(
|
|
2374
|
+
"These are conservative provider-cost ledger estimates, not an AWS invoice; reconcile IVS, MediaConvert, replay S3, and shared runtime S3 Cost Explorer data separately after billing lag.",
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2050
2378
|
function printAdminResult({ operation, result }) {
|
|
2051
2379
|
const data = result?.data || {};
|
|
2380
|
+
if (Array.isArray(data.applications)) {
|
|
2381
|
+
console.log(`${data.applications.length} sponsor application(s):`);
|
|
2382
|
+
for (const application of data.applications) {
|
|
2383
|
+
console.log(
|
|
2384
|
+
` #${application.id} ${String(application.status).toUpperCase()} · ${application.username || `user ${application.userId}`} · agreement ${application.agreementVersion || "unknown"}`,
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
return;
|
|
2388
|
+
}
|
|
2389
|
+
if (data.application) {
|
|
2390
|
+
console.log(
|
|
2391
|
+
`Sponsor application #${data.application.id}: ${String(data.application.status).toUpperCase()} · ${data.application.username || `user ${data.application.userId}`}`,
|
|
2392
|
+
);
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
if (data.sponsor) {
|
|
2396
|
+
console.log(
|
|
2397
|
+
`Sponsor ${data.sponsor.username || `user ${data.sponsor.userId}`}: ${String(data.sponsor.status).toUpperCase()}.`,
|
|
2398
|
+
);
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
if (data.scan) {
|
|
2402
|
+
const scan = data.scan;
|
|
2403
|
+
console.log(
|
|
2404
|
+
`Sponsor-integrity scan #${scan.id || "not started"}: ${scan.status || "not started"} · ${scan.scannedCount || 0} scanned · ${scan.selectedReviewCount || 0} selected · ${data.openCaseCount || 0} open.`,
|
|
2405
|
+
);
|
|
2406
|
+
if (Array.isArray(data.casesCreated) && data.casesCreated.length > 0) {
|
|
2407
|
+
console.log(
|
|
2408
|
+
`Created ${data.casesCreated.length} review case(s) on this page.`,
|
|
2409
|
+
);
|
|
2410
|
+
}
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
if (Array.isArray(data.cases)) {
|
|
2414
|
+
console.log(`${data.cases.length} sponsor-integrity case(s):`);
|
|
2415
|
+
for (const item of data.cases) {
|
|
2416
|
+
const flags =
|
|
2417
|
+
Array.isArray(item.hardFlags) && item.hardFlags.length
|
|
2418
|
+
? ` · flags=${item.hardFlags.join(",")}`
|
|
2419
|
+
: "";
|
|
2420
|
+
console.log(
|
|
2421
|
+
` #${item.id} ${String(item.status).toUpperCase()} · job #${item.jobId} · ${item.sponsorUsername || `sponsor ${item.sponsorUserId}`}${flags}`,
|
|
2422
|
+
);
|
|
2423
|
+
}
|
|
2424
|
+
return;
|
|
2425
|
+
}
|
|
2426
|
+
if (data.case) {
|
|
2427
|
+
const item = data.case;
|
|
2428
|
+
console.log(
|
|
2429
|
+
`Sponsor-integrity case #${item.id}: ${String(item.status).toUpperCase()} · job #${item.job?.id} · ${item.sponsorUsername || `sponsor ${item.sponsorUserId}`}.`,
|
|
2430
|
+
);
|
|
2431
|
+
const relays = Array.isArray(item.relays) && item.relays.length > 0
|
|
2432
|
+
? item.relays
|
|
2433
|
+
: item.relay
|
|
2434
|
+
? [item.relay]
|
|
2435
|
+
: [];
|
|
2436
|
+
console.log(
|
|
2437
|
+
`Relays: ${relays.map((relay) => `${relay.kind || "initial_request"}: ${relay.summary || "(missing)"}`).join(" | ") || "(missing)"}`,
|
|
2438
|
+
);
|
|
2439
|
+
console.log(
|
|
2440
|
+
`Provenance: ${(item.agents || []).map((agent) => `${agent.role}:${agent.provider}:${agent.resolvedModel || "unresolved"}:${agent.resolvedEffort || "unresolved"}`).join(" · ") || "missing"}`,
|
|
2441
|
+
);
|
|
2442
|
+
console.log(
|
|
2443
|
+
`Artifact files: ${(item.artifactFiles || []).map((file) => file.path).join(", ") || "none"}`,
|
|
2444
|
+
);
|
|
2445
|
+
return;
|
|
2446
|
+
}
|
|
2447
|
+
if (data.caseId) {
|
|
2448
|
+
console.log(
|
|
2449
|
+
`Sponsor-integrity case #${data.caseId}: ${data.decision}${data.scanCompleted ? "; scan complete" : ""}.`,
|
|
2450
|
+
);
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2052
2453
|
if (data.review) {
|
|
2053
2454
|
console.log(
|
|
2054
2455
|
`Confirmed Build #${data.review.buildId} runtime at published artifact #${data.review.publishedArtifactVersionId}.`,
|
|
@@ -2057,6 +2458,14 @@ function printAdminResult({ operation, result }) {
|
|
|
2057
2458
|
console.log(`Review receipt: ${data.receiptPath}`);
|
|
2058
2459
|
return;
|
|
2059
2460
|
}
|
|
2461
|
+
if (data.monthlyAiCosts) {
|
|
2462
|
+
printAdminMonthlyAiCosts(data.monthlyAiCosts);
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
if (data.monthlyMediaCosts) {
|
|
2466
|
+
printAdminMonthlyMediaCosts(data.monthlyMediaCosts);
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2060
2469
|
if (data.validation) {
|
|
2061
2470
|
console.log(
|
|
2062
2471
|
`Editorial valid for edition #${data.validation.editionId}: ${data.validation.citedEventCount} cited and ${data.validation.coveredEventCount} covered event(s).`,
|
|
@@ -2089,6 +2498,11 @@ function printAdminResult({ operation, result }) {
|
|
|
2089
2498
|
);
|
|
2090
2499
|
}
|
|
2091
2500
|
printTodoItems(report.carryoverTodos?.items || [], "Unfinished work");
|
|
2501
|
+
if (report.sponsorIntegrity) {
|
|
2502
|
+
console.log(
|
|
2503
|
+
`Sponsor integrity: ${report.sponsorIntegrity.scan?.status || "not started"}; ${report.sponsorIntegrity.cases?.open || 0} open case(s); ${report.sponsorIntegrity.pendingApplications || 0} pending application(s).`,
|
|
2504
|
+
);
|
|
2505
|
+
}
|
|
2092
2506
|
const surfaces = report.brief?.engagementPulse?.surfaces;
|
|
2093
2507
|
if (surfaces && typeof surfaces === "object") {
|
|
2094
2508
|
const deltas = Object.entries(surfaces)
|