@stage5/lumine 0.3.35 → 0.3.37
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/lib/admin.js +81 -1
- package/lib/api.js +1 -1
- package/lib/commands.js +10 -2
- package/package.json +1 -1
- package/sdk/BUILD_SDK_INDEX.md +2 -2
- package/sdk/LUMINE_ADMIN.md +33 -0
package/lib/admin.js
CHANGED
|
@@ -3509,7 +3509,7 @@ export function parseAdminOperation(options) {
|
|
|
3509
3509
|
// long as two GPT-6.1 Sol calls, so it gets its own timeout. The daily
|
|
3510
3510
|
// website management run calls it in a bounded loop (Mikey, 2026-09-28).
|
|
3511
3511
|
const usage =
|
|
3512
|
-
"Usage: lumine admin reward-bank coverage <buildId> [--max-step 3] | seed <buildId> [--max-step 3] [--identity zero|ciel|auto] | report <buildId> [--days 1].";
|
|
3512
|
+
"Usage: lumine admin reward-bank coverage <buildId> [--max-step 3] | seed <buildId> [--max-step 3] [--identity zero|ciel|auto] | report <buildId> [--days 1] | question <buildId> --question-id <id> | repair <buildId> --file <repair.json> [--dry-run].";
|
|
3513
3513
|
const buildId = parseRequiredInteger(
|
|
3514
3514
|
target || options.adminBuild,
|
|
3515
3515
|
"Build ID",
|
|
@@ -3519,6 +3519,59 @@ export function parseAdminOperation(options) {
|
|
|
3519
3519
|
? parseRequiredInteger(options.adminMaxStep, "--max-step", 1)
|
|
3520
3520
|
: 3;
|
|
3521
3521
|
if (maxStep > 10) throw cliValidationError("--max-step must be at most 10.");
|
|
3522
|
+
if (action === "question") {
|
|
3523
|
+
const questionId = parseRequiredInteger(
|
|
3524
|
+
options.adminQuestionId,
|
|
3525
|
+
"--question-id",
|
|
3526
|
+
1,
|
|
3527
|
+
);
|
|
3528
|
+
return readOperation(
|
|
3529
|
+
"reward-bank.question",
|
|
3530
|
+
withQuery("/cli/admin/reward-bank/question", {
|
|
3531
|
+
buildId: String(buildId),
|
|
3532
|
+
questionId: String(questionId),
|
|
3533
|
+
}),
|
|
3534
|
+
{ requiresRun: false },
|
|
3535
|
+
);
|
|
3536
|
+
}
|
|
3537
|
+
if (action === "repair") {
|
|
3538
|
+
const repair = readAdminJsonFile(
|
|
3539
|
+
options.adminFile,
|
|
3540
|
+
"--file <repair.json>",
|
|
3541
|
+
{ maxBytes: 16 * 1024 },
|
|
3542
|
+
);
|
|
3543
|
+
const fields = ["questionId", "expectedFingerprint", "answer", "reason"];
|
|
3544
|
+
if (
|
|
3545
|
+
!repair ||
|
|
3546
|
+
typeof repair !== "object" ||
|
|
3547
|
+
Array.isArray(repair) ||
|
|
3548
|
+
Object.keys(repair).some((key) => !fields.includes(key)) ||
|
|
3549
|
+
!Number.isSafeInteger(repair.questionId) ||
|
|
3550
|
+
repair.questionId <= 0 ||
|
|
3551
|
+
typeof repair.answer !== "number" ||
|
|
3552
|
+
!Number.isFinite(repair.answer) ||
|
|
3553
|
+
typeof repair.expectedFingerprint !== "string" ||
|
|
3554
|
+
!/^[a-f0-9]{64}$/.test(repair.expectedFingerprint) ||
|
|
3555
|
+
typeof repair.reason !== "string" ||
|
|
3556
|
+
!repair.reason.trim() ||
|
|
3557
|
+
repair.reason.length > 2000
|
|
3558
|
+
) {
|
|
3559
|
+
throw cliValidationError(
|
|
3560
|
+
"Repair JSON needs questionId, the inspected expectedFingerprint, a finite numeric answer and a reason (1–2000 characters); no other fields.",
|
|
3561
|
+
);
|
|
3562
|
+
}
|
|
3563
|
+
return writeOperation(
|
|
3564
|
+
"reward-bank.repair",
|
|
3565
|
+
"POST",
|
|
3566
|
+
"/cli/admin/reward-bank/repair",
|
|
3567
|
+
{
|
|
3568
|
+
buildId,
|
|
3569
|
+
repair,
|
|
3570
|
+
dryRun: Boolean(options.adminDryRun),
|
|
3571
|
+
},
|
|
3572
|
+
{ requiresRun: false, mutates: !options.adminDryRun },
|
|
3573
|
+
);
|
|
3574
|
+
}
|
|
3522
3575
|
if (action === "report") {
|
|
3523
3576
|
const days = options.adminDays
|
|
3524
3577
|
? parseRequiredInteger(options.adminDays, "--days", 1)
|
|
@@ -7124,6 +7177,13 @@ function printRewardBankReport(data) {
|
|
|
7124
7177
|
);
|
|
7125
7178
|
}
|
|
7126
7179
|
}
|
|
7180
|
+
if (data.numericAnswers) {
|
|
7181
|
+
const n = data.numericAnswers;
|
|
7182
|
+
console.log(`Numeric answers (${n.serverAnswerContract}): ${n.decimalQuestions} decimal questions / ${n.questions} total · ${n.decimalsCreatedInWindow} new decimals`);
|
|
7183
|
+
console.log(` Decimal follow-up: ${n.decimalClaims.served} served · ${n.decimalClaims.answered} answered · first-try ${pct(n.decimalClaims.firstTryRate)} · ${n.decimalClaims.coverage}`);
|
|
7184
|
+
} else {
|
|
7185
|
+
console.log("Numeric answer telemetry: unavailable on this server version.");
|
|
7186
|
+
}
|
|
7127
7187
|
console.log(`Learners: ${data.learners.total}`);
|
|
7128
7188
|
for (const row of data.learners.byRuleStep) {
|
|
7129
7189
|
console.log(
|
|
@@ -7378,6 +7438,26 @@ function printAdminResult({ operation, result }) {
|
|
|
7378
7438
|
}
|
|
7379
7439
|
}
|
|
7380
7440
|
if (operation.name.startsWith("reward-bank.")) {
|
|
7441
|
+
if (
|
|
7442
|
+
["reward-bank.question", "reward-bank.repair"].includes(operation.name)
|
|
7443
|
+
) {
|
|
7444
|
+
const question = data.question;
|
|
7445
|
+
console.log(
|
|
7446
|
+
`Question #${question.id} · Build ${question.buildId} · ${question.mode} · ${question.status}`,
|
|
7447
|
+
);
|
|
7448
|
+
console.log(question.prompt);
|
|
7449
|
+
console.log(`Stored answer: ${question.answer}`);
|
|
7450
|
+
if (question.hint) console.log(`Hint: ${question.hint}`);
|
|
7451
|
+
if (question.guide) console.log(`Guide: ${question.guide}`);
|
|
7452
|
+
console.log(`Fingerprint: ${data.fingerprint}`);
|
|
7453
|
+
console.log(`History: ${JSON.stringify(data.impact)}`);
|
|
7454
|
+
if (Object.hasOwn(data, "proposedAnswer"))
|
|
7455
|
+
console.log(
|
|
7456
|
+
`Proposed answer: ${data.proposedAnswer} · would change: ${data.wouldChange}`,
|
|
7457
|
+
);
|
|
7458
|
+
console.log(data.historyPolicy);
|
|
7459
|
+
return;
|
|
7460
|
+
}
|
|
7381
7461
|
if (operation.name === "reward-bank.seed") {
|
|
7382
7462
|
console.log(
|
|
7383
7463
|
data.seeded
|
package/lib/api.js
CHANGED
|
@@ -372,7 +372,7 @@ export async function saveProjectFiles({
|
|
|
372
372
|
// Required when the workspace has no filesHash (old/stale checkout).
|
|
373
373
|
...(force ? { force: true } : {}),
|
|
374
374
|
},
|
|
375
|
-
timeoutMs: options.timeoutMs,
|
|
375
|
+
timeoutMs: options.validationTimeoutMs ?? options.timeoutMs,
|
|
376
376
|
});
|
|
377
377
|
}
|
|
378
378
|
|
package/lib/commands.js
CHANGED
|
@@ -1316,7 +1316,7 @@ export async function check(options) {
|
|
|
1316
1316
|
const result = await requestJson({
|
|
1317
1317
|
url: `${options.apiUrl}/cli/build/${buildId}/launch-check`,
|
|
1318
1318
|
authToken: auth.token,
|
|
1319
|
-
timeoutMs: options.timeoutMs,
|
|
1319
|
+
timeoutMs: options.validationTimeoutMs ?? options.timeoutMs,
|
|
1320
1320
|
});
|
|
1321
1321
|
printCheck(result);
|
|
1322
1322
|
if (!result.ok) process.exitCode = 1;
|
|
@@ -1373,7 +1373,7 @@ export async function launch(options) {
|
|
|
1373
1373
|
const checkResult = await requestJson({
|
|
1374
1374
|
url: `${options.apiUrl}/cli/build/${buildId}/launch-check`,
|
|
1375
1375
|
authToken: auth.token,
|
|
1376
|
-
timeoutMs: options.timeoutMs,
|
|
1376
|
+
timeoutMs: options.validationTimeoutMs ?? options.timeoutMs,
|
|
1377
1377
|
});
|
|
1378
1378
|
printCheck(checkResult);
|
|
1379
1379
|
const launchOk =
|
|
@@ -2803,6 +2803,7 @@ export function parseArgs(args) {
|
|
|
2803
2803
|
adminEditionId: raw.editionId ? String(raw.editionId) : "",
|
|
2804
2804
|
adminLeaseToken: raw.leaseToken ? String(raw.leaseToken) : "",
|
|
2805
2805
|
adminFile: raw.file ? String(raw.file) : "",
|
|
2806
|
+
adminQuestionId: raw.questionId ? String(raw.questionId) : "",
|
|
2806
2807
|
rewardPreflight: Boolean(raw.preflight),
|
|
2807
2808
|
rewardApprovalFile: raw.approvalFile ? String(raw.approvalFile) : "",
|
|
2808
2809
|
// admin craft revise --item <id|name> [--why] [--emoji] [--category]
|
|
@@ -2939,6 +2940,13 @@ export function parseArgs(args) {
|
|
|
2939
2940
|
DEFAULT_TIMEOUT_MS,
|
|
2940
2941
|
1000,
|
|
2941
2942
|
),
|
|
2943
|
+
// Large saved projects can take longer than the ordinary 20s request
|
|
2944
|
+
// deadline. The server bounds compiler work at 120s; leave transport room.
|
|
2945
|
+
// An explicit --timeout-ms / environment setting still wins.
|
|
2946
|
+
validationTimeoutMs: Math.max(
|
|
2947
|
+
Number(raw.timeoutMs || process.env.TWINKLE_TIMEOUT_MS) || 150000,
|
|
2948
|
+
1000,
|
|
2949
|
+
),
|
|
2942
2950
|
help: !!raw.help || command === "help",
|
|
2943
2951
|
};
|
|
2944
2952
|
}
|
package/package.json
CHANGED
package/sdk/BUILD_SDK_INDEX.md
CHANGED
|
@@ -1029,9 +1029,9 @@ const result = await Twinkle.characters.chat({ character: 'zero', thinkingMode:
|
|
|
1029
1029
|
- Example: const { level } = await Twinkle.minecraft.getPlayArea({ id: 'twinkle-keep' });
|
|
1030
1030
|
- async getPlayAreaChunks({ id, chunks: [[cx, cz], ...] }) | scopes: content:read
|
|
1031
1031
|
- Returns: { scenes: [{ cx, cz, scene: { origin: [x,y,z], size: [w,h,d], palette, blocks, light, biomes, count, ... } | null }] }
|
|
1032
|
-
- Up to
|
|
1032
|
+
- Up to 24 chunk columns of a play area in the /snap scene format (packed visible blocks with per-face light), cropped to the area's box. Stream the ones around the player.
|
|
1033
1033
|
- Same scene format as getSnap; only blocks with a visible face inside the area are included. scene is null for a chunk that is not part of the area.
|
|
1034
|
-
- At most
|
|
1034
|
+
- At most 24 chunks per call; reads share the 180-per-minute build read limit, so cache chunks and load the nearest first.
|
|
1035
1035
|
- Example: const { scenes } = await Twinkle.minecraft.getPlayAreaChunks({ id: level.id, chunks: [[64, 29], [65, 29]] });
|
|
1036
1036
|
- async createPlayArea({ name, world, box, spawn, id }) | scopes: content:write
|
|
1037
1037
|
- Returns: { level }
|
package/sdk/LUMINE_ADMIN.md
CHANGED
|
@@ -1714,8 +1714,32 @@ them so the first learner on a unit never waits or pays.
|
|
|
1714
1714
|
lumine admin reward-bank coverage <buildId> [--max-step 3] [--json] # read-only, no run
|
|
1715
1715
|
lumine admin reward-bank seed <buildId> [--max-step 3] [--json] # delegated full run
|
|
1716
1716
|
lumine admin reward-bank report <buildId> [--days 1] [--json] # read-only telemetry
|
|
1717
|
+
lumine admin reward-bank question <buildId> --question-id <id> [--json]
|
|
1718
|
+
lumine admin reward-bank repair <buildId> --file <repair.json> --dry-run [--json]
|
|
1719
|
+
lumine admin reward-bank repair <buildId> --file <repair.json> [--json]
|
|
1717
1720
|
```
|
|
1718
1721
|
|
|
1722
|
+
`question` returns the complete prompt, answer, hint and guide, question
|
|
1723
|
+
statistics, a canonical `fingerprint`, and aggregate challenge history. It is
|
|
1724
|
+
owner-only and does not need a daily run. A report excerpt is not an exact
|
|
1725
|
+
question inspection.
|
|
1726
|
+
|
|
1727
|
+
`repair` accepts exactly `{ "questionId": 41, "expectedFingerprint": "<hash
|
|
1728
|
+
from inspection>", "answer": 0.5, "reason": "Verified explanation and arithmetic" }`.
|
|
1729
|
+
Inspect and verify the mathematics before preparing a repair. `--dry-run`
|
|
1730
|
+
checks the same guard without writing. The real command locks and rechecks the
|
|
1731
|
+
question, changes only its numeric answer, returns canonical readback and
|
|
1732
|
+
records an idempotent transaction audit. A stale fingerprint is rejected;
|
|
1733
|
+
inspect again instead of guessing a new hash. Unknown plan fields are rejected.
|
|
1734
|
+
No model call or AI Energy charge is involved.
|
|
1735
|
+
|
|
1736
|
+
The repaired answer governs subsequent attempts, including already-issued
|
|
1737
|
+
unsolved challenges. Past attempts, grades, ladders, question statistics and
|
|
1738
|
+
rewards stay unchanged; the receipt states this explicitly. The history counts
|
|
1739
|
+
are observations, not a lock over every learner's activity. If the old answer
|
|
1740
|
+
affected a learner, inspect that history and prepare a separate, exact remedy;
|
|
1741
|
+
this command never guesses compensating rewards or rewrites past grades.
|
|
1742
|
+
|
|
1719
1743
|
`report` covers the last `--days` (1-31): generation rounds by source
|
|
1720
1744
|
(learner or seed) with outcomes (`accepted`, `off_brief`: the checker judged
|
|
1721
1745
|
the question outside the brief's language, level or LaTeX rule;
|
|
@@ -2502,6 +2526,9 @@ Daily Reflection post reads and recommendation candidates include the stored
|
|
|
2502
2526
|
An absent grade is unknown. Verify `grade === "Masterpiece"` before placing one
|
|
2503
2527
|
of Mikey's reflections anywhere on the newspaper front page; lower or missing
|
|
2504
2528
|
grades can be considered for inside pages. The CLI does not infer a grade.
|
|
2529
|
+
Masterpiece is only an eligibility condition for his reflections: it does not
|
|
2530
|
+
award front-page placement, the lead, or editorial priority. Read the actual
|
|
2531
|
+
content and compare its significance to members with the day's other stories.
|
|
2505
2532
|
|
|
2506
2533
|
## Subject and Featured mutations
|
|
2507
2534
|
|
|
@@ -3019,6 +3046,12 @@ entertainment, likely comments and opportunities to join in are not the only
|
|
|
3019
3046
|
measures of importance. Explain the values being communicated; do not reduce
|
|
3020
3047
|
them to founder biography or an administrative announcement.
|
|
3021
3048
|
|
|
3049
|
+
**Editorial judgment (Mikey, 2026-10-15):** a Masterpiece grade never automatically
|
|
3050
|
+
earns a front-page slot or the lead. Use the project's canonical `CORE_VALUES.md`
|
|
3051
|
+
to assess the actual story's relevance to the community and its culture, alongside
|
|
3052
|
+
the other eligible stories. Give the substantive reason for the placement;
|
|
3053
|
+
neither the grade nor Mikey's authorship supplies that reason.
|
|
3054
|
+
|
|
3022
3055
|
Use clear, lively language that respects readers' intelligence. Give enough
|
|
3023
3056
|
context for someone who missed the original post, and make the interesting
|
|
3024
3057
|
part clear in the headline and opening. Avoid talking down to readers, forced
|