@stage5/lumine 0.2.32 → 0.2.34
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 +11 -0
- package/lib/admin.js +213 -10
- package/lib/commands.js +18 -4
- package/package.json +1 -1
- package/sdk/LUMINE_ADMIN.md +112 -12
package/README.md
CHANGED
|
@@ -169,6 +169,7 @@ lumine admin daily-run start --identity auto --comment-mode off --json
|
|
|
169
169
|
lumine admin recommendations list --cursor '<cursor>' --json
|
|
170
170
|
lumine admin subjects candidates --after 2026-08-01T00:00:00Z --json
|
|
171
171
|
lumine admin subjects candidates --effort unassigned --json
|
|
172
|
+
lumine admin builds candidates --cursor '<cursor>' --json
|
|
172
173
|
lumine admin subject get 123 --include-comments --json
|
|
173
174
|
lumine admin post get https://www.twin-kle.com/ai-stories/88 --json
|
|
174
175
|
lumine admin post comments dailyReflection:99 --json
|
|
@@ -184,6 +185,9 @@ lumine admin brief --days 3 --json
|
|
|
184
185
|
lumine admin notable add Minecrarft_guy --note "Created 8 thoughtful subjects and helped peers in 23 comments this window." --json
|
|
185
186
|
lumine admin post recommend comment:456 --anyone-can-reward --reward-twinkles 3 --json
|
|
186
187
|
lumine admin post reward comment:456 --twinkles 3 --json
|
|
188
|
+
lumine admin comment draft build:884 --file comment.md \
|
|
189
|
+
--reviewed-version 4512 --reviewed-via runtime --json
|
|
190
|
+
lumine admin comment post --draft-id 77 --json
|
|
187
191
|
lumine admin daily-run complete --json
|
|
188
192
|
```
|
|
189
193
|
|
|
@@ -195,6 +199,13 @@ and posts use the selected bot's server-owned canonical persona; a later human
|
|
|
195
199
|
reply is handled by Twinkle's existing autonomous Zero/Ciel responder without
|
|
196
200
|
Lumine remaining active.
|
|
197
201
|
|
|
202
|
+
Management agents also inspect recent public Build candidates during each run.
|
|
203
|
+
A direct Build comment is never server-generated: first open and try the
|
|
204
|
+
published app or pull and read its code, then compose with `--file` and bind
|
|
205
|
+
the draft to the exact `publishedArtifactVersionId` using
|
|
206
|
+
`--reviewed-version` and `--reviewed-via runtime|code`. The server rejects
|
|
207
|
+
missing or stale review evidence and any app/thread change before publication.
|
|
208
|
+
|
|
198
209
|
Every operation is noninteractive when its required arguments are present.
|
|
199
210
|
`--json` prints exactly one uncolored JSON value and returns a nonzero status
|
|
200
211
|
for forbidden, not-found, validation, and partial-failure responses. Pass a
|
package/lib/admin.js
CHANGED
|
@@ -125,6 +125,12 @@ export async function adminCommand(options) {
|
|
|
125
125
|
},
|
|
126
126
|
timeoutMs: options.timeoutMs,
|
|
127
127
|
});
|
|
128
|
+
if (operation.name === "builds.candidates") {
|
|
129
|
+
result = normalizeAdminBuildCandidatesResult({
|
|
130
|
+
result,
|
|
131
|
+
siteUrl: options.siteUrl,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
128
134
|
if (recommendationContentTypes) {
|
|
129
135
|
result = filterRecommendationQueueResult({
|
|
130
136
|
result,
|
|
@@ -179,6 +185,38 @@ export async function adminCommand(options) {
|
|
|
179
185
|
return result;
|
|
180
186
|
}
|
|
181
187
|
|
|
188
|
+
export function normalizeAdminBuildCandidatesResult({ result, siteUrl }) {
|
|
189
|
+
const builds = Array.isArray(result?.builds) ? result.builds : [];
|
|
190
|
+
const nextCursor = String(result?.cursor || "").trim() || null;
|
|
191
|
+
return {
|
|
192
|
+
ok: true,
|
|
193
|
+
status: "success",
|
|
194
|
+
data: {
|
|
195
|
+
builds: builds.map((build) => {
|
|
196
|
+
const id = Number(build?.id || 0);
|
|
197
|
+
return {
|
|
198
|
+
...build,
|
|
199
|
+
url:
|
|
200
|
+
id > 0
|
|
201
|
+
? `${String(siteUrl || "").replace(/\/$/, "")}/app/${id}`
|
|
202
|
+
: null,
|
|
203
|
+
review: {
|
|
204
|
+
publishedArtifactVersionId:
|
|
205
|
+
Number(build?.publishedArtifactVersionId || 0) || null,
|
|
206
|
+
codePullAvailable: build?.collaborationMode === "open_source",
|
|
207
|
+
requiredBeforeComment: true,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}),
|
|
211
|
+
pagination: {
|
|
212
|
+
nextCursor,
|
|
213
|
+
hasMore: Boolean(nextCursor),
|
|
214
|
+
exhausted: !nextCursor,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
182
220
|
export function assertComposedCommentDraftResult({ result, expectedContent }) {
|
|
183
221
|
const draft = result?.data?.draft;
|
|
184
222
|
if (
|
|
@@ -313,13 +351,15 @@ export function resolveOperatorViewFilter({ operation, unviewed, viewed }) {
|
|
|
313
351
|
}
|
|
314
352
|
|
|
315
353
|
function adminOperationRequiresRun(operation) {
|
|
316
|
-
return
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
354
|
+
return (
|
|
355
|
+
![
|
|
356
|
+
"identity.list",
|
|
357
|
+
"identity.status",
|
|
358
|
+
"identity.use",
|
|
359
|
+
"daily-run.start",
|
|
360
|
+
"daily-run.status",
|
|
361
|
+
].includes(operation.name) && !operation.name.startsWith("ai-bucket.")
|
|
362
|
+
);
|
|
323
363
|
}
|
|
324
364
|
|
|
325
365
|
function noActiveRunError() {
|
|
@@ -360,6 +400,50 @@ export function parseAdminOperation(options) {
|
|
|
360
400
|
}
|
|
361
401
|
}
|
|
362
402
|
|
|
403
|
+
if (namespace === "ai-bucket" || namespace === "ai-buckets") {
|
|
404
|
+
const bucketId = parseRequiredInteger(
|
|
405
|
+
options.adminBucketId,
|
|
406
|
+
"AI bucket ID",
|
|
407
|
+
1,
|
|
408
|
+
);
|
|
409
|
+
if (action === "get" || action === "status") {
|
|
410
|
+
return readOperation(
|
|
411
|
+
"ai-bucket.get",
|
|
412
|
+
`/cli/admin/ai-buckets/${bucketId}`,
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
if (action === "accounts" && target === "add") {
|
|
416
|
+
return writeOperation(
|
|
417
|
+
"ai-bucket.accounts.add",
|
|
418
|
+
"POST",
|
|
419
|
+
`/cli/admin/ai-buckets/${bucketId}/accounts`,
|
|
420
|
+
{
|
|
421
|
+
userIds: parseAiBucketUserIds(options.adminUserIds),
|
|
422
|
+
note: options.note || undefined,
|
|
423
|
+
},
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
if (action === "note" && target === "set") {
|
|
427
|
+
const note = String(options.note || "").trim();
|
|
428
|
+
if (!note) {
|
|
429
|
+
throw cliValidationError(
|
|
430
|
+
"Pass the quota-only context with --note <text>.",
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
if (note.length > 255) {
|
|
434
|
+
throw cliValidationError(
|
|
435
|
+
"An AI bucket note can be at most 255 characters.",
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
return writeOperation(
|
|
439
|
+
"ai-bucket.note.set",
|
|
440
|
+
"PUT",
|
|
441
|
+
`/cli/admin/ai-buckets/${bucketId}/note`,
|
|
442
|
+
{ note },
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
363
447
|
if (namespace === "daily-run") {
|
|
364
448
|
if (action === "start") {
|
|
365
449
|
return writeOperation(
|
|
@@ -407,6 +491,18 @@ export function parseAdminOperation(options) {
|
|
|
407
491
|
);
|
|
408
492
|
}
|
|
409
493
|
|
|
494
|
+
if (namespace === "builds" && action === "candidates") {
|
|
495
|
+
return readOperation(
|
|
496
|
+
"builds.candidates",
|
|
497
|
+
withQuery("/build/public/list", {
|
|
498
|
+
sort: "recent",
|
|
499
|
+
scope: "all",
|
|
500
|
+
cursor: options.adminCursor,
|
|
501
|
+
limit: options.limit,
|
|
502
|
+
}),
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
410
506
|
if (
|
|
411
507
|
namespace === "subjects" &&
|
|
412
508
|
(action === "list" || action === "candidates")
|
|
@@ -644,7 +740,7 @@ export function parseAdminOperation(options) {
|
|
|
644
740
|
}
|
|
645
741
|
|
|
646
742
|
if (namespace === "bot-output" && !action) {
|
|
647
|
-
if (options.adminDays
|
|
743
|
+
if (options.adminDays) {
|
|
648
744
|
const days = Number(options.adminDays);
|
|
649
745
|
if (!Number.isInteger(days) || days < 1 || days > 30) {
|
|
650
746
|
throw cliValidationError("--days must be an integer between 1 and 30.");
|
|
@@ -676,7 +772,7 @@ export function parseAdminOperation(options) {
|
|
|
676
772
|
|
|
677
773
|
if (namespace === "comment") {
|
|
678
774
|
if (action === "draft" || action === "reply") {
|
|
679
|
-
const parsedTarget =
|
|
775
|
+
const parsedTarget = parseAdminCommentTarget({
|
|
680
776
|
target,
|
|
681
777
|
explicitType: options.adminType,
|
|
682
778
|
});
|
|
@@ -685,6 +781,35 @@ export function parseAdminOperation(options) {
|
|
|
685
781
|
"comment reply targets a comment: lumine admin comment reply comment:<id>.",
|
|
686
782
|
);
|
|
687
783
|
}
|
|
784
|
+
const reviewedBuildVersionId = options.adminReviewedBuildVersion
|
|
785
|
+
? parseRequiredInteger(
|
|
786
|
+
options.adminReviewedBuildVersion,
|
|
787
|
+
"--reviewed-version",
|
|
788
|
+
1,
|
|
789
|
+
)
|
|
790
|
+
: undefined;
|
|
791
|
+
const buildReviewMethod = options.adminBuildReviewMethod
|
|
792
|
+
? parseAdminBuildReviewMethod(options.adminBuildReviewMethod)
|
|
793
|
+
: undefined;
|
|
794
|
+
if (parsedTarget.type === "build") {
|
|
795
|
+
if (!options.adminFile) {
|
|
796
|
+
throw cliValidationError(
|
|
797
|
+
"Build comments are management-agent composed only; pass --file <comment.md> after reviewing the project.",
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
if (!reviewedBuildVersionId || !buildReviewMethod) {
|
|
801
|
+
throw cliValidationError(
|
|
802
|
+
"After reviewing the project, pass both --reviewed-version <published-artifact-id> and --reviewed-via runtime|code.",
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
} else if (
|
|
806
|
+
parsedTarget.type !== "comment" &&
|
|
807
|
+
(reviewedBuildVersionId || buildReviewMethod)
|
|
808
|
+
) {
|
|
809
|
+
throw cliValidationError(
|
|
810
|
+
"Build review evidence applies only to build:<id> or a comment:<id> inside a Build.",
|
|
811
|
+
);
|
|
812
|
+
}
|
|
688
813
|
return writeOperation(
|
|
689
814
|
"comment.draft",
|
|
690
815
|
"POST",
|
|
@@ -698,6 +823,8 @@ export function parseAdminOperation(options) {
|
|
|
698
823
|
...(options.adminFile
|
|
699
824
|
? { content: readComposedCommentFile(options.adminFile) }
|
|
700
825
|
: {}),
|
|
826
|
+
...(reviewedBuildVersionId ? { reviewedBuildVersionId } : {}),
|
|
827
|
+
...(buildReviewMethod ? { buildReviewMethod } : {}),
|
|
701
828
|
},
|
|
702
829
|
);
|
|
703
830
|
}
|
|
@@ -741,7 +868,7 @@ export function parseAdminOperation(options) {
|
|
|
741
868
|
}
|
|
742
869
|
|
|
743
870
|
throw cliValidationError(
|
|
744
|
-
"Usage: lumine admin identity|daily-run|recommendations|post|subjects|subject|featured|comment|chat|news|audit|brief|bot-output|notable ...",
|
|
871
|
+
"Usage: lumine admin identity|daily-run|recommendations|builds|post|subjects|subject|featured|comment|chat|news|audit|brief|bot-output|notable ...",
|
|
745
872
|
);
|
|
746
873
|
}
|
|
747
874
|
|
|
@@ -920,6 +1047,50 @@ export function parseRecommendationTarget({ target, explicitType = "" }) {
|
|
|
920
1047
|
return { type, id };
|
|
921
1048
|
}
|
|
922
1049
|
|
|
1050
|
+
export function parseAdminCommentTarget({ target, explicitType = "" }) {
|
|
1051
|
+
const normalized = String(target || "").trim();
|
|
1052
|
+
const prefixed = normalized.match(
|
|
1053
|
+
/^(subject|comment|build|aistory|dailyreflection):(\d+)$/i,
|
|
1054
|
+
);
|
|
1055
|
+
const buildUrl = normalized.match(/\/(?:app|build)\/(\d+)(?:[/?#]|$)/i);
|
|
1056
|
+
const baseTarget = parseRecommendationTarget({
|
|
1057
|
+
target:
|
|
1058
|
+
prefixed?.[1]?.toLowerCase() === "build" || buildUrl
|
|
1059
|
+
? `subject:${prefixed?.[2] || buildUrl?.[1]}`
|
|
1060
|
+
: normalized,
|
|
1061
|
+
explicitType:
|
|
1062
|
+
String(explicitType || "").toLowerCase() === "build"
|
|
1063
|
+
? "subject"
|
|
1064
|
+
: explicitType,
|
|
1065
|
+
});
|
|
1066
|
+
const inferredBuild = prefixed?.[1]?.toLowerCase() === "build" || !!buildUrl;
|
|
1067
|
+
const explicitBuild = String(explicitType || "").toLowerCase() === "build";
|
|
1068
|
+
if (explicitType && !explicitBuild && inferredBuild) {
|
|
1069
|
+
throw cliValidationError(
|
|
1070
|
+
"The target and --type identify different content types.",
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
if (explicitBuild && !inferredBuild && !/^\d+$/.test(normalized)) {
|
|
1074
|
+
throw cliValidationError(
|
|
1075
|
+
"The target and --type identify different content types.",
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
if (inferredBuild || explicitBuild) {
|
|
1079
|
+
return { type: "build", id: baseTarget.id };
|
|
1080
|
+
}
|
|
1081
|
+
return baseTarget;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function parseAdminBuildReviewMethod(value) {
|
|
1085
|
+
const normalized = String(value || "")
|
|
1086
|
+
.trim()
|
|
1087
|
+
.toLowerCase();
|
|
1088
|
+
if (normalized !== "runtime" && normalized !== "code") {
|
|
1089
|
+
throw cliValidationError("--reviewed-via must be runtime or code.");
|
|
1090
|
+
}
|
|
1091
|
+
return normalized;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
923
1094
|
function normalizeRecommendationTargetType(value) {
|
|
924
1095
|
const normalized = String(value || "")
|
|
925
1096
|
.trim()
|
|
@@ -1010,6 +1181,29 @@ function parseOrderedIds(value) {
|
|
|
1010
1181
|
return ids;
|
|
1011
1182
|
}
|
|
1012
1183
|
|
|
1184
|
+
function parseAiBucketUserIds(value) {
|
|
1185
|
+
const raw = String(value || "").trim();
|
|
1186
|
+
if (!raw) {
|
|
1187
|
+
throw cliValidationError(
|
|
1188
|
+
"Pass explicit accounts with --user-ids <id,id,...>.",
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
const ids = raw
|
|
1192
|
+
.split(",")
|
|
1193
|
+
.map((part) => part.trim())
|
|
1194
|
+
.filter(Boolean)
|
|
1195
|
+
.map((part) => parseRequiredInteger(part, "AI bucket user ID", 1));
|
|
1196
|
+
if (ids.length > 500) {
|
|
1197
|
+
throw cliValidationError(
|
|
1198
|
+
"An AI bucket batch can contain at most 500 users.",
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
if (new Set(ids).size !== ids.length) {
|
|
1202
|
+
throw cliValidationError("AI bucket user IDs must be unique.");
|
|
1203
|
+
}
|
|
1204
|
+
return ids;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1013
1207
|
function parseRequiredInteger(
|
|
1014
1208
|
value,
|
|
1015
1209
|
label,
|
|
@@ -1049,6 +1243,15 @@ function cliValidationError(message) {
|
|
|
1049
1243
|
|
|
1050
1244
|
function printAdminResult({ operation, result }) {
|
|
1051
1245
|
const data = result?.data || {};
|
|
1246
|
+
if (data.bucket && Array.isArray(data.memberUserIds)) {
|
|
1247
|
+
const added = Array.isArray(data.accounts)
|
|
1248
|
+
? `; added ${data.accounts.length} explicit account(s)`
|
|
1249
|
+
: "";
|
|
1250
|
+
console.log(
|
|
1251
|
+
`AI bucket #${data.bucket.id} (${data.bucket.label}): ${data.memberCount} canonical member account(s)${added}.`,
|
|
1252
|
+
);
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1052
1255
|
if (data.run !== undefined) {
|
|
1053
1256
|
if (!data.run) {
|
|
1054
1257
|
console.log("No active delegated administrator daily run.");
|
package/lib/commands.js
CHANGED
|
@@ -2172,6 +2172,8 @@ export function parseArgs(args) {
|
|
|
2172
2172
|
: raw.ids
|
|
2173
2173
|
? String(raw.ids)
|
|
2174
2174
|
: "",
|
|
2175
|
+
adminBucketId: raw.bucketId ? String(raw.bucketId) : "",
|
|
2176
|
+
adminUserIds: raw.userIds ? String(raw.userIds) : "",
|
|
2175
2177
|
adminType: raw.type ? String(raw.type) : "",
|
|
2176
2178
|
adminKind: raw.kind ? String(raw.kind) : "",
|
|
2177
2179
|
adminContentTypes: raw.contentTypes ? String(raw.contentTypes) : "",
|
|
@@ -2192,6 +2194,10 @@ export function parseArgs(args) {
|
|
|
2192
2194
|
adminEditionId: raw.editionId ? String(raw.editionId) : "",
|
|
2193
2195
|
adminLeaseToken: raw.leaseToken ? String(raw.leaseToken) : "",
|
|
2194
2196
|
adminFile: raw.file ? String(raw.file) : "",
|
|
2197
|
+
adminReviewedBuildVersion: raw.reviewedVersion
|
|
2198
|
+
? String(raw.reviewedVersion)
|
|
2199
|
+
: "",
|
|
2200
|
+
adminBuildReviewMethod: raw.reviewedVia ? String(raw.reviewedVia) : "",
|
|
2195
2201
|
adminFull: parseBoolean(raw.full, false),
|
|
2196
2202
|
rewardTwinkles: raw.rewardTwinkles ? String(raw.rewardTwinkles) : "",
|
|
2197
2203
|
includeComments: parseBoolean(raw.includeComments, false),
|
|
@@ -2507,9 +2513,13 @@ export function printHelp() {
|
|
|
2507
2513
|
lumine thumbnail generate ["<prompt>"] --model <gpt-image-2|nano-banana>
|
|
2508
2514
|
lumine doctor runtime-assets
|
|
2509
2515
|
lumine admin identity list|status|use <zero|ciel|auto> [--json]
|
|
2516
|
+
lumine admin ai-bucket get --bucket-id <id> [--json]
|
|
2517
|
+
lumine admin ai-bucket accounts add --bucket-id <id> --user-ids <id,id,...> [--note <text>] [--json]
|
|
2518
|
+
lumine admin ai-bucket note set --bucket-id <id> --note <text> [--json]
|
|
2510
2519
|
lumine admin daily-run start [--identity zero|ciel|auto] [--comment-mode off|draft|post] [--run-key <key>] [--json]
|
|
2511
2520
|
lumine admin daily-run status|complete|fail [--reason <text>] [--json]
|
|
2512
2521
|
lumine admin recommendations list [--content-types comment,dailyReflection] [--unviewed|--viewed] [--cursor <cursor>] [--json]
|
|
2522
|
+
lumine admin builds candidates [--cursor <cursor>] [--limit <number>] [--json]
|
|
2513
2523
|
lumine admin subjects candidates [--after <date>] [--effort unassigned] [--unviewed|--viewed] [--cursor <cursor>] [--json]
|
|
2514
2524
|
lumine admin subject get|reveal <subject-url-or-id> [--json]
|
|
2515
2525
|
lumine admin subject comments <subject-url-or-id> [--unviewed|--viewed] [--cursor <cursor>] [--json]
|
|
@@ -2523,8 +2533,8 @@ export function printHelp() {
|
|
|
2523
2533
|
lumine admin post recommend <target> [--type subject|comment|aiStory|dailyReflection] [--anyone-can-reward] [--reward-twinkles 3] [--json]
|
|
2524
2534
|
lumine admin post skip <target> [--type comment|aiStory|dailyReflection] [--reason <text>] [--json]
|
|
2525
2535
|
lumine admin post reward <target> [--type subject|comment|aiStory|dailyReflection] --twinkles 3 [--json]
|
|
2526
|
-
lumine admin comment draft <target> [--type subject|comment|aiStory|dailyReflection] [--identity zero|ciel|auto] [--json]
|
|
2527
|
-
lumine admin comment reply comment:<id> [--identity zero|ciel|auto] [--json]
|
|
2536
|
+
lumine admin comment draft <target> [--type subject|comment|build|aiStory|dailyReflection] [--file <comment.md>] [--reviewed-version <id> --reviewed-via runtime|code] [--identity zero|ciel|auto] [--json]
|
|
2537
|
+
lumine admin comment reply comment:<id> [--file <reply.md>] [--reviewed-version <id> --reviewed-via runtime|code] [--identity zero|ciel|auto] [--json]
|
|
2528
2538
|
lumine admin comment post --draft-id <id> [--json]
|
|
2529
2539
|
lumine admin comment edit <comment-id> --file <comment.md> [--json]
|
|
2530
2540
|
lumine admin brief [--days <1..30>] [--json]
|
|
@@ -2593,7 +2603,7 @@ Options:
|
|
|
2593
2603
|
--description <text> Build description for new/describe
|
|
2594
2604
|
--no-description Skip New description or clear with describe
|
|
2595
2605
|
--summary <text> Save summary
|
|
2596
|
-
--note <text>
|
|
2606
|
+
--note <text> Suggestion, notable-user, or AI-bucket context
|
|
2597
2607
|
--cursor <id> Continue an owner suggestion inbox listing
|
|
2598
2608
|
--after <date> Admin subjects: inclusive Unix/ISO creation boundary
|
|
2599
2609
|
--effort unassigned Admin subjects: show only unassigned effort
|
|
@@ -2605,13 +2615,17 @@ Options:
|
|
|
2605
2615
|
--idempotency-key <k> Stable retry key for one admin mutation
|
|
2606
2616
|
--level <1|2|3> Admin subject effort level
|
|
2607
2617
|
--subject-ids <ids> Complete ordered Featured subject IDs
|
|
2608
|
-
--
|
|
2618
|
+
--bucket-id <id> Unbanned AI identity bucket for account consolidation
|
|
2619
|
+
--user-ids <ids> Explicit user IDs for an AI bucket batch (up to 500)
|
|
2620
|
+
--type <type> Admin target: subject, comment, build, aiStory, or dailyReflection
|
|
2609
2621
|
--kind recommend Admin recommendation queue kind
|
|
2610
2622
|
--anyone-can-reward Enable canonical reward eligibility
|
|
2611
2623
|
--reward-twinkles 3 Pair a recommendation with exactly 3 Twinkles
|
|
2612
2624
|
--twinkles 3 Give exactly 3 Twinkles through the normal economy
|
|
2613
2625
|
--draft-id <id> Canonical delegated comment draft ID
|
|
2614
2626
|
--file <path> Editorial JSON or composed comment text file
|
|
2627
|
+
--reviewed-version <id> Published Build artifact version actually reviewed
|
|
2628
|
+
--reviewed-via <method> Build review method: runtime or code
|
|
2615
2629
|
--reason <text> Reason when marking an admin run failed
|
|
2616
2630
|
--force Overwrite server files even if this workspace is stale or missing filesHash
|
|
2617
2631
|
--search <text> Search public open-source Builds
|
package/package.json
CHANGED
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -49,6 +49,36 @@ Comment mode is stored only on the current run:
|
|
|
49
49
|
- `draft`: server-generated drafts, no public comment.
|
|
50
50
|
- `post`: drafts plus idempotent publication through the ordinary comment path.
|
|
51
51
|
|
|
52
|
+
### Private AI-bucket maintenance
|
|
53
|
+
|
|
54
|
+
AI identity buckets are private operator bookkeeping, not a Zero/Ciel public
|
|
55
|
+
action. They therefore do not require or attach to a delegated daily run:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
lumine admin ai-bucket get --bucket-id 10 --json
|
|
59
|
+
lumine admin ai-bucket accounts add --bucket-id 10 \
|
|
60
|
+
--user-ids 3127,13037,15410,16288 \
|
|
61
|
+
--note "operator-confirmed account family" --json
|
|
62
|
+
lumine admin ai-bucket note set --bucket-id 10 \
|
|
63
|
+
--note "Quota accounting only; not a moderation flag." --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`accounts add` accepts 1-500 unique positive user IDs, preflights the complete
|
|
67
|
+
batch before writing, adds the canonical user and durable verified-email rules,
|
|
68
|
+
re-attributes current-day AI usage, and returns the canonical bucket members.
|
|
69
|
+
It is idempotent to retry. The API records the real operator in the private
|
|
70
|
+
Lumine audit log; no public bot identity is involved.
|
|
71
|
+
|
|
72
|
+
`note set` records up to 255 characters of private operational context on the
|
|
73
|
+
canonical bucket. Use it to distinguish quota bookkeeping from moderation;
|
|
74
|
+
the note itself changes no access, ban, or identity rules.
|
|
75
|
+
|
|
76
|
+
This surface intentionally accepts only an existing **unbanned** bucket. It
|
|
77
|
+
cannot ban accounts, block signup, add IP/device/risk-key rules, or infer an
|
|
78
|
+
account family. Identification remains a human/LLM evidence judgment and must
|
|
79
|
+
be explicitly requested by Mikey; routine administrator runs still escalate
|
|
80
|
+
suspected alternate accounts and never auto-enforce.
|
|
81
|
+
|
|
52
82
|
## Editorial priorities
|
|
53
83
|
|
|
54
84
|
The CLI enforces none of this — it is the standing instruction for the operator
|
|
@@ -460,6 +490,7 @@ lumine admin subjects candidates --after 2026-08-01T00:00:00Z \
|
|
|
460
490
|
--cursor '<cursor>' --json
|
|
461
491
|
lumine admin subjects candidates --effort unassigned --json
|
|
462
492
|
lumine admin subjects candidates --unviewed --json
|
|
493
|
+
lumine admin builds candidates --cursor '<cursor>' --limit 50 --json
|
|
463
494
|
```
|
|
464
495
|
|
|
465
496
|
Schemas:
|
|
@@ -505,6 +536,29 @@ type SubjectCandidates = Success<{
|
|
|
505
536
|
subjects: Subject[];
|
|
506
537
|
pagination: Pagination & { scannedCount: number };
|
|
507
538
|
}>;
|
|
539
|
+
|
|
540
|
+
type BuildCandidates = Success<{
|
|
541
|
+
builds: Array<{
|
|
542
|
+
id: number;
|
|
543
|
+
title: string | null;
|
|
544
|
+
description: string | null;
|
|
545
|
+
username: string | null;
|
|
546
|
+
publishedAt: number | null;
|
|
547
|
+
publishedArtifactVersionId: number | null;
|
|
548
|
+
collaborationMode: "private" | "open_source";
|
|
549
|
+
url: string;
|
|
550
|
+
review: {
|
|
551
|
+
publishedArtifactVersionId: number | null;
|
|
552
|
+
codePullAvailable: boolean;
|
|
553
|
+
requiredBeforeComment: true;
|
|
554
|
+
};
|
|
555
|
+
}>;
|
|
556
|
+
pagination: {
|
|
557
|
+
nextCursor: string | null;
|
|
558
|
+
hasMore: boolean;
|
|
559
|
+
exhausted: boolean;
|
|
560
|
+
};
|
|
561
|
+
}>;
|
|
508
562
|
```
|
|
509
563
|
|
|
510
564
|
Both cursors freeze a primary-key high-water mark and traverse descending IDs,
|
|
@@ -514,6 +568,24 @@ filters, so a page — recommendation or subject — can be empty while `hasMore
|
|
|
514
568
|
remains true; continue until `exhausted`. Subject `--after` is inclusive, and
|
|
515
569
|
the opaque cursor is bound to its original date and effort filters.
|
|
516
570
|
|
|
571
|
+
`builds candidates` is a management-agent discovery view over the canonical
|
|
572
|
+
public Build browser, ordered by the current published release. It is
|
|
573
|
+
available through the `admin` namespace only while a delegated run is active;
|
|
574
|
+
page until `pagination.exhausted`. Each item includes its canonical app URL,
|
|
575
|
+
published artifact version, and whether its code is pullable. This list does
|
|
576
|
+
not decide that an app deserves a comment. The management agent must open and
|
|
577
|
+
genuinely try the published runtime, or pull and read an open-source project,
|
|
578
|
+
before making that judgment. Direct API/persona automation is never a review
|
|
579
|
+
substitute.
|
|
580
|
+
|
|
581
|
+
During every management run, scan recent Build candidates back through the
|
|
582
|
+
run's review window alongside Subjects and the recommendation queue. An app
|
|
583
|
+
that is thin, broken, private, unchanged since a prior substantive bot
|
|
584
|
+
comment, or not meaningfully understood may be left alone. A new or materially
|
|
585
|
+
updated app where specific, truthful feedback would help is comment-worthy.
|
|
586
|
+
This is editorial attention, not a quota: do not manufacture a Build comment
|
|
587
|
+
just to prove the queue was visited.
|
|
588
|
+
|
|
517
589
|
`--content-types` is sent to APIs that support server-side filtering so excluded
|
|
518
590
|
types do not run their eligibility/content queries. The local CLI also filters
|
|
519
591
|
the returned page defensively for deployment compatibility. The server cursor
|
|
@@ -1629,7 +1701,7 @@ from memory:
|
|
|
1629
1701
|
decisions are yours to make and record with `post skip` or in the run
|
|
1630
1702
|
report).
|
|
1631
1703
|
|
|
1632
|
-
**Lumine Build app posts are composed-only, and only after actually looking
|
|
1704
|
+
**Lumine Build apps and app posts are composed-only, and only after actually looking
|
|
1633
1705
|
(Mikey's direction, 2026-08-10).** When a post is about a Build app — the
|
|
1634
1706
|
author shares their app, announces an update, or asks for feedback on their
|
|
1635
1707
|
build — never use the server-generated draft path: the API persona cannot
|
|
@@ -1647,6 +1719,29 @@ tried it — ask the author about it instead. This is the standing rule for
|
|
|
1647
1719
|
every composed comment, applied to apps: never claim an experience the
|
|
1648
1720
|
session did not actually have.
|
|
1649
1721
|
|
|
1722
|
+
The same rule covers comments placed **directly on a Build app**. This is
|
|
1723
|
+
deliberately management-agent-only: no server-generated draft and no pure API
|
|
1724
|
+
persona may author one. After reviewing the project, bind the composed comment
|
|
1725
|
+
to the exact published artifact you saw:
|
|
1726
|
+
|
|
1727
|
+
```bash
|
|
1728
|
+
lumine admin comment draft build:884 --file comment.md \
|
|
1729
|
+
--reviewed-version 4512 --reviewed-via runtime --json
|
|
1730
|
+
lumine admin comment post --draft-id 77 --json
|
|
1731
|
+
```
|
|
1732
|
+
|
|
1733
|
+
Use `--reviewed-via code` only when you actually pulled and read the project;
|
|
1734
|
+
`runtime` means you opened and tried the published app. Replies to human
|
|
1735
|
+
comments inside a Build use `comment:<id>` plus the same review flags. The API
|
|
1736
|
+
rejects missing review evidence, a server-generated Build draft, a mismatched
|
|
1737
|
+
published version, a private/noncanonical Build, or any Build/comment-context
|
|
1738
|
+
change between draft and publication. A changed version means review the new
|
|
1739
|
+
project state and compose again. The flags are an auditable statement of what
|
|
1740
|
+
the management agent did, not permission to infer experience from metadata.
|
|
1741
|
+
Autonomous mention/reply generation and sponsored AI replies are disabled in
|
|
1742
|
+
Build threads. The generic `comment edit` shortcut is also disabled there;
|
|
1743
|
+
review the current version and post a version-bound correction reply instead.
|
|
1744
|
+
|
|
1650
1745
|
**Offer a Lumine prompt when the moment invites it (Mikey's direction,
|
|
1651
1746
|
2026-08-10).** Zero and Ciel may include one concrete, copy-pasteable Lumine
|
|
1652
1747
|
prompt in a comment or reply — a genuinely powerful one, tailored to what the
|
|
@@ -1686,15 +1781,18 @@ containers, and publication applies to both kinds of draft.
|
|
|
1686
1781
|
A draft targets one of:
|
|
1687
1782
|
|
|
1688
1783
|
- `subject:<id>` (or a bare numeric ID) — a top-level comment on the subject;
|
|
1784
|
+
- `build:<id>` — a top-level comment on a public canonical Build, composed
|
|
1785
|
+
after reviewing its exact published version;
|
|
1689
1786
|
- `aiStory:<id>` / `dailyReflection:<id>` — a top-level comment on the
|
|
1690
1787
|
standalone post;
|
|
1691
1788
|
- `comment:<id>` — a public reply to that specific comment. `comment reply`
|
|
1692
1789
|
is the same operation and requires a comment target.
|
|
1693
1790
|
|
|
1694
1791
|
A reply's container resolves canonically from the target comment: its subject,
|
|
1695
|
-
or
|
|
1696
|
-
rejected with `CLI_ADMIN_UNSUPPORTED_REPLY_ROOT`.
|
|
1697
|
-
|
|
1792
|
+
Build, or AI Story / Daily Reflection root. Comments under any other root are
|
|
1793
|
+
rejected with `CLI_ADMIN_UNSUPPORTED_REPLY_ROOT`. Build replies require the
|
|
1794
|
+
same exact-version review evidence as top-level Build comments. Replies to
|
|
1795
|
+
Zero/Ciel comments and to notification comments are rejected with
|
|
1698
1796
|
`CLI_ADMIN_INVALID_REPLY_TARGET` — the bots never thread with themselves or
|
|
1699
1797
|
each other, and a human's later reply to a delegated comment still enters the
|
|
1700
1798
|
existing autonomous comment-assistant pipeline. Published replies carry the
|
|
@@ -1706,7 +1804,7 @@ type CommentDraft = Success<{
|
|
|
1706
1804
|
draft: {
|
|
1707
1805
|
id: number;
|
|
1708
1806
|
runId: number;
|
|
1709
|
-
targetType: "subject" | "comment" | "aiStory" | "dailyReflection";
|
|
1807
|
+
targetType: "subject" | "comment" | "build" | "aiStory" | "dailyReflection";
|
|
1710
1808
|
targetId: number;
|
|
1711
1809
|
targetUrl: string;
|
|
1712
1810
|
subjectId: number | null; // container subject; null for standalone posts
|
|
@@ -1737,7 +1835,8 @@ type CommentPost = CommentGet & {
|
|
|
1737
1835
|
};
|
|
1738
1836
|
published: {
|
|
1739
1837
|
commentId: number;
|
|
1740
|
-
targetType:
|
|
1838
|
+
targetType:
|
|
1839
|
+
"subject" | "comment" | "build" | "aiStory" | "dailyReflection";
|
|
1741
1840
|
targetId: number;
|
|
1742
1841
|
subjectId: number | null;
|
|
1743
1842
|
subjectUrl: string | null;
|
|
@@ -1748,12 +1847,13 @@ type CommentPost = CommentGet & {
|
|
|
1748
1847
|
};
|
|
1749
1848
|
```
|
|
1750
1849
|
|
|
1751
|
-
|
|
1752
|
-
complete visible comment context, then invokes the existing exact
|
|
1753
|
-
system prompt through the shared response assembler with a
|
|
1754
|
-
decision policy (comment vs reply). The raw prompt is never
|
|
1755
|
-
audited. The model—not regexes or keyword rules—chooses `draft`
|
|
1756
|
-
under the run policy.
|
|
1850
|
+
For Subjects and standalone posts, the server loads the canonical container
|
|
1851
|
+
and its complete visible comment context, then invokes the existing exact
|
|
1852
|
+
Zero/Ciel system prompt through the shared response assembler with a
|
|
1853
|
+
mode-specific decision policy (comment vs reply). The raw prompt is never
|
|
1854
|
+
returned or audited. The model—not regexes or keyword rules—chooses `draft`
|
|
1855
|
+
or `skip` under the run policy. Build comments never enter that generated
|
|
1856
|
+
path; they require management-agent-composed content and review evidence.
|
|
1757
1857
|
|
|
1758
1858
|
Draft IDs are bound to operator, run, public bot, target, comment mode,
|
|
1759
1859
|
context revision, persona revision, expiry, and idempotency key. The context
|