@stage5/lumine 0.2.39 → 0.2.41
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 +78 -13
- package/lib/admin-news.js +236 -0
- package/lib/admin-workflows.js +419 -0
- package/lib/admin.js +495 -44
- package/lib/agent/mcp-server.js +138 -0
- package/lib/agent/providers/claude-code.js +214 -0
- package/lib/agent/providers/codex.js +522 -0
- package/lib/agent/providers/environment.js +40 -0
- package/lib/agent/providers/index.js +38 -0
- package/lib/agent/tool-session.js +301 -0
- package/lib/agent/trace.js +138 -0
- package/lib/agent.js +453 -0
- package/lib/api.js +81 -1
- package/lib/build-review.js +493 -0
- package/lib/commands.js +145 -11
- package/lib/constants.js +15 -0
- package/lib/forum.js +375 -0
- package/package.json +1 -1
- package/sdk/BUILD_SDK_INDEX.md +26 -3
- package/sdk/LUMINE_ADMIN.md +95 -20
package/lib/admin.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { assertAuthScope, resolveAuth } from "./auth.js";
|
|
4
4
|
import { requestJson } from "./http.js";
|
|
5
|
+
import {
|
|
6
|
+
extractNewsClaim,
|
|
7
|
+
readAdminJsonFile,
|
|
8
|
+
validateNewsEditorial,
|
|
9
|
+
writeNewsClaimArtifacts,
|
|
10
|
+
} from "./admin-news.js";
|
|
11
|
+
import {
|
|
12
|
+
runAutomaticPagination,
|
|
13
|
+
runBatchSkips,
|
|
14
|
+
} from "./admin-workflows.js";
|
|
15
|
+
import {
|
|
16
|
+
parseBuildReviewReceipt,
|
|
17
|
+
runManagedBuildReview,
|
|
18
|
+
} from "./build-review.js";
|
|
5
19
|
|
|
6
20
|
const MAX_EDITORIAL_FILE_BYTES = 256 * 1024;
|
|
7
21
|
const MAX_COMPOSED_TEXT_FILE_BYTES = 64 * 1024;
|
|
@@ -64,6 +78,19 @@ function readEditorialFile(filePath) {
|
|
|
64
78
|
|
|
65
79
|
export async function adminCommand(options) {
|
|
66
80
|
const operation = parseAdminOperation(options);
|
|
81
|
+
if (operation.name === "news.validate") {
|
|
82
|
+
const validation = validateNewsEditorial({
|
|
83
|
+
claim: operation.claim,
|
|
84
|
+
editorial: operation.editorial,
|
|
85
|
+
});
|
|
86
|
+
const result = {
|
|
87
|
+
ok: true,
|
|
88
|
+
status: "success",
|
|
89
|
+
changed: false,
|
|
90
|
+
data: { validation },
|
|
91
|
+
};
|
|
92
|
+
return finishAdminOutput({ options, operation, result });
|
|
93
|
+
}
|
|
67
94
|
const viewFilter = resolveOperatorViewFilter({
|
|
68
95
|
operation,
|
|
69
96
|
unviewed: options.adminUnviewed,
|
|
@@ -112,34 +139,76 @@ export async function adminCommand(options) {
|
|
|
112
139
|
options.idempotencyKey || (operation.mutates ? `cli:${randomUUID()}` : "");
|
|
113
140
|
let result;
|
|
114
141
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (operation.name === "builds.candidates") {
|
|
127
|
-
result = normalizeAdminBuildCandidatesResult({
|
|
128
|
-
result,
|
|
129
|
-
siteUrl: options.siteUrl,
|
|
142
|
+
const fetchOperation = async (requestPath = operation.path) =>
|
|
143
|
+
requestJson({
|
|
144
|
+
method: operation.method,
|
|
145
|
+
url: `${options.apiUrl}${requestPath}`,
|
|
146
|
+
authToken: auth.token,
|
|
147
|
+
body: operation.body,
|
|
148
|
+
headers: {
|
|
149
|
+
...(runId ? { "x-lumine-admin-run-id": String(runId) } : {}),
|
|
150
|
+
...(requestId ? { "x-lumine-idempotency-key": requestId } : {}),
|
|
151
|
+
},
|
|
152
|
+
timeoutMs: options.timeoutMs,
|
|
130
153
|
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
result,
|
|
135
|
-
|
|
154
|
+
const transformResult = (rawResult) =>
|
|
155
|
+
transformAdminResult({
|
|
156
|
+
operation,
|
|
157
|
+
result: rawResult,
|
|
158
|
+
options,
|
|
159
|
+
recommendationContentTypes,
|
|
160
|
+
viewFilter,
|
|
136
161
|
});
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
162
|
+
if (operation.name === "build.review") {
|
|
163
|
+
result = await runManagedBuildReview({
|
|
164
|
+
options,
|
|
165
|
+
authToken: auth.token,
|
|
166
|
+
buildId: operation.buildId,
|
|
167
|
+
});
|
|
168
|
+
} else if (operation.name === "post.skip-batch") {
|
|
169
|
+
result = await runBatchSkips({
|
|
170
|
+
options,
|
|
171
|
+
authToken: auth.token,
|
|
172
|
+
runId,
|
|
173
|
+
parseTarget: parseRecommendationTarget,
|
|
174
|
+
});
|
|
175
|
+
} else if (options.adminAll) {
|
|
176
|
+
if (options.adminCursor) {
|
|
177
|
+
throw cliValidationError(
|
|
178
|
+
"Use --resume with the scan checkpoint instead of combining --all with --cursor.",
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
result = await runAutomaticPagination({
|
|
182
|
+
options,
|
|
183
|
+
operation,
|
|
184
|
+
runId,
|
|
185
|
+
fetchPage: fetchOperation,
|
|
186
|
+
transformPage: transformResult,
|
|
187
|
+
recordCoverage: async (coverage) =>
|
|
188
|
+
requestJson({
|
|
189
|
+
method: "POST",
|
|
190
|
+
url: `${options.apiUrl}/cli/admin/daily-runs/coverage`,
|
|
191
|
+
authToken: auth.token,
|
|
192
|
+
body: coverage,
|
|
193
|
+
headers: {
|
|
194
|
+
"x-lumine-admin-run-id": String(runId),
|
|
195
|
+
"x-lumine-idempotency-key": `cli:queue-coverage:${runId}:${adminValueFingerprint(coverage).slice(0, 32)}`,
|
|
196
|
+
},
|
|
197
|
+
timeoutMs: options.timeoutMs,
|
|
198
|
+
}),
|
|
199
|
+
});
|
|
200
|
+
} else {
|
|
201
|
+
if (options.adminResume) {
|
|
202
|
+
throw cliValidationError("--resume requires --all or post skip-batch.");
|
|
203
|
+
}
|
|
204
|
+
result = transformResult(await fetchOperation());
|
|
140
205
|
}
|
|
141
206
|
} catch (error) {
|
|
142
|
-
if (
|
|
207
|
+
if (
|
|
208
|
+
operation.mutates &&
|
|
209
|
+
requestId &&
|
|
210
|
+
operation.name !== "post.skip-batch"
|
|
211
|
+
) {
|
|
143
212
|
const retryInstruction = `Retry with --idempotency-key ${requestId}.`;
|
|
144
213
|
error.data = error.data || {
|
|
145
214
|
ok: false,
|
|
@@ -175,6 +244,81 @@ export async function adminCommand(options) {
|
|
|
175
244
|
expectedContent: operation.body.content,
|
|
176
245
|
});
|
|
177
246
|
}
|
|
247
|
+
if (operation.name === "news.claim") {
|
|
248
|
+
const artifacts = writeNewsClaimArtifacts({
|
|
249
|
+
result,
|
|
250
|
+
outputPath: options.adminOutput,
|
|
251
|
+
scaffoldPath: options.adminScaffoldFile,
|
|
252
|
+
});
|
|
253
|
+
result = {
|
|
254
|
+
...result,
|
|
255
|
+
data: { ...(result.data || {}), artifacts },
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return finishAdminOutput({ options, operation, result });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function transformAdminResult({
|
|
262
|
+
operation,
|
|
263
|
+
result,
|
|
264
|
+
options,
|
|
265
|
+
recommendationContentTypes,
|
|
266
|
+
viewFilter,
|
|
267
|
+
}) {
|
|
268
|
+
let transformed = result;
|
|
269
|
+
if (operation.name === "recommendations.list") {
|
|
270
|
+
assertRecommendationWindowResult({ operation, result: transformed });
|
|
271
|
+
}
|
|
272
|
+
if (operation.name === "builds.candidates") {
|
|
273
|
+
transformed = normalizeAdminBuildCandidatesResult({
|
|
274
|
+
result: transformed,
|
|
275
|
+
siteUrl: options.siteUrl,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
if (recommendationContentTypes) {
|
|
279
|
+
transformed = filterRecommendationQueueResult({
|
|
280
|
+
result: transformed,
|
|
281
|
+
contentTypes: recommendationContentTypes,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
if (viewFilter) {
|
|
285
|
+
transformed = filterListResultByOperatorView({
|
|
286
|
+
result: transformed,
|
|
287
|
+
viewFilter,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return transformed;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function assertRecommendationWindowResult({ operation, result }) {
|
|
294
|
+
const mode = operation?.pagination?.coverageMode;
|
|
295
|
+
if (!mode || mode === "legacy") return;
|
|
296
|
+
const after = result?.data?.pagination?.after;
|
|
297
|
+
const snapshotTimeStamp = result?.data?.pagination?.snapshotTimeStamp;
|
|
298
|
+
if (
|
|
299
|
+
!Number.isSafeInteger(after) ||
|
|
300
|
+
after < 0 ||
|
|
301
|
+
!Number.isSafeInteger(snapshotTimeStamp) ||
|
|
302
|
+
snapshotTimeStamp < 0
|
|
303
|
+
) {
|
|
304
|
+
const error = new Error(
|
|
305
|
+
"The deployed API did not confirm the bounded recommendation window and snapshot. Deploy the matching API before using this CLI; use --include-legacy only for an intentional historical scan.",
|
|
306
|
+
);
|
|
307
|
+
error.code = "LUMINE_ADMIN_RECOMMENDATION_WINDOW_UNSUPPORTED";
|
|
308
|
+
error.data = {
|
|
309
|
+
ok: false,
|
|
310
|
+
status: "validation_error",
|
|
311
|
+
error: {
|
|
312
|
+
code: error.code,
|
|
313
|
+
message: error.message,
|
|
314
|
+
details: { requestedMode: mode },
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function finishAdminOutput({ options, operation, result }) {
|
|
178
322
|
if (options.json) {
|
|
179
323
|
console.log(JSON.stringify(result));
|
|
180
324
|
return result;
|
|
@@ -460,6 +604,31 @@ export function parseAdminOperation(options) {
|
|
|
460
604
|
if (action === "status") {
|
|
461
605
|
return readOperation("daily-run.status", "/cli/admin/daily-runs/status");
|
|
462
606
|
}
|
|
607
|
+
if (action === "report") {
|
|
608
|
+
return readOperation("daily-run.report", "/cli/admin/daily-runs/report");
|
|
609
|
+
}
|
|
610
|
+
if (action === "escalation" && target === "add") {
|
|
611
|
+
const rawTarget = String(options.adminTarget || "").trim();
|
|
612
|
+
const summary = String(options.note || "").trim();
|
|
613
|
+
if (!rawTarget || !summary) {
|
|
614
|
+
throw cliValidationError(
|
|
615
|
+
"Pass a concrete --target and --note when recording a run escalation.",
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
const parsedTarget = parseAdminEscalationTarget(rawTarget);
|
|
619
|
+
return writeOperation(
|
|
620
|
+
"daily-run.escalation.add",
|
|
621
|
+
"POST",
|
|
622
|
+
"/cli/admin/daily-runs/escalations",
|
|
623
|
+
{
|
|
624
|
+
targetType: parsedTarget.targetType || undefined,
|
|
625
|
+
targetId: parsedTarget.targetId || undefined,
|
|
626
|
+
url: parsedTarget.url || undefined,
|
|
627
|
+
summary,
|
|
628
|
+
severity: options.adminSeverity || "attention",
|
|
629
|
+
},
|
|
630
|
+
);
|
|
631
|
+
}
|
|
463
632
|
if (action === "complete" || action === "fail") {
|
|
464
633
|
return writeOperation(
|
|
465
634
|
`daily-run.${action}`,
|
|
@@ -478,6 +647,7 @@ export function parseAdminOperation(options) {
|
|
|
478
647
|
if (kind !== "recommend") {
|
|
479
648
|
throw cliValidationError("--kind currently supports only recommend.");
|
|
480
649
|
}
|
|
650
|
+
const recommendationWindow = parseRecommendationWindow(options);
|
|
481
651
|
return readOperation(
|
|
482
652
|
"recommendations.list",
|
|
483
653
|
withQuery("/cli/admin/recommendations", {
|
|
@@ -485,7 +655,33 @@ export function parseAdminOperation(options) {
|
|
|
485
655
|
contentTypes: options.adminContentTypes,
|
|
486
656
|
cursor: options.adminCursor,
|
|
487
657
|
limit: options.limit,
|
|
658
|
+
sinceRun: recommendationWindow.mode === "since-run" ? "true" : "",
|
|
659
|
+
after:
|
|
660
|
+
recommendationWindow.mode === "after"
|
|
661
|
+
? recommendationWindow.after
|
|
662
|
+
: "",
|
|
663
|
+
includeLegacy:
|
|
664
|
+
recommendationWindow.mode === "legacy" ? "true" : "",
|
|
488
665
|
}),
|
|
666
|
+
{
|
|
667
|
+
pagination: {
|
|
668
|
+
collectionKey: "items",
|
|
669
|
+
coverageQueue: "recommendations",
|
|
670
|
+
coverageMode: recommendationWindow.mode,
|
|
671
|
+
after:
|
|
672
|
+
recommendationWindow.mode === "after"
|
|
673
|
+
? parseAfterForCoverage(recommendationWindow.after)
|
|
674
|
+
: null,
|
|
675
|
+
filters: {
|
|
676
|
+
contentTypes: options.adminContentTypes || null,
|
|
677
|
+
operatorView: options.adminUnviewed
|
|
678
|
+
? "unviewed"
|
|
679
|
+
: options.adminViewed
|
|
680
|
+
? "viewed"
|
|
681
|
+
: null,
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
},
|
|
489
685
|
);
|
|
490
686
|
}
|
|
491
687
|
|
|
@@ -498,8 +694,33 @@ export function parseAdminOperation(options) {
|
|
|
498
694
|
cursor: options.adminCursor,
|
|
499
695
|
limit: options.limit,
|
|
500
696
|
}),
|
|
697
|
+
{
|
|
698
|
+
pagination: {
|
|
699
|
+
collectionKey: "builds",
|
|
700
|
+
coverageQueue: "builds",
|
|
701
|
+
coverageMode: "all",
|
|
702
|
+
after: null,
|
|
703
|
+
filters: { sort: "recent", scope: "all" },
|
|
704
|
+
},
|
|
705
|
+
},
|
|
501
706
|
);
|
|
502
707
|
}
|
|
708
|
+
if (namespace === "builds" && action === "review") {
|
|
709
|
+
const parsed = parseAdminCommentTarget({ target, explicitType: "build" });
|
|
710
|
+
if (parsed.type !== "build") {
|
|
711
|
+
throw cliValidationError(
|
|
712
|
+
"Build review targets a Build URL or build:<id>.",
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
return {
|
|
716
|
+
name: "build.review",
|
|
717
|
+
method: "GET",
|
|
718
|
+
path: "",
|
|
719
|
+
body: undefined,
|
|
720
|
+
mutates: false,
|
|
721
|
+
buildId: parsed.id,
|
|
722
|
+
};
|
|
723
|
+
}
|
|
503
724
|
|
|
504
725
|
if (
|
|
505
726
|
namespace === "subjects" &&
|
|
@@ -524,6 +745,7 @@ export function parseAdminOperation(options) {
|
|
|
524
745
|
cursor: options.adminCursor,
|
|
525
746
|
limit: options.limit,
|
|
526
747
|
}),
|
|
748
|
+
{ pagination: { collectionKey: "comments" } },
|
|
527
749
|
);
|
|
528
750
|
}
|
|
529
751
|
if (action === "reveal") {
|
|
@@ -591,6 +813,7 @@ export function parseAdminOperation(options) {
|
|
|
591
813
|
cursor: options.adminCursor,
|
|
592
814
|
limit: options.limit,
|
|
593
815
|
}),
|
|
816
|
+
{ pagination: { collectionKey: "comments" } },
|
|
594
817
|
);
|
|
595
818
|
}
|
|
596
819
|
if (action === "recommend") {
|
|
@@ -613,6 +836,20 @@ export function parseAdminOperation(options) {
|
|
|
613
836
|
{ reason: options.adminReason || undefined },
|
|
614
837
|
);
|
|
615
838
|
}
|
|
839
|
+
if (action === "skip-batch") {
|
|
840
|
+
if (!options.adminTargetFile) {
|
|
841
|
+
throw cliValidationError(
|
|
842
|
+
"Pass batch skip targets with --target-file <file>.",
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
return {
|
|
846
|
+
name: "post.skip-batch",
|
|
847
|
+
method: "POST",
|
|
848
|
+
path: "",
|
|
849
|
+
body: undefined,
|
|
850
|
+
mutates: true,
|
|
851
|
+
};
|
|
852
|
+
}
|
|
616
853
|
if (action === "reward") {
|
|
617
854
|
const parsedTarget = parseRecommendationTarget({
|
|
618
855
|
target,
|
|
@@ -653,22 +890,41 @@ export function parseAdminOperation(options) {
|
|
|
653
890
|
...(repairDate ? { date: repairDate } : {}),
|
|
654
891
|
});
|
|
655
892
|
}
|
|
656
|
-
if (action === "
|
|
657
|
-
const
|
|
658
|
-
options.
|
|
659
|
-
"--edition-id",
|
|
660
|
-
1,
|
|
893
|
+
if (action === "validate") {
|
|
894
|
+
const claim = extractNewsClaim(
|
|
895
|
+
readAdminJsonFile(options.adminClaimFile, "--claim <claim.json>"),
|
|
661
896
|
);
|
|
662
|
-
|
|
897
|
+
return {
|
|
898
|
+
name: "news.validate",
|
|
899
|
+
local: true,
|
|
900
|
+
mutates: false,
|
|
901
|
+
claim,
|
|
902
|
+
editorial: readEditorialFile(options.adminFile),
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
if (action === "submit") {
|
|
906
|
+
const claim = options.adminClaimFile
|
|
907
|
+
? extractNewsClaim(
|
|
908
|
+
readAdminJsonFile(options.adminClaimFile, "--claim <claim.json>"),
|
|
909
|
+
)
|
|
910
|
+
: null;
|
|
911
|
+
const editionId = claim
|
|
912
|
+
? claim.editionId
|
|
913
|
+
: parseRequiredInteger(options.adminEditionId, "--edition-id", 1);
|
|
914
|
+
const leaseToken = claim
|
|
915
|
+
? claim.leaseToken
|
|
916
|
+
: String(options.adminLeaseToken || "").trim();
|
|
663
917
|
if (!leaseToken) {
|
|
664
918
|
throw cliValidationError(
|
|
665
919
|
"Pass the claim's lease token with --lease-token <token>.",
|
|
666
920
|
);
|
|
667
921
|
}
|
|
922
|
+
const editorial = readEditorialFile(options.adminFile);
|
|
923
|
+
if (claim) validateNewsEditorial({ claim, editorial });
|
|
668
924
|
return writeOperation("news.submit", "POST", "/cli/admin/news/submit", {
|
|
669
925
|
editionId,
|
|
670
926
|
leaseToken,
|
|
671
|
-
editorial
|
|
927
|
+
editorial,
|
|
672
928
|
model: options.model || undefined,
|
|
673
929
|
});
|
|
674
930
|
}
|
|
@@ -776,6 +1032,7 @@ export function parseAdminOperation(options) {
|
|
|
776
1032
|
limit: options.limit,
|
|
777
1033
|
full: options.adminFull ? "true" : "",
|
|
778
1034
|
}),
|
|
1035
|
+
{ pagination: { collectionKey: "events" } },
|
|
779
1036
|
);
|
|
780
1037
|
}
|
|
781
1038
|
|
|
@@ -800,20 +1057,46 @@ export function parseAdminOperation(options) {
|
|
|
800
1057
|
const buildReviewMethod = options.adminBuildReviewMethod
|
|
801
1058
|
? parseAdminBuildReviewMethod(options.adminBuildReviewMethod)
|
|
802
1059
|
: undefined;
|
|
1060
|
+
const reviewReceipt = options.adminReviewReceipt
|
|
1061
|
+
? parseBuildReviewReceipt(options.adminReviewReceipt)
|
|
1062
|
+
: null;
|
|
1063
|
+
if (
|
|
1064
|
+
reviewReceipt &&
|
|
1065
|
+
(reviewedBuildVersionId || buildReviewMethod)
|
|
1066
|
+
) {
|
|
1067
|
+
throw cliValidationError(
|
|
1068
|
+
"Pass either --review-receipt or manual --reviewed-version/--reviewed-via evidence, not both.",
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
const confirmedBuildVersionId = reviewReceipt
|
|
1072
|
+
? Number(reviewReceipt.publishedArtifactVersionId)
|
|
1073
|
+
: reviewedBuildVersionId;
|
|
1074
|
+
const confirmedBuildReviewMethod = reviewReceipt
|
|
1075
|
+
? "runtime"
|
|
1076
|
+
: buildReviewMethod;
|
|
1077
|
+
if (
|
|
1078
|
+
reviewReceipt &&
|
|
1079
|
+
parsedTarget.type === "build" &&
|
|
1080
|
+
Number(reviewReceipt.buildId) !== parsedTarget.id
|
|
1081
|
+
) {
|
|
1082
|
+
throw cliValidationError(
|
|
1083
|
+
"The review receipt belongs to a different Build.",
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
803
1086
|
if (parsedTarget.type === "build") {
|
|
804
1087
|
if (!options.adminFile) {
|
|
805
1088
|
throw cliValidationError(
|
|
806
1089
|
"Build comments are management-agent composed only; pass --file <comment.md> after reviewing the project.",
|
|
807
1090
|
);
|
|
808
1091
|
}
|
|
809
|
-
if (!
|
|
1092
|
+
if (!confirmedBuildVersionId || !confirmedBuildReviewMethod) {
|
|
810
1093
|
throw cliValidationError(
|
|
811
1094
|
"After reviewing the project, pass both --reviewed-version <published-artifact-id> and --reviewed-via runtime|code.",
|
|
812
1095
|
);
|
|
813
1096
|
}
|
|
814
1097
|
} else if (
|
|
815
1098
|
parsedTarget.type !== "comment" &&
|
|
816
|
-
(
|
|
1099
|
+
(confirmedBuildVersionId || confirmedBuildReviewMethod)
|
|
817
1100
|
) {
|
|
818
1101
|
throw cliValidationError(
|
|
819
1102
|
"Build review evidence applies only to build:<id> or a comment:<id> inside a Build.",
|
|
@@ -832,8 +1115,12 @@ export function parseAdminOperation(options) {
|
|
|
832
1115
|
...(options.adminFile
|
|
833
1116
|
? { content: readComposedTextFile(options.adminFile) }
|
|
834
1117
|
: {}),
|
|
835
|
-
...(
|
|
836
|
-
|
|
1118
|
+
...(confirmedBuildVersionId
|
|
1119
|
+
? { reviewedBuildVersionId: confirmedBuildVersionId }
|
|
1120
|
+
: {}),
|
|
1121
|
+
...(confirmedBuildReviewMethod
|
|
1122
|
+
? { buildReviewMethod: confirmedBuildReviewMethod }
|
|
1123
|
+
: {}),
|
|
837
1124
|
},
|
|
838
1125
|
);
|
|
839
1126
|
}
|
|
@@ -890,6 +1177,17 @@ function subjectsListOperation(options) {
|
|
|
890
1177
|
effort: options.adminEffort,
|
|
891
1178
|
limit: options.limit,
|
|
892
1179
|
}),
|
|
1180
|
+
{
|
|
1181
|
+
pagination: {
|
|
1182
|
+
collectionKey: "subjects",
|
|
1183
|
+
coverageQueue: "subjects",
|
|
1184
|
+
coverageMode: options.adminAfter ? "after" : "all",
|
|
1185
|
+
after: options.adminAfter
|
|
1186
|
+
? parseAfterForCoverage(options.adminAfter)
|
|
1187
|
+
: null,
|
|
1188
|
+
filters: { effort: options.adminEffort || "all" },
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
893
1191
|
);
|
|
894
1192
|
}
|
|
895
1193
|
|
|
@@ -997,6 +1295,35 @@ function recommendOperation(target, options) {
|
|
|
997
1295
|
);
|
|
998
1296
|
}
|
|
999
1297
|
|
|
1298
|
+
export function parseRecommendationWindow(options) {
|
|
1299
|
+
const selected = [
|
|
1300
|
+
options.adminSinceRun ? "since-run" : "",
|
|
1301
|
+
options.adminAfter ? "after" : "",
|
|
1302
|
+
options.adminIncludeLegacy ? "legacy" : "",
|
|
1303
|
+
].filter(Boolean);
|
|
1304
|
+
if (selected.length > 1) {
|
|
1305
|
+
throw cliValidationError(
|
|
1306
|
+
"Choose one recommendation window: --since-run, --after, or --include-legacy.",
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
const mode = selected[0] || "since-run";
|
|
1310
|
+
if (mode === "after") parseAfterForCoverage(options.adminAfter);
|
|
1311
|
+
return { mode, after: mode === "after" ? options.adminAfter : "" };
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
function parseAfterForCoverage(value) {
|
|
1315
|
+
const raw = String(value || "").trim();
|
|
1316
|
+
if (/^\d+$/.test(raw)) {
|
|
1317
|
+
const parsed = Number(raw);
|
|
1318
|
+
if (Number.isSafeInteger(parsed) && parsed >= 0) return parsed;
|
|
1319
|
+
}
|
|
1320
|
+
const parsedMs = Date.parse(raw);
|
|
1321
|
+
if (Number.isFinite(parsedMs)) return Math.floor(parsedMs / 1000);
|
|
1322
|
+
throw cliValidationError(
|
|
1323
|
+
"--after must be a Unix timestamp or ISO-8601 date.",
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1000
1327
|
export function parseSubjectId(value) {
|
|
1001
1328
|
const normalized = String(value || "").trim();
|
|
1002
1329
|
const match = normalized.match(/(?:^subject:|\/subjects\/)(\d+)(?:[/?#]|$)/i);
|
|
@@ -1090,6 +1417,42 @@ export function parseAdminCommentTarget({ target, explicitType = "" }) {
|
|
|
1090
1417
|
return baseTarget;
|
|
1091
1418
|
}
|
|
1092
1419
|
|
|
1420
|
+
export function parseAdminEscalationTarget(value) {
|
|
1421
|
+
const normalized = String(value || "").trim();
|
|
1422
|
+
const genericTarget = normalized.match(
|
|
1423
|
+
/^([a-zA-Z][a-zA-Z0-9_-]{0,39}):(\d+)$/,
|
|
1424
|
+
);
|
|
1425
|
+
if (genericTarget) {
|
|
1426
|
+
return {
|
|
1427
|
+
targetType: genericTarget[1],
|
|
1428
|
+
targetId: parseRequiredInteger(genericTarget[2], "escalation target ID", 1),
|
|
1429
|
+
url: null,
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
if (/^https:\/\//i.test(normalized)) {
|
|
1433
|
+
let parsedUrl;
|
|
1434
|
+
try {
|
|
1435
|
+
parsedUrl = new URL(normalized);
|
|
1436
|
+
} catch {
|
|
1437
|
+
throw cliValidationError("The escalation target URL is invalid.");
|
|
1438
|
+
}
|
|
1439
|
+
if (parsedUrl.protocol !== "https:") {
|
|
1440
|
+
throw cliValidationError("The escalation target URL must use HTTPS.");
|
|
1441
|
+
}
|
|
1442
|
+
if (
|
|
1443
|
+
/\/(?:subjects|comments|ai-stories|daily-reflections|app|build)\/\d+(?:[/?#]|$)/i.test(
|
|
1444
|
+
normalized,
|
|
1445
|
+
)
|
|
1446
|
+
) {
|
|
1447
|
+
const parsed = parseAdminCommentTarget({ target: normalized });
|
|
1448
|
+
return { targetType: parsed.type, targetId: parsed.id, url: normalized };
|
|
1449
|
+
}
|
|
1450
|
+
return { targetType: null, targetId: null, url: normalized };
|
|
1451
|
+
}
|
|
1452
|
+
const parsed = parseAdminCommentTarget({ target: normalized });
|
|
1453
|
+
return { targetType: parsed.type, targetId: parsed.id, url: null };
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1093
1456
|
function parseAdminBuildReviewMethod(value) {
|
|
1094
1457
|
const normalized = String(value || "")
|
|
1095
1458
|
.trim()
|
|
@@ -1134,8 +1497,15 @@ export function formatAdminJsonError(error) {
|
|
|
1134
1497
|
};
|
|
1135
1498
|
}
|
|
1136
1499
|
|
|
1137
|
-
function readOperation(name, path) {
|
|
1138
|
-
return {
|
|
1500
|
+
function readOperation(name, path, extra = {}) {
|
|
1501
|
+
return {
|
|
1502
|
+
name,
|
|
1503
|
+
method: "GET",
|
|
1504
|
+
path,
|
|
1505
|
+
body: undefined,
|
|
1506
|
+
mutates: false,
|
|
1507
|
+
...extra,
|
|
1508
|
+
};
|
|
1139
1509
|
}
|
|
1140
1510
|
|
|
1141
1511
|
function writeOperation(name, method, path, body) {
|
|
@@ -1276,8 +1646,73 @@ function cliValidationError(message) {
|
|
|
1276
1646
|
return error;
|
|
1277
1647
|
}
|
|
1278
1648
|
|
|
1649
|
+
function adminValueFingerprint(value) {
|
|
1650
|
+
return createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1279
1653
|
function printAdminResult({ operation, result }) {
|
|
1280
1654
|
const data = result?.data || {};
|
|
1655
|
+
if (data.review) {
|
|
1656
|
+
console.log(
|
|
1657
|
+
`Confirmed Build #${data.review.buildId} runtime at published artifact #${data.review.publishedArtifactVersionId}.`,
|
|
1658
|
+
);
|
|
1659
|
+
console.log(`Screenshot: ${data.screenshotPath}`);
|
|
1660
|
+
console.log(`Review receipt: ${data.receiptPath}`);
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
if (data.validation) {
|
|
1664
|
+
console.log(
|
|
1665
|
+
`Editorial valid for edition #${data.validation.editionId}: ${data.validation.citedEventCount} cited and ${data.validation.coveredEventCount} covered event(s).`,
|
|
1666
|
+
);
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
if (data.batch) {
|
|
1670
|
+
console.log(
|
|
1671
|
+
`Skipped ${data.batch.completedCount} audited target(s); ${data.batch.changedCount} changed canonical state.`,
|
|
1672
|
+
);
|
|
1673
|
+
console.log(`Checkpoint: ${data.batch.checkpointPath}`);
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
if (data.report) {
|
|
1677
|
+
const report = data.report;
|
|
1678
|
+
console.log(
|
|
1679
|
+
`Run #${report.run.id}: ${report.mutations.successfulMutationCount} successful mutation(s), ${report.queueCoverage.length} queue coverage record(s), ${report.escalations.length} escalation(s).`,
|
|
1680
|
+
);
|
|
1681
|
+
for (const coverage of report.queueCoverage) {
|
|
1682
|
+
console.log(
|
|
1683
|
+
` ${coverage.queue}: ${coverage.candidateCount} candidate(s), ${coverage.scannedCount} row(s) scanned across ${coverage.pages} page(s).`,
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
for (const escalation of report.escalations) {
|
|
1687
|
+
const target =
|
|
1688
|
+
escalation.url ||
|
|
1689
|
+
`${escalation.targetType || "target"}:${escalation.targetId || "?"}`;
|
|
1690
|
+
console.log(
|
|
1691
|
+
` ${String(escalation.severity || "attention").toUpperCase()} ${target} — ${escalation.summary}`,
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
const surfaces = report.brief?.engagementPulse?.surfaces;
|
|
1695
|
+
if (surfaces && typeof surfaces === "object") {
|
|
1696
|
+
const deltas = Object.entries(surfaces)
|
|
1697
|
+
.filter(([, value]) => Number(value?.delta || 0) !== 0)
|
|
1698
|
+
.sort(
|
|
1699
|
+
([, left], [, right]) =>
|
|
1700
|
+
Math.abs(Number(right?.delta || 0)) -
|
|
1701
|
+
Math.abs(Number(left?.delta || 0)),
|
|
1702
|
+
)
|
|
1703
|
+
.slice(0, 5)
|
|
1704
|
+
.map(
|
|
1705
|
+
([name, value]) =>
|
|
1706
|
+
`${name} ${Number(value.delta) > 0 ? "+" : ""}${Number(value.delta)}`,
|
|
1707
|
+
);
|
|
1708
|
+
if (deltas.length) console.log(`Engagement deltas: ${deltas.join(", ")}.`);
|
|
1709
|
+
}
|
|
1710
|
+
const notableCount = Array.isArray(report.brief?.notableCandidates)
|
|
1711
|
+
? report.brief.notableCandidates.length
|
|
1712
|
+
: 0;
|
|
1713
|
+
console.log(`Notable-user candidates in this brief: ${notableCount}.`);
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1281
1716
|
if (data.bucket && Array.isArray(data.memberUserIds)) {
|
|
1282
1717
|
const added = Array.isArray(data.accounts)
|
|
1283
1718
|
? `; added ${data.accounts.length} explicit account(s)`
|
|
@@ -1347,12 +1782,28 @@ function printAdminResult({ operation, result }) {
|
|
|
1347
1782
|
return;
|
|
1348
1783
|
}
|
|
1349
1784
|
if (data.claim) {
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
`
|
|
1355
|
-
|
|
1785
|
+
if (data.artifacts?.claimFile) {
|
|
1786
|
+
console.log(
|
|
1787
|
+
`Claimed edition #${data.claim.editionId} (${data.claim.dateKey}): ${data.claim.events.length} event(s).`,
|
|
1788
|
+
);
|
|
1789
|
+
console.log(`Claim file: ${data.artifacts.claimFile}`);
|
|
1790
|
+
if (data.artifacts?.scaffoldFile) {
|
|
1791
|
+
console.log(`Editorial scaffold: ${data.artifacts.scaffoldFile}`);
|
|
1792
|
+
}
|
|
1793
|
+
console.log(
|
|
1794
|
+
`Validate before submission: lumine admin news validate --claim ${data.artifacts.claimFile} --file ${data.artifacts.scaffoldFile || "editorial.json"}`,
|
|
1795
|
+
);
|
|
1796
|
+
console.log(
|
|
1797
|
+
`Submit the confirmed pair: lumine admin news submit --claim ${data.artifacts.claimFile} --file ${data.artifacts.scaffoldFile || "editorial.json"}`,
|
|
1798
|
+
);
|
|
1799
|
+
} else {
|
|
1800
|
+
console.log(
|
|
1801
|
+
`Claimed edition #${data.claim.editionId} (${data.claim.dateKey}): ${data.claim.events.length} event(s); lease token ${data.claim.leaseToken}.`,
|
|
1802
|
+
);
|
|
1803
|
+
console.log(
|
|
1804
|
+
`Write the editorial JSON, then run: lumine admin news submit --edition-id ${data.claim.editionId} --lease-token ${data.claim.leaseToken} --file editorial.json`,
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1356
1807
|
return;
|
|
1357
1808
|
}
|
|
1358
1809
|
if (data.newspaper) {
|