@stage5/lumine 0.2.53 → 0.2.55
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 +66 -5
- package/lib/admin-workflows.js +759 -59
- package/lib/admin.js +268 -4
- 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/auth.js +15 -9
- package/lib/commands.js +76 -28
- package/lib/constants.js +1 -0
- package/lib/sponsor.js +1292 -0
- package/package.json +1 -1
- package/sdk/LUMINE_ADMIN.md +43 -6
package/lib/admin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { once } from "node:events";
|
|
2
3
|
import { readFileSync } from "node:fs";
|
|
3
4
|
import { assertAuthScope, resolveAuth } from "./auth.js";
|
|
4
5
|
import { requestJson } from "./http.js";
|
|
@@ -8,7 +9,13 @@ import {
|
|
|
8
9
|
validateNewsEditorial,
|
|
9
10
|
writeNewsClaimArtifacts,
|
|
10
11
|
} from "./admin-news.js";
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
forEachPaginatedResultItem,
|
|
14
|
+
getPaginatedResultStorage,
|
|
15
|
+
runAutomaticPagination,
|
|
16
|
+
runBatchSkips,
|
|
17
|
+
writePaginatedResultJson,
|
|
18
|
+
} from "./admin-workflows.js";
|
|
12
19
|
import {
|
|
13
20
|
parseBuildReviewReceipt,
|
|
14
21
|
runManagedBuildReview,
|
|
@@ -380,9 +387,25 @@ export function assertRecommendationWindowResult({ operation, result }) {
|
|
|
380
387
|
}
|
|
381
388
|
}
|
|
382
389
|
|
|
383
|
-
function finishAdminOutput({ options, operation, result }) {
|
|
390
|
+
async function finishAdminOutput({ options, operation, result }) {
|
|
391
|
+
const paginationStorage = getPaginatedResultStorage(result);
|
|
384
392
|
if (options.json) {
|
|
385
|
-
|
|
393
|
+
if (paginationStorage) {
|
|
394
|
+
await writePaginatedResultJson({
|
|
395
|
+
result,
|
|
396
|
+
write: async (chunk) => {
|
|
397
|
+
if (!process.stdout.write(chunk)) {
|
|
398
|
+
await once(process.stdout, "drain");
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
} else {
|
|
403
|
+
console.log(JSON.stringify(result));
|
|
404
|
+
}
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
407
|
+
if (paginationStorage) {
|
|
408
|
+
await printSpooledAdminResult({ result, storage: paginationStorage });
|
|
386
409
|
return result;
|
|
387
410
|
}
|
|
388
411
|
printAdminResult({ operation, result });
|
|
@@ -814,6 +837,108 @@ export function parseAdminOperation(options) {
|
|
|
814
837
|
);
|
|
815
838
|
}
|
|
816
839
|
|
|
840
|
+
if (namespace === "sponsor" || namespace === "sponsors") {
|
|
841
|
+
if (action === "applications") {
|
|
842
|
+
if (!target || target === "list") {
|
|
843
|
+
return readOperation(
|
|
844
|
+
"sponsor.applications.list",
|
|
845
|
+
withQuery("/cli/admin/sponsors/applications", {
|
|
846
|
+
status: options.adminStatus || "pending",
|
|
847
|
+
limit: options.limit,
|
|
848
|
+
}),
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
if (target === "review") {
|
|
852
|
+
const applicationId = parseRequiredInteger(
|
|
853
|
+
extra,
|
|
854
|
+
"Sponsor application ID",
|
|
855
|
+
1,
|
|
856
|
+
);
|
|
857
|
+
const decision = parseChoice(
|
|
858
|
+
options.adminDecision || options.adminStatus,
|
|
859
|
+
"--decision",
|
|
860
|
+
["approve", "reject"],
|
|
861
|
+
);
|
|
862
|
+
return writeOperation(
|
|
863
|
+
"sponsor.application.review",
|
|
864
|
+
"POST",
|
|
865
|
+
`/cli/admin/sponsors/applications/${applicationId}/review`,
|
|
866
|
+
{ decision, note: options.note || undefined },
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
if (action === "status" && target === "set") {
|
|
871
|
+
const sponsorUserId = parseRequiredInteger(extra, "Sponsor user ID", 1);
|
|
872
|
+
const status = parseChoice(options.adminStatus, "--status", [
|
|
873
|
+
"probationary",
|
|
874
|
+
"trusted",
|
|
875
|
+
"suspended",
|
|
876
|
+
"revoked",
|
|
877
|
+
]);
|
|
878
|
+
return writeOperation(
|
|
879
|
+
"sponsor.status.set",
|
|
880
|
+
"PUT",
|
|
881
|
+
`/cli/admin/sponsors/${sponsorUserId}/status`,
|
|
882
|
+
{ status, note: options.note || undefined },
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
if (action === "integrity") {
|
|
886
|
+
if (target === "status") {
|
|
887
|
+
return readOperation(
|
|
888
|
+
"sponsor.integrity.status",
|
|
889
|
+
"/cli/admin/daily-runs/sponsor-integrity/status",
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
if (target === "scan") {
|
|
893
|
+
return writeOperation(
|
|
894
|
+
"sponsor.integrity.scan",
|
|
895
|
+
"POST",
|
|
896
|
+
"/cli/admin/daily-runs/sponsor-integrity/scan",
|
|
897
|
+
{},
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
if (target === "cases") {
|
|
901
|
+
return readOperation(
|
|
902
|
+
"sponsor.integrity.cases",
|
|
903
|
+
withQuery("/cli/admin/daily-runs/sponsor-integrity/cases", {
|
|
904
|
+
status: options.adminStatus || "open",
|
|
905
|
+
limit: options.limit,
|
|
906
|
+
}),
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
if (target === "get") {
|
|
910
|
+
const caseId = parseRequiredInteger(extra, "Integrity case ID", 1);
|
|
911
|
+
return readOperation(
|
|
912
|
+
"sponsor.integrity.get",
|
|
913
|
+
`/cli/admin/daily-runs/sponsor-integrity/cases/${caseId}`,
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
if (target === "review") {
|
|
917
|
+
const caseId = parseRequiredInteger(extra, "Integrity case ID", 1);
|
|
918
|
+
const decision = parseChoice(options.adminDecision, "--decision", [
|
|
919
|
+
"clear",
|
|
920
|
+
"hold",
|
|
921
|
+
"flag",
|
|
922
|
+
"disqualify",
|
|
923
|
+
]);
|
|
924
|
+
if (decision !== "clear" && !String(options.note || "").trim()) {
|
|
925
|
+
throw cliValidationError(
|
|
926
|
+
"Sponsor-integrity hold, flag, and disqualify decisions require --note <evidence>.",
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
return writeOperation(
|
|
930
|
+
"sponsor.integrity.review",
|
|
931
|
+
"POST",
|
|
932
|
+
`/cli/admin/daily-runs/sponsor-integrity/cases/${caseId}/review`,
|
|
933
|
+
{ decision, note: options.note || undefined },
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
throw cliValidationError(
|
|
938
|
+
"Usage: lumine admin sponsor applications list|review | sponsor status set | sponsor integrity status|scan|cases|get|review.",
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
|
|
817
942
|
if (namespace === "daily-run") {
|
|
818
943
|
if (action === "start") {
|
|
819
944
|
return writeOperation(
|
|
@@ -1490,7 +1615,7 @@ export function parseAdminOperation(options) {
|
|
|
1490
1615
|
}
|
|
1491
1616
|
|
|
1492
1617
|
throw cliValidationError(
|
|
1493
|
-
"Usage: lumine admin identity|economy|rescue|daily-run|escalation|todo|recommendations|builds|post|subjects|subject|featured|comment|announcement|chat|news|audit|brief|ai-costs|media-costs|bot-output|notable ...",
|
|
1618
|
+
"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 ...",
|
|
1494
1619
|
);
|
|
1495
1620
|
}
|
|
1496
1621
|
|
|
@@ -2049,6 +2174,16 @@ function parseRequiredInteger(
|
|
|
2049
2174
|
return number;
|
|
2050
2175
|
}
|
|
2051
2176
|
|
|
2177
|
+
function parseChoice(value, label, choices) {
|
|
2178
|
+
const normalized = String(value || "")
|
|
2179
|
+
.trim()
|
|
2180
|
+
.toLowerCase();
|
|
2181
|
+
if (!choices.includes(normalized)) {
|
|
2182
|
+
throw cliValidationError(`${label} must be ${choices.join(", ")}.`);
|
|
2183
|
+
}
|
|
2184
|
+
return normalized;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2052
2187
|
function defaultDailyRunKey() {
|
|
2053
2188
|
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
2054
2189
|
timeZone: "Asia/Bangkok",
|
|
@@ -2263,8 +2398,132 @@ function printAdminMonthlyMediaCosts(monthlyMediaCosts) {
|
|
|
2263
2398
|
);
|
|
2264
2399
|
}
|
|
2265
2400
|
|
|
2401
|
+
async function printSpooledAdminResult({ result, storage }) {
|
|
2402
|
+
const data = result?.data || {};
|
|
2403
|
+
const count = Number(storage.candidateCount || 0);
|
|
2404
|
+
if (storage.collectionKey === "subjects") {
|
|
2405
|
+
console.log(`${count} subject(s):`);
|
|
2406
|
+
await forEachPaginatedResultItem(result, async (subject) => {
|
|
2407
|
+
console.log(
|
|
2408
|
+
`#${subject.id} ${subject.title || "(untitled)"} — ${subject.author?.username || "unknown"} — effort ${subject.effortLevel ?? "unknown"}`,
|
|
2409
|
+
);
|
|
2410
|
+
console.log(` ${subject.url}`);
|
|
2411
|
+
});
|
|
2412
|
+
} else if (storage.collectionKey === "events") {
|
|
2413
|
+
console.log(`${count} audit event(s):`);
|
|
2414
|
+
await forEachPaginatedResultItem(result, async (event) => {
|
|
2415
|
+
const target =
|
|
2416
|
+
event.targetType && event.targetId
|
|
2417
|
+
? ` ${event.targetType}:${event.targetId}`
|
|
2418
|
+
: "";
|
|
2419
|
+
console.log(
|
|
2420
|
+
`#${event.id} run ${event.runId ?? "-"} ${event.action}${target} — ${event.result}${event.changed === true ? " (changed)" : event.changed === false ? " (no change)" : ""}`,
|
|
2421
|
+
);
|
|
2422
|
+
});
|
|
2423
|
+
} else if (storage.collectionKey === "comments") {
|
|
2424
|
+
console.log(`${count} comment(s) for ${data.subject?.url || "this target"}:`);
|
|
2425
|
+
await forEachPaginatedResultItem(result, async (comment) => {
|
|
2426
|
+
console.log(
|
|
2427
|
+
`#${comment.id} ${comment.author?.username || "unknown"}: ${comment.content || "(empty)"}`,
|
|
2428
|
+
);
|
|
2429
|
+
});
|
|
2430
|
+
} else if (storage.collectionKey === "items") {
|
|
2431
|
+
console.log(`${count} recommendation candidate(s):`);
|
|
2432
|
+
await forEachPaginatedResultItem(result, async (item) => {
|
|
2433
|
+
console.log(`#${item.contentId} ${item.contentType}`);
|
|
2434
|
+
if (item.url || item.subjectUrl) {
|
|
2435
|
+
console.log(` ${item.url || item.subjectUrl}`);
|
|
2436
|
+
}
|
|
2437
|
+
});
|
|
2438
|
+
} else if (storage.collectionKey === "builds") {
|
|
2439
|
+
console.log(`${count} Build candidate(s):`);
|
|
2440
|
+
await forEachPaginatedResultItem(result, async (build) => {
|
|
2441
|
+
console.log(`#${build.id} ${build.title || "(untitled)"}`);
|
|
2442
|
+
if (build.url) console.log(` ${build.url}`);
|
|
2443
|
+
});
|
|
2444
|
+
} else {
|
|
2445
|
+
console.log(
|
|
2446
|
+
`${count} ${storage.collectionKey} candidate(s) saved at ${storage.spoolPath}.`,
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
printPagination(data.pagination);
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2266
2452
|
function printAdminResult({ operation, result }) {
|
|
2267
2453
|
const data = result?.data || {};
|
|
2454
|
+
if (Array.isArray(data.applications)) {
|
|
2455
|
+
console.log(`${data.applications.length} sponsor application(s):`);
|
|
2456
|
+
for (const application of data.applications) {
|
|
2457
|
+
console.log(
|
|
2458
|
+
` #${application.id} ${String(application.status).toUpperCase()} · ${application.username || `user ${application.userId}`} · agreement ${application.agreementVersion || "unknown"}`,
|
|
2459
|
+
);
|
|
2460
|
+
}
|
|
2461
|
+
return;
|
|
2462
|
+
}
|
|
2463
|
+
if (data.application) {
|
|
2464
|
+
console.log(
|
|
2465
|
+
`Sponsor application #${data.application.id}: ${String(data.application.status).toUpperCase()} · ${data.application.username || `user ${data.application.userId}`}`,
|
|
2466
|
+
);
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
if (data.sponsor) {
|
|
2470
|
+
console.log(
|
|
2471
|
+
`Sponsor ${data.sponsor.username || `user ${data.sponsor.userId}`}: ${String(data.sponsor.status).toUpperCase()}.`,
|
|
2472
|
+
);
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
if (data.scan) {
|
|
2476
|
+
const scan = data.scan;
|
|
2477
|
+
console.log(
|
|
2478
|
+
`Sponsor-integrity scan #${scan.id || "not started"}: ${scan.status || "not started"} · ${scan.scannedCount || 0} scanned · ${scan.selectedReviewCount || 0} selected · ${data.openCaseCount || 0} open.`,
|
|
2479
|
+
);
|
|
2480
|
+
if (Array.isArray(data.casesCreated) && data.casesCreated.length > 0) {
|
|
2481
|
+
console.log(
|
|
2482
|
+
`Created ${data.casesCreated.length} review case(s) on this page.`,
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
if (Array.isArray(data.cases)) {
|
|
2488
|
+
console.log(`${data.cases.length} sponsor-integrity case(s):`);
|
|
2489
|
+
for (const item of data.cases) {
|
|
2490
|
+
const flags =
|
|
2491
|
+
Array.isArray(item.hardFlags) && item.hardFlags.length
|
|
2492
|
+
? ` · flags=${item.hardFlags.join(",")}`
|
|
2493
|
+
: "";
|
|
2494
|
+
console.log(
|
|
2495
|
+
` #${item.id} ${String(item.status).toUpperCase()} · job #${item.jobId} · ${item.sponsorUsername || `sponsor ${item.sponsorUserId}`}${flags}`,
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
if (data.case) {
|
|
2501
|
+
const item = data.case;
|
|
2502
|
+
console.log(
|
|
2503
|
+
`Sponsor-integrity case #${item.id}: ${String(item.status).toUpperCase()} · job #${item.job?.id} · ${item.sponsorUsername || `sponsor ${item.sponsorUserId}`}.`,
|
|
2504
|
+
);
|
|
2505
|
+
const relays = Array.isArray(item.relays) && item.relays.length > 0
|
|
2506
|
+
? item.relays
|
|
2507
|
+
: item.relay
|
|
2508
|
+
? [item.relay]
|
|
2509
|
+
: [];
|
|
2510
|
+
console.log(
|
|
2511
|
+
`Relays: ${relays.map((relay) => `${relay.kind || "initial_request"}: ${relay.summary || "(missing)"}`).join(" | ") || "(missing)"}`,
|
|
2512
|
+
);
|
|
2513
|
+
console.log(
|
|
2514
|
+
`Provenance: ${(item.agents || []).map((agent) => `${agent.role}:${agent.provider}:${agent.resolvedModel || "unresolved"}:${agent.resolvedEffort || "unresolved"}`).join(" · ") || "missing"}`,
|
|
2515
|
+
);
|
|
2516
|
+
console.log(
|
|
2517
|
+
`Artifact files: ${(item.artifactFiles || []).map((file) => file.path).join(", ") || "none"}`,
|
|
2518
|
+
);
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
if (data.caseId) {
|
|
2522
|
+
console.log(
|
|
2523
|
+
`Sponsor-integrity case #${data.caseId}: ${data.decision}${data.scanCompleted ? "; scan complete" : ""}.`,
|
|
2524
|
+
);
|
|
2525
|
+
return;
|
|
2526
|
+
}
|
|
2268
2527
|
if (data.review) {
|
|
2269
2528
|
console.log(
|
|
2270
2529
|
`Confirmed Build #${data.review.buildId} runtime at published artifact #${data.review.publishedArtifactVersionId}.`,
|
|
@@ -2313,6 +2572,11 @@ function printAdminResult({ operation, result }) {
|
|
|
2313
2572
|
);
|
|
2314
2573
|
}
|
|
2315
2574
|
printTodoItems(report.carryoverTodos?.items || [], "Unfinished work");
|
|
2575
|
+
if (report.sponsorIntegrity) {
|
|
2576
|
+
console.log(
|
|
2577
|
+
`Sponsor integrity: ${report.sponsorIntegrity.scan?.status || "not started"}; ${report.sponsorIntegrity.cases?.open || 0} open case(s); ${report.sponsorIntegrity.pendingApplications || 0} pending application(s).`,
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2316
2580
|
const surfaces = report.brief?.engagementPulse?.surfaces;
|
|
2317
2581
|
if (surfaces && typeof surfaces === "object") {
|
|
2318
2582
|
const deltas = Object.entries(surfaces)
|
|
@@ -79,8 +79,12 @@ export async function runClaudeCodeAgentPass({
|
|
|
79
79
|
args,
|
|
80
80
|
cwd: isolationDir,
|
|
81
81
|
streamJson: true,
|
|
82
|
+
signal: options.agentAbortSignal,
|
|
82
83
|
});
|
|
83
|
-
return {
|
|
84
|
+
return {
|
|
85
|
+
finalText: result.finalText,
|
|
86
|
+
provenance: result.provenance,
|
|
87
|
+
};
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
export async function reviewClaudeCodeAgentLoop({
|
|
@@ -96,6 +100,7 @@ export async function reviewClaudeCodeAgentLoop({
|
|
|
96
100
|
binary,
|
|
97
101
|
cwd: isolationDir,
|
|
98
102
|
streamJson: false,
|
|
103
|
+
signal: options.agentAbortSignal,
|
|
99
104
|
args: [
|
|
100
105
|
"-p",
|
|
101
106
|
"--output-format",
|
|
@@ -129,16 +134,22 @@ export async function reviewClaudeCodeAgentLoop({
|
|
|
129
134
|
}
|
|
130
135
|
}
|
|
131
136
|
|
|
132
|
-
async function runClaudeProcess({ binary, args, cwd, streamJson }) {
|
|
137
|
+
async function runClaudeProcess({ binary, args, cwd, streamJson, signal }) {
|
|
133
138
|
const child = spawn(binary, args, {
|
|
134
139
|
cwd,
|
|
135
140
|
stdio: ["ignore", "pipe", "pipe"],
|
|
136
141
|
env: createSubscriptionAgentEnvironment(),
|
|
142
|
+
...(signal ? { signal } : {}),
|
|
137
143
|
});
|
|
138
144
|
child.stderr.on("data", (chunk) => process.stderr.write(chunk));
|
|
139
145
|
let finalText = "";
|
|
140
146
|
let structuredOutput = null;
|
|
141
147
|
let rawOutput = "";
|
|
148
|
+
let providerModel = null;
|
|
149
|
+
let providerEffort = null;
|
|
150
|
+
let providerUsage = {};
|
|
151
|
+
let providerServiceTier = null;
|
|
152
|
+
let providerRuntimeVersion = null;
|
|
142
153
|
|
|
143
154
|
if (streamJson) {
|
|
144
155
|
const lines = readline.createInterface({
|
|
@@ -155,13 +166,53 @@ async function runClaudeProcess({ binary, args, cwd, streamJson }) {
|
|
|
155
166
|
return;
|
|
156
167
|
}
|
|
157
168
|
if (event?.type === "assistant") {
|
|
169
|
+
providerModel =
|
|
170
|
+
firstNonEmptyString(event.message?.model, providerModel) || null;
|
|
171
|
+
providerEffort =
|
|
172
|
+
firstNonEmptyString(
|
|
173
|
+
event.message?.effort,
|
|
174
|
+
event.message?.reasoning_effort,
|
|
175
|
+
providerEffort,
|
|
176
|
+
) || null;
|
|
177
|
+
providerUsage = mergeUsageEvidence(providerUsage, event.message?.usage);
|
|
158
178
|
const texts = (event.message?.content || [])
|
|
159
179
|
.filter((block) => block?.type === "text")
|
|
160
180
|
.map((block) => String(block.text || "").trim())
|
|
161
181
|
.filter(Boolean);
|
|
162
182
|
if (texts.length > 0) finalText = texts.join("\n\n");
|
|
163
183
|
}
|
|
184
|
+
if (event?.type === "system") {
|
|
185
|
+
providerModel = firstNonEmptyString(event.model, providerModel) || null;
|
|
186
|
+
providerRuntimeVersion =
|
|
187
|
+
firstNonEmptyString(
|
|
188
|
+
event.claude_code_version,
|
|
189
|
+
event.claudeCodeVersion,
|
|
190
|
+
event.version,
|
|
191
|
+
providerRuntimeVersion,
|
|
192
|
+
) || null;
|
|
193
|
+
}
|
|
164
194
|
if (event?.type === "result") {
|
|
195
|
+
providerModel = firstNonEmptyString(event.model, providerModel) || null;
|
|
196
|
+
providerEffort =
|
|
197
|
+
firstNonEmptyString(
|
|
198
|
+
event.effort,
|
|
199
|
+
event.reasoning_effort,
|
|
200
|
+
providerEffort,
|
|
201
|
+
) || null;
|
|
202
|
+
providerServiceTier =
|
|
203
|
+
firstNonEmptyString(
|
|
204
|
+
event.service_tier,
|
|
205
|
+
event.serviceTier,
|
|
206
|
+
providerServiceTier,
|
|
207
|
+
) || null;
|
|
208
|
+
providerUsage = mergeUsageEvidence(providerUsage, event.usage);
|
|
209
|
+
providerRuntimeVersion =
|
|
210
|
+
firstNonEmptyString(
|
|
211
|
+
event.claude_code_version,
|
|
212
|
+
event.claudeCodeVersion,
|
|
213
|
+
event.version,
|
|
214
|
+
providerRuntimeVersion,
|
|
215
|
+
) || null;
|
|
165
216
|
if (typeof event.result === "string" && event.result.trim()) {
|
|
166
217
|
finalText = event.result.trim();
|
|
167
218
|
}
|
|
@@ -200,8 +251,58 @@ async function runClaudeProcess({ binary, args, cwd, streamJson }) {
|
|
|
200
251
|
}
|
|
201
252
|
finalText = String(parsed?.result || "").trim();
|
|
202
253
|
structuredOutput = parsed?.structured_output || null;
|
|
254
|
+
providerModel = firstNonEmptyString(parsed?.model) || null;
|
|
255
|
+
providerEffort =
|
|
256
|
+
firstNonEmptyString(parsed?.effort, parsed?.reasoning_effort) || null;
|
|
257
|
+
providerServiceTier =
|
|
258
|
+
firstNonEmptyString(parsed?.service_tier, parsed?.serviceTier) || null;
|
|
259
|
+
providerRuntimeVersion =
|
|
260
|
+
firstNonEmptyString(
|
|
261
|
+
parsed?.claude_code_version,
|
|
262
|
+
parsed?.claudeCodeVersion,
|
|
263
|
+
parsed?.version,
|
|
264
|
+
) || null;
|
|
265
|
+
providerUsage = mergeUsageEvidence(providerUsage, parsed?.usage);
|
|
203
266
|
}
|
|
204
|
-
return {
|
|
267
|
+
return {
|
|
268
|
+
finalText,
|
|
269
|
+
structuredOutput,
|
|
270
|
+
provenance: {
|
|
271
|
+
resolvedModel: providerModel,
|
|
272
|
+
resolvedEffort: providerEffort,
|
|
273
|
+
resolvedServiceTier: providerServiceTier,
|
|
274
|
+
runtimeVersion: providerRuntimeVersion,
|
|
275
|
+
evidenceTier:
|
|
276
|
+
providerModel || providerEffort || providerServiceTier
|
|
277
|
+
? "provider_reported"
|
|
278
|
+
: "requested_only",
|
|
279
|
+
usage: providerUsage,
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function firstNonEmptyString(...values) {
|
|
285
|
+
for (const value of values) {
|
|
286
|
+
const normalized = String(value || "").trim();
|
|
287
|
+
if (normalized) return normalized.slice(0, 160);
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function mergeUsageEvidence(current, value) {
|
|
293
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
294
|
+
return current;
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
...current,
|
|
298
|
+
...Object.fromEntries(
|
|
299
|
+
Object.entries(value)
|
|
300
|
+
.filter(([, amount]) =>
|
|
301
|
+
["number", "string", "boolean"].includes(typeof amount),
|
|
302
|
+
)
|
|
303
|
+
.slice(0, 30),
|
|
304
|
+
),
|
|
305
|
+
};
|
|
205
306
|
}
|
|
206
307
|
|
|
207
308
|
function normalizeProviderLaunchError(error, binary) {
|