@hongmaple0820/scale-engine 0.40.1 → 0.40.2
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/dist/api/cli.js +267 -7
- package/dist/api/cli.js.map +1 -1
- package/dist/api/doctor.js +1 -1
- package/dist/api/doctor.js.map +1 -1
- package/dist/bootstrap/DependencyBootstrap.d.ts +1 -0
- package/dist/bootstrap/DependencyBootstrap.js +137 -25
- package/dist/bootstrap/DependencyBootstrap.js.map +1 -1
- package/dist/capabilities/InstalledSkillsIntegration.js +29 -9
- package/dist/capabilities/InstalledSkillsIntegration.js.map +1 -1
- package/dist/context/ContextBudget.js +2 -2
- package/dist/core/GbrainRuntime.d.ts +25 -0
- package/dist/core/GbrainRuntime.js +270 -0
- package/dist/core/GbrainRuntime.js.map +1 -0
- package/dist/env/EnvironmentDoctor.js +221 -5
- package/dist/env/EnvironmentDoctor.js.map +1 -1
- package/dist/memory/MemoryProviders.js +38 -91
- package/dist/memory/MemoryProviders.js.map +1 -1
- package/dist/runtime/ModelUsageLedger.d.ts +53 -2
- package/dist/runtime/ModelUsageLedger.js +243 -39
- package/dist/runtime/ModelUsageLedger.js.map +1 -1
- package/dist/setup/SetupVerification.d.ts +42 -0
- package/dist/setup/SetupVerification.js +180 -0
- package/dist/setup/SetupVerification.js.map +1 -0
- package/dist/tools/ToolCapabilityRegistry.js +10 -0
- package/dist/tools/ToolCapabilityRegistry.js.map +1 -1
- package/dist/workflow/VerificationProfile.js +1 -1
- package/dist/workflow/VerificationProfile.js.map +1 -1
- package/docs/CONTEXT_BUDGET.md +12 -2
- package/docs/GOVERNANCE_DASHBOARD.md +7 -0
- package/docs/start/quickstart.md +1 -0
- package/package.json +3 -2
- package/scripts/workflow/lib/gbrain-runtime.mjs +185 -0
- package/scripts/workflow/lib/report-output.mjs +107 -0
- package/scripts/workflow/provider-rehearsal.mjs +129 -48
- package/scripts/workflow/setup-smoke.mjs +142 -8
package/dist/api/cli.js
CHANGED
|
@@ -33,6 +33,7 @@ import { quickStart, detectPlatform, governanceNextSteps } from './quickstart.js
|
|
|
33
33
|
import { bootstrapDependencies } from '../bootstrap/DependencyBootstrap.js';
|
|
34
34
|
import { renderDependencyBootstrapReport } from '../bootstrap/DependencyBootstrapRenderer.js';
|
|
35
35
|
import { runSetupWizard } from '../setup/SetupWizard.js';
|
|
36
|
+
import { verifySetup } from '../setup/SetupVerification.js';
|
|
36
37
|
import { normalizeLanguage, resolveCliLanguage } from '../i18n/Language.js';
|
|
37
38
|
import { SkillDiscovery } from '../skills/SkillDiscovery.js';
|
|
38
39
|
import { inspectRequiredWorkflowSkills, inspectWorkflowSkills } from '../skills/SkillDoctor.js';
|
|
@@ -75,7 +76,7 @@ import { doctorHtmlArtifacts, renderHtmlArtifact, resolveHtmlArtifactForOpen, se
|
|
|
75
76
|
import { renderGovernanceDashboard } from '../output/GovernanceDashboard.js';
|
|
76
77
|
import { cleanupWorkspaceLifecycle, inspectWorkspaceLifecycle, } from '../workflow/WorkspaceLifecycle.js';
|
|
77
78
|
import { inspectWorkspaceSafety } from '../workflow/WorkspaceSafety.js';
|
|
78
|
-
import { RuntimeEvidenceLedger, SessionLedger, createAiOsAdoption, createAiOsBenchmark, createAiOsDashboard, createAiOsDoctor, createAiOsMigration, createAiOsPlan, createAiOsRun, createAiOsStatus, doctorRuntimeEvidence, evaluateFinalReportReadiness, } from '../runtime/index.js';
|
|
79
|
+
import { ModelUsageLedger, RuntimeEvidenceLedger, SessionLedger, buildModelUsageInput, createAiOsAdoption, createAiOsBenchmark, createAiOsDashboard, createAiOsDoctor, createAiOsMigration, createAiOsPlan, createAiOsRun, createAiOsStatus, doctorRuntimeEvidence, evaluateFinalReportReadiness, } from '../runtime/index.js';
|
|
79
80
|
import { MemoryFabric, MemoryBrain, doctorMemoryFabric, renderContextPackMarkdown, renderMemoryLearningCandidateMarkdown, inspectMemoryProviders, recallMemoryProviders, settleMemoryLearning, useMemoryProvider, writeMemoryProvidersConfig, } from '../memory/index.js';
|
|
80
81
|
import { resolveWorkspaceTopology, workspaceTopologyPath, workspaceTopologyTemplate, } from '../workflow/WorkspaceTopology.js';
|
|
81
82
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
@@ -2817,7 +2818,6 @@ const bootstrap = defineCommand({
|
|
|
2817
2818
|
meta: { name: 'bootstrap', description: 'Bootstrap third-party workflow dependencies with explicit install intent' },
|
|
2818
2819
|
subCommands: { deps: bootstrapDepsCommand },
|
|
2819
2820
|
});
|
|
2820
|
-
// ============================================================================
|
|
2821
2821
|
const setup = defineCommand({
|
|
2822
2822
|
meta: { name: 'setup', description: 'Interactive SCALE setup for third-party skills, CLIs, memory, and knowledge providers' },
|
|
2823
2823
|
args: {
|
|
@@ -2828,6 +2828,7 @@ const setup = defineCommand({
|
|
|
2828
2828
|
include: { type: 'string', description: 'Additional dependency ids to include explicitly' },
|
|
2829
2829
|
apply: { type: 'boolean', default: false, description: 'Run install commands for ready dependencies' },
|
|
2830
2830
|
yes: { type: 'boolean', default: false, description: 'Confirm installation without prompting' },
|
|
2831
|
+
verify: { type: 'boolean', default: false, description: 'Verify governed setup and dependency readiness instead of running the setup wizard' },
|
|
2831
2832
|
interactive: { type: 'boolean', default: true, description: 'Prompt before installation when dependencies are ready' },
|
|
2832
2833
|
lang: { type: 'string', description: 'Output language zh/en. Defaults to zh, then SCALE_LANG, then .scale/config.yaml locale.' },
|
|
2833
2834
|
'memory-provider': { type: 'string', description: 'Switch memory provider during setup: gbrain, agentmemory, or scale-local' },
|
|
@@ -2840,10 +2841,24 @@ const setup = defineCommand({
|
|
|
2840
2841
|
async run({ args }) {
|
|
2841
2842
|
const projectDir = resolve(String(args.dir ?? PROJECT_DIR));
|
|
2842
2843
|
const lang = resolveCliLanguage({ lang: args.lang, projectDir, scaleDir: SCALE_DIR });
|
|
2843
|
-
const explicitPacks =
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2844
|
+
const { explicitPacks, recommendedPacks } = resolveSetupPacks(args);
|
|
2845
|
+
if (isTruthyFlag(args.verify)) {
|
|
2846
|
+
const verification = await verifySetup({
|
|
2847
|
+
projectDir,
|
|
2848
|
+
scaleDir: SCALE_DIR,
|
|
2849
|
+
packIds: explicitPacks.length > 0 ? uniqueStrings([...recommendedPacks, ...explicitPacks]) : recommendedPacks,
|
|
2850
|
+
includeIds: parseCommaList(args.include),
|
|
2851
|
+
});
|
|
2852
|
+
if (args.json) {
|
|
2853
|
+
console.log(JSON.stringify(verification, null, 2));
|
|
2854
|
+
}
|
|
2855
|
+
else {
|
|
2856
|
+
renderSetupVerifyReport(verification, lang);
|
|
2857
|
+
}
|
|
2858
|
+
if (!verification.ok)
|
|
2859
|
+
process.exitCode = 1;
|
|
2860
|
+
return;
|
|
2861
|
+
}
|
|
2847
2862
|
const report = await runSetupWizard({
|
|
2848
2863
|
projectDir,
|
|
2849
2864
|
scaleDir: SCALE_DIR,
|
|
@@ -2892,6 +2907,64 @@ const setup = defineCommand({
|
|
|
2892
2907
|
});
|
|
2893
2908
|
// config command — Configuration profile management
|
|
2894
2909
|
// ============================================================================
|
|
2910
|
+
function resolveSetupPacks(args) {
|
|
2911
|
+
const explicitPacks = parseCommaList(args.pack);
|
|
2912
|
+
const recommendedPacks = args.profile
|
|
2913
|
+
? getBootstrapPlanForProfile(String(args.profile), args['governance-pack'] ? String(args['governance-pack']) : undefined).packs
|
|
2914
|
+
: [];
|
|
2915
|
+
return { explicitPacks, recommendedPacks };
|
|
2916
|
+
}
|
|
2917
|
+
function renderSetupVerifyReport(report, lang) {
|
|
2918
|
+
if (lang === 'zh') {
|
|
2919
|
+
console.log('\nSCALE 安装验收');
|
|
2920
|
+
console.log(` 项目: ${report.projectDir}`);
|
|
2921
|
+
console.log(` 依赖包: ${report.packIds.join(', ') || 'full'}`);
|
|
2922
|
+
console.log(` 结论: ${report.ok ? '通过' : '未通过'}`);
|
|
2923
|
+
console.log(` 阻塞项: ${report.summary.blockingIssues.length}`);
|
|
2924
|
+
console.log(` 受管能力: ${report.summary.installedTools}/${report.summary.totalTools}`);
|
|
2925
|
+
console.log(` 记忆供应商: ${report.summary.availableMemoryProviders}`);
|
|
2926
|
+
console.log(` 代码图谱供应商: ${report.summary.availableCodeProviders}`);
|
|
2927
|
+
if (report.summary.blockingIssues.length > 0) {
|
|
2928
|
+
console.log(' 阻塞详情:');
|
|
2929
|
+
for (const issue of report.summary.blockingIssues)
|
|
2930
|
+
console.log(` - ${issue}`);
|
|
2931
|
+
}
|
|
2932
|
+
if (report.warnings.length > 0) {
|
|
2933
|
+
console.log(` 警告${report.warnings.length > 12 ? ` (显示前 12 条,共 ${report.warnings.length} 条)` : ''}:`);
|
|
2934
|
+
for (const warning of report.warnings.slice(0, 12))
|
|
2935
|
+
console.log(` - ${warning}`);
|
|
2936
|
+
}
|
|
2937
|
+
if (report.recommendations.length > 0) {
|
|
2938
|
+
console.log(' 下一步:');
|
|
2939
|
+
for (const command of report.recommendations.slice(0, 12))
|
|
2940
|
+
console.log(` ${command}`);
|
|
2941
|
+
}
|
|
2942
|
+
return;
|
|
2943
|
+
}
|
|
2944
|
+
console.log('\nSCALE Setup Verification');
|
|
2945
|
+
console.log(` Project: ${report.projectDir}`);
|
|
2946
|
+
console.log(` Packs: ${report.packIds.join(', ') || 'full'}`);
|
|
2947
|
+
console.log(` Result: ${report.ok ? 'passed' : 'failed'}`);
|
|
2948
|
+
console.log(` Blocking issues: ${report.summary.blockingIssues.length}`);
|
|
2949
|
+
console.log(` Governed capabilities: ${report.summary.installedTools}/${report.summary.totalTools}`);
|
|
2950
|
+
console.log(` Memory providers: ${report.summary.availableMemoryProviders}`);
|
|
2951
|
+
console.log(` Code providers: ${report.summary.availableCodeProviders}`);
|
|
2952
|
+
if (report.summary.blockingIssues.length > 0) {
|
|
2953
|
+
console.log(' Blockers:');
|
|
2954
|
+
for (const issue of report.summary.blockingIssues)
|
|
2955
|
+
console.log(` - ${issue}`);
|
|
2956
|
+
}
|
|
2957
|
+
if (report.warnings.length > 0) {
|
|
2958
|
+
console.log(` Warnings${report.warnings.length > 12 ? ` (showing first 12 of ${report.warnings.length})` : ''}:`);
|
|
2959
|
+
for (const warning of report.warnings.slice(0, 12))
|
|
2960
|
+
console.log(` - ${warning}`);
|
|
2961
|
+
}
|
|
2962
|
+
if (report.recommendations.length > 0) {
|
|
2963
|
+
console.log(' Next:');
|
|
2964
|
+
for (const command of report.recommendations.slice(0, 12))
|
|
2965
|
+
console.log(` ${command}`);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2895
2968
|
const configProfile = defineCommand({
|
|
2896
2969
|
meta: { name: 'profile', description: 'View or switch configuration profile' },
|
|
2897
2970
|
args: {
|
|
@@ -4537,6 +4610,169 @@ function normalizeRuntimeSessionStatus(value) {
|
|
|
4537
4610
|
return normalized;
|
|
4538
4611
|
throw new Error(`Invalid runtime session status "${normalized}"; expected active, completed, failed, or abandoned.`);
|
|
4539
4612
|
}
|
|
4613
|
+
function parseNonNegativeNumberArg(value, name) {
|
|
4614
|
+
if (value === undefined || value === null || value === '')
|
|
4615
|
+
return undefined;
|
|
4616
|
+
const parsed = Number(value);
|
|
4617
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
4618
|
+
throw new Error(`${name} must be a non-negative number.`);
|
|
4619
|
+
}
|
|
4620
|
+
return parsed;
|
|
4621
|
+
}
|
|
4622
|
+
function parseJsonArg(value, name) {
|
|
4623
|
+
try {
|
|
4624
|
+
return JSON.parse(String(value ?? 'null'));
|
|
4625
|
+
}
|
|
4626
|
+
catch {
|
|
4627
|
+
throw new Error(`${name} must be valid JSON.`);
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
function parseMetadataJson(value, name = '--metadata-json') {
|
|
4631
|
+
const parsed = parseJsonArg(value ?? '{}', name);
|
|
4632
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
4633
|
+
throw new Error(`${name} must be a JSON object.`);
|
|
4634
|
+
}
|
|
4635
|
+
return parsed;
|
|
4636
|
+
}
|
|
4637
|
+
function hasModelUsageArgs(args) {
|
|
4638
|
+
return [
|
|
4639
|
+
'provider',
|
|
4640
|
+
'model',
|
|
4641
|
+
'usage-json',
|
|
4642
|
+
'usage-file',
|
|
4643
|
+
'input-tokens',
|
|
4644
|
+
'output-tokens',
|
|
4645
|
+
'cache-eligible-tokens',
|
|
4646
|
+
'cache-creation-input-tokens',
|
|
4647
|
+
'cache-read-input-tokens',
|
|
4648
|
+
'cached-tokens',
|
|
4649
|
+
'estimated-cost-usd',
|
|
4650
|
+
].some(key => args[key] !== undefined && args[key] !== '');
|
|
4651
|
+
}
|
|
4652
|
+
function buildModelUsageRecordInput(args, defaults = {}) {
|
|
4653
|
+
const usagePayload = args['usage-file']
|
|
4654
|
+
? parseJsonArg(readFileSync(resolve(PROJECT_DIR, String(args['usage-file'])), 'utf-8'), '--usage-file')
|
|
4655
|
+
: args['usage-json']
|
|
4656
|
+
? parseJsonArg(args['usage-json'], '--usage-json')
|
|
4657
|
+
: undefined;
|
|
4658
|
+
const provider = String(args.provider ?? defaults.provider ?? '').trim();
|
|
4659
|
+
if (!provider)
|
|
4660
|
+
throw new Error('Model usage recording requires --provider.');
|
|
4661
|
+
return buildModelUsageInput({
|
|
4662
|
+
provider,
|
|
4663
|
+
model: args.model ? String(args.model) : undefined,
|
|
4664
|
+
taskId: args['task-id'] ? String(args['task-id']) : defaults.taskId,
|
|
4665
|
+
sessionId: args['session-id'] ? String(args['session-id']) : defaults.sessionId,
|
|
4666
|
+
inputTokens: parseNonNegativeNumberArg(args['input-tokens'], '--input-tokens'),
|
|
4667
|
+
outputTokens: parseNonNegativeNumberArg(args['output-tokens'], '--output-tokens'),
|
|
4668
|
+
cacheEligibleTokens: parseNonNegativeNumberArg(args['cache-eligible-tokens'], '--cache-eligible-tokens'),
|
|
4669
|
+
cacheCreationInputTokens: parseNonNegativeNumberArg(args['cache-creation-input-tokens'], '--cache-creation-input-tokens'),
|
|
4670
|
+
cacheReadInputTokens: parseNonNegativeNumberArg(args['cache-read-input-tokens'], '--cache-read-input-tokens'),
|
|
4671
|
+
cachedTokens: parseNonNegativeNumberArg(args['cached-tokens'], '--cached-tokens'),
|
|
4672
|
+
estimatedCostUsd: parseNonNegativeNumberArg(args['estimated-cost-usd'], '--estimated-cost-usd'),
|
|
4673
|
+
metadata: args['metadata-json'] !== undefined ? parseMetadataJson(args['metadata-json']) : undefined,
|
|
4674
|
+
timestamp: args.timestamp ? String(args.timestamp) : undefined,
|
|
4675
|
+
usagePayload,
|
|
4676
|
+
});
|
|
4677
|
+
}
|
|
4678
|
+
const tokenRecord = defineCommand({
|
|
4679
|
+
meta: { name: 'record', description: 'Record real model usage from provider usage payloads or explicit token counts' },
|
|
4680
|
+
args: {
|
|
4681
|
+
provider: { type: 'string', required: true, description: 'Model provider: anthropic, openai, codex, etc.' },
|
|
4682
|
+
model: { type: 'string', description: 'Optional model id' },
|
|
4683
|
+
'task-id': { type: 'string', description: 'Task id linked to this model usage' },
|
|
4684
|
+
'session-id': { type: 'string', description: 'Session id linked to this model usage' },
|
|
4685
|
+
'usage-json': { type: 'string', description: 'Raw provider response or usage JSON to normalize into the usage ledger' },
|
|
4686
|
+
'usage-file': { type: 'string', description: 'Path to a JSON file containing a raw provider response or usage payload' },
|
|
4687
|
+
'input-tokens': { type: 'string', description: 'Explicit input token count; overrides usage JSON when provided' },
|
|
4688
|
+
'output-tokens': { type: 'string', description: 'Explicit output token count; overrides usage JSON when provided' },
|
|
4689
|
+
'cache-eligible-tokens': { type: 'string', description: 'Explicit cache-eligible token count' },
|
|
4690
|
+
'cache-creation-input-tokens': { type: 'string', description: 'Explicit Anthropic cache creation token count' },
|
|
4691
|
+
'cache-read-input-tokens': { type: 'string', description: 'Explicit Anthropic cache read token count' },
|
|
4692
|
+
'cached-tokens': { type: 'string', description: 'Explicit OpenAI cached token count' },
|
|
4693
|
+
'estimated-cost-usd': { type: 'string', description: 'Optional estimated cost in USD' },
|
|
4694
|
+
timestamp: { type: 'string', description: 'Optional ISO timestamp' },
|
|
4695
|
+
'metadata-json': { type: 'string', default: '{}', description: 'Additional JSON metadata' },
|
|
4696
|
+
json: { type: 'boolean', default: false },
|
|
4697
|
+
},
|
|
4698
|
+
run({ args }) {
|
|
4699
|
+
const record = new ModelUsageLedger(SCALE_DIR).record(buildModelUsageRecordInput(args));
|
|
4700
|
+
if (args.json) {
|
|
4701
|
+
console.log(JSON.stringify(record, null, 2));
|
|
4702
|
+
return;
|
|
4703
|
+
}
|
|
4704
|
+
console.log(`Model usage recorded: ${record.id}`);
|
|
4705
|
+
console.log(` Provider: ${record.provider}`);
|
|
4706
|
+
console.log(` Model: ${record.model ?? 'unknown'}`);
|
|
4707
|
+
console.log(` Tokens: input ${record.inputTokens}, output ${record.outputTokens}, total ${record.totalTokens}`);
|
|
4708
|
+
if (record.cacheSavingsTokens > 0)
|
|
4709
|
+
console.log(` Cache savings: ${record.cacheSavingsTokens} tokens`);
|
|
4710
|
+
},
|
|
4711
|
+
});
|
|
4712
|
+
const tokenReport = defineCommand({
|
|
4713
|
+
meta: { name: 'report', description: 'Summarize recorded model usage by day, provider, model, and task' },
|
|
4714
|
+
args: {
|
|
4715
|
+
day: { type: 'string', description: 'Exact UTC day in YYYY-MM-DD format' },
|
|
4716
|
+
since: { type: 'string', description: 'ISO timestamp lower bound' },
|
|
4717
|
+
until: { type: 'string', description: 'ISO timestamp upper bound' },
|
|
4718
|
+
'since-days': { type: 'string', default: '7d', description: 'Relative time window when day/since/until are omitted; use all to disable' },
|
|
4719
|
+
provider: { type: 'string', description: 'Filter by provider' },
|
|
4720
|
+
model: { type: 'string', description: 'Filter by model id' },
|
|
4721
|
+
'task-id': { type: 'string', description: 'Filter by task id' },
|
|
4722
|
+
'session-id': { type: 'string', description: 'Filter by session id' },
|
|
4723
|
+
limit: { type: 'string', description: 'Maximum recent records to include in the report; defaults to 20' },
|
|
4724
|
+
json: { type: 'boolean', default: false },
|
|
4725
|
+
},
|
|
4726
|
+
run({ args }) {
|
|
4727
|
+
const limit = parsePositiveIntArg(args.limit, '--limit');
|
|
4728
|
+
const sinceDays = args.day || args.since || args.until ? undefined : parseSinceDays(args['since-days']) ?? 7;
|
|
4729
|
+
const since = args.since
|
|
4730
|
+
? String(args.since)
|
|
4731
|
+
: sinceDays
|
|
4732
|
+
? new Date(Date.now() - sinceDays * 24 * 60 * 60 * 1000).toISOString()
|
|
4733
|
+
: undefined;
|
|
4734
|
+
const report = new ModelUsageLedger(SCALE_DIR).report({
|
|
4735
|
+
day: args.day ? String(args.day) : undefined,
|
|
4736
|
+
since,
|
|
4737
|
+
until: args.until ? String(args.until) : undefined,
|
|
4738
|
+
provider: args.provider ? String(args.provider) : undefined,
|
|
4739
|
+
model: args.model ? String(args.model) : undefined,
|
|
4740
|
+
taskId: args['task-id'] ? String(args['task-id']) : undefined,
|
|
4741
|
+
sessionId: args['session-id'] ? String(args['session-id']) : undefined,
|
|
4742
|
+
limit,
|
|
4743
|
+
});
|
|
4744
|
+
if (args.json) {
|
|
4745
|
+
console.log(JSON.stringify(report, null, 2));
|
|
4746
|
+
return;
|
|
4747
|
+
}
|
|
4748
|
+
console.log('SCALE Token Report');
|
|
4749
|
+
if (report.filters.day)
|
|
4750
|
+
console.log(` Day: ${report.filters.day}`);
|
|
4751
|
+
else if (report.filters.since || report.filters.until)
|
|
4752
|
+
console.log(` Window: ${report.filters.since ?? '-inf'} -> ${report.filters.until ?? 'now'}`);
|
|
4753
|
+
console.log(` Records: ${report.summary.totalRecords}`);
|
|
4754
|
+
console.log(` Tokens: input ${report.summary.totalInputTokens}, output ${report.summary.totalOutputTokens}, total ${report.summary.totalTokens}`);
|
|
4755
|
+
console.log(` Cache: eligible ${report.summary.cacheEligibleTokens}, create ${report.summary.cacheCreationInputTokens}, read ${report.summary.cacheReadInputTokens}, cached ${report.summary.cachedTokens}, saved ${report.summary.cacheSavingsTokens}`);
|
|
4756
|
+
if (report.summary.estimatedCostUsd !== undefined)
|
|
4757
|
+
console.log(` Estimated cost: $${report.summary.estimatedCostUsd.toFixed(6)}`);
|
|
4758
|
+
for (const row of report.byProvider.slice(0, 5)) {
|
|
4759
|
+
console.log(` Provider ${row.key}: ${row.records} record(s), ${row.totalTokens} total tokens, ${row.cacheSavingsTokens} saved`);
|
|
4760
|
+
}
|
|
4761
|
+
for (const row of report.byModel.slice(0, 5)) {
|
|
4762
|
+
console.log(` Model ${row.key}: ${row.records} record(s), ${row.totalTokens} total tokens`);
|
|
4763
|
+
}
|
|
4764
|
+
for (const row of report.byTask.slice(0, 5)) {
|
|
4765
|
+
console.log(` Task ${row.key}: ${row.records} record(s), ${row.totalTokens} total tokens`);
|
|
4766
|
+
}
|
|
4767
|
+
for (const row of report.records.slice(0, 10)) {
|
|
4768
|
+
console.log(` Recent ${row.timestamp}: ${row.provider}/${row.model ?? 'unknown'} task=${row.taskId ?? '-'} total=${row.totalTokens}`);
|
|
4769
|
+
}
|
|
4770
|
+
},
|
|
4771
|
+
});
|
|
4772
|
+
const token = defineCommand({
|
|
4773
|
+
meta: { name: 'token', description: 'Record and audit real model token usage' },
|
|
4774
|
+
subCommands: { record: tokenRecord, report: tokenReport },
|
|
4775
|
+
});
|
|
4540
4776
|
const runtimeStart = defineCommand({
|
|
4541
4777
|
meta: { name: 'start', description: 'Start a runtime session ledger' },
|
|
4542
4778
|
args: {
|
|
@@ -4604,6 +4840,18 @@ const runtimeRecord = defineCommand({
|
|
|
4604
4840
|
'exit-code': { type: 'string', description: 'Exit code when applicable' },
|
|
4605
4841
|
summary: { type: 'string', required: true, description: 'Short output summary' },
|
|
4606
4842
|
artifacts: { type: 'string', description: 'Comma-separated artifact paths' },
|
|
4843
|
+
provider: { type: 'string', description: 'Optional model provider when attaching model usage: anthropic, openai, codex, etc.' },
|
|
4844
|
+
model: { type: 'string', description: 'Optional model id when attaching model usage' },
|
|
4845
|
+
'usage-json': { type: 'string', description: 'Raw provider response or usage JSON to normalize into the usage ledger' },
|
|
4846
|
+
'usage-file': { type: 'string', description: 'Path to a JSON file containing a raw provider response or usage payload' },
|
|
4847
|
+
'input-tokens': { type: 'string', description: 'Explicit input token count; overrides usage JSON when provided' },
|
|
4848
|
+
'output-tokens': { type: 'string', description: 'Explicit output token count; overrides usage JSON when provided' },
|
|
4849
|
+
'cache-eligible-tokens': { type: 'string', description: 'Explicit cache-eligible token count' },
|
|
4850
|
+
'cache-creation-input-tokens': { type: 'string', description: 'Explicit Anthropic cache creation token count' },
|
|
4851
|
+
'cache-read-input-tokens': { type: 'string', description: 'Explicit Anthropic cache read token count' },
|
|
4852
|
+
'cached-tokens': { type: 'string', description: 'Explicit OpenAI cached token count' },
|
|
4853
|
+
'estimated-cost-usd': { type: 'string', description: 'Optional estimated cost in USD' },
|
|
4854
|
+
timestamp: { type: 'string', description: 'Optional ISO timestamp for the usage record' },
|
|
4607
4855
|
'metadata-json': { type: 'string', default: '{}', description: 'Additional JSON metadata' },
|
|
4608
4856
|
json: { type: 'boolean', default: false },
|
|
4609
4857
|
},
|
|
@@ -4648,13 +4896,24 @@ const runtimeRecord = defineCommand({
|
|
|
4648
4896
|
},
|
|
4649
4897
|
});
|
|
4650
4898
|
}
|
|
4899
|
+
const usageRecord = hasModelUsageArgs(args)
|
|
4900
|
+
? new ModelUsageLedger(SCALE_DIR).record(buildModelUsageRecordInput(args, {
|
|
4901
|
+
taskId: record.taskId,
|
|
4902
|
+
sessionId: record.sessionId,
|
|
4903
|
+
}))
|
|
4904
|
+
: undefined;
|
|
4651
4905
|
if (args.json) {
|
|
4652
|
-
console.log(JSON.stringify(record, null, 2));
|
|
4906
|
+
console.log(JSON.stringify(usageRecord ? { evidence: record, usage: usageRecord } : record, null, 2));
|
|
4653
4907
|
return;
|
|
4654
4908
|
}
|
|
4655
4909
|
console.log(`Runtime evidence recorded: ${record.id}`);
|
|
4656
4910
|
console.log(` Status: ${record.status}`);
|
|
4657
4911
|
console.log(` Kind: ${record.kind}`);
|
|
4912
|
+
if (usageRecord) {
|
|
4913
|
+
console.log(` Model usage: ${usageRecord.provider}/${usageRecord.model ?? 'unknown'} ${usageRecord.totalTokens} total tokens`);
|
|
4914
|
+
if (usageRecord.cacheSavingsTokens > 0)
|
|
4915
|
+
console.log(` Cache savings: ${usageRecord.cacheSavingsTokens} tokens`);
|
|
4916
|
+
}
|
|
4658
4917
|
if (record.redactionApplied)
|
|
4659
4918
|
console.log(' Redaction: applied');
|
|
4660
4919
|
},
|
|
@@ -6274,6 +6533,7 @@ const main = defineCommand({
|
|
|
6274
6533
|
workflow,
|
|
6275
6534
|
evidence,
|
|
6276
6535
|
runtime,
|
|
6536
|
+
token,
|
|
6277
6537
|
memory,
|
|
6278
6538
|
diagnose,
|
|
6279
6539
|
hunt,
|